2009-11-10 Tristan Gingold <gingold@adacore.com>
authorTristan Gingold <gingold@adacore.com>
Tue, 10 Nov 2009 10:22:22 +0000 (10:22 +0000)
committerTristan Gingold <gingold@adacore.com>
Tue, 10 Nov 2009 10:22:22 +0000 (10:22 +0000)
* avr-tdep.c (avr_extract_return_value): Remove.
(avr_return_value): Mostly rewritten.  Fix handling for structures.
(avr_push_dummy_call): Handle struct_return.

2009-11-10  Tristan Gingold  <gingold@adacore.com>

* avr-tdep.c (avr_scan_prologue): Decode instructions used for
small stack allocation.
Adjust code for prologue that don't write SP.

gdb/ChangeLog
gdb/avr-tdep.c

index b7b8d56..66c26d7 100644 (file)
@@ -1,5 +1,17 @@
 2009-11-10  Tristan Gingold  <gingold@adacore.com>
 
+       * avr-tdep.c (avr_extract_return_value): Remove.
+       (avr_return_value): Mostly rewritten.  Fix handling for structures.
+       (avr_push_dummy_call): Handle struct_return.
+
+2009-11-10  Tristan Gingold  <gingold@adacore.com>
+
+       * avr-tdep.c (avr_scan_prologue): Decode instructions used for
+       small stack allocation.
+       Adjust code for prologue that don't write SP.
+
+2009-11-10  Tristan Gingold  <gingold@adacore.com>
+
        * avr-tdep.c (avr_make_saddr): Return 0 for NULL.
 
 2009-11-10  Tristan Gingold  <gingold@adacore.com>
index 6de10f2..56c3f63 100644 (file)
@@ -654,6 +654,25 @@ avr_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR pc_beg, CORE_ADDR pc_end,
      fprintf_unfiltered (gdb_stderr,
                          _("Hit end of prologue while scanning pushes\n"));
 
+  /* Handle static small stack allocation using rcall or push.  */
+
+  while (scan_stage == 1 && vpc < len)
+    {
+      insn = extract_unsigned_integer (&prologue[vpc], 2, byte_order);
+      if (insn == 0xd000)      /* rcall .+0 */
+        {
+          info->size += gdbarch_tdep (gdbarch)->call_length;
+          vpc += 2;
+        }
+      else if (insn == 0x920f)  /* push r0 */
+        {
+          info->size += 1;
+          vpc += 2;
+        }
+      else
+        break;
+    }
+
   /* Second stage of the prologue scanning.
      Scan:
      in r28,__SP_L__
@@ -707,18 +726,21 @@ avr_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR pc_beg, CORE_ADDR pc_end,
       };
 
       insn = extract_unsigned_integer (&prologue[vpc], 2, byte_order);
-      vpc += 2;
       if ((insn & 0xff30) == 0x9720)   /* sbiw r28,XXX */
-       locals_size = (insn & 0xf) | ((insn & 0xc0) >> 2);
+        {
+          locals_size = (insn & 0xf) | ((insn & 0xc0) >> 2);
+          vpc += 2;
+        }
       else if ((insn & 0xf0f0) == 0x50c0)      /* subi r28,lo8(XX) */
        {
          locals_size = (insn & 0xf) | ((insn & 0xf00) >> 4);
+         vpc += 2;
          insn = extract_unsigned_integer (&prologue[vpc], 2, byte_order);
          vpc += 2;
-         locals_size += ((insn & 0xf) | ((insn & 0xf00) >> 4) << 8);
+         locals_size += ((insn & 0xf) | ((insn & 0xf00) >> 4)) << 8;
        }
       else
-       return pc_beg + vpc;
+        return pc_beg + vpc;
 
       /* Scan the last part of the prologue. May not be present for interrupt
          or signal handler functions, which is why we set the prologue type
@@ -815,40 +837,6 @@ avr_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
     return avr_break_insn;
 }
 
-/* Given a return value in `regcache' with a type `type', 
-   extract and copy its value into `valbuf'.
-
-   Return values are always passed via registers r25:r24:...  */
-
-static void
-avr_extract_return_value (struct type *type, struct regcache *regcache,
-                          gdb_byte *valbuf)
-{
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  ULONGEST r24, r25;
-  ULONGEST c;
-  int len;
-  if (TYPE_LENGTH (type) == 1)
-    {
-      regcache_cooked_read_unsigned (regcache, 24, &c);
-      store_unsigned_integer (valbuf, 1, byte_order, c);
-    }
-  else
-    {
-      int i;
-      /* The MSB of the return value is always in r25, calculate which
-         register holds the LSB.  */
-      int lsb_reg = 25 - TYPE_LENGTH (type) + 1;
-
-      for (i=0; i< TYPE_LENGTH (type); i++)
-        {
-          regcache_cooked_read (regcache, lsb_reg + i,
-                                (bfd_byte *) valbuf + i);
-        }
-    }
-}
-
 /* Determine, for architecture GDBARCH, how a return value of TYPE
    should be returned.  If it is supposed to be returned in registers,
    and READBUF is non-zero, read the appropriate value from REGCACHE,
@@ -860,30 +848,40 @@ avr_return_value (struct gdbarch *gdbarch, struct type *func_type,
                  struct type *valtype, struct regcache *regcache,
                  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  int struct_return = ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
-                       || TYPE_CODE (valtype) == TYPE_CODE_UNION
-                       || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
-                      && !(TYPE_LENGTH (valtype) == 1
-                           || TYPE_LENGTH (valtype) == 2
-                           || TYPE_LENGTH (valtype) == 4
-                           || TYPE_LENGTH (valtype) == 8));
+  int i;
+  /* Single byte are returned in r24.
+     Otherwise, the MSB of the return value is always in r25, calculate which
+     register holds the LSB.  */
+  int lsb_reg;
+
+  if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+       || TYPE_CODE (valtype) == TYPE_CODE_UNION
+       || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+      && TYPE_LENGTH (valtype) > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (TYPE_LENGTH (valtype) <= 2)
+    lsb_reg = 24;
+  else if (TYPE_LENGTH (valtype) <= 4)
+    lsb_reg = 22;
+  else if (TYPE_LENGTH (valtype) <= 8)
+    lsb_reg = 18;
+  else
+    gdb_assert (0);
 
   if (writebuf != NULL)
     {
-      gdb_assert (!struct_return);
-      error (_("Cannot store return value."));
+      for (i = 0; i < TYPE_LENGTH (valtype); i++)
+        regcache_cooked_write (regcache, lsb_reg + i, writebuf + i);
     }
 
   if (readbuf != NULL)
     {
-      gdb_assert (!struct_return);
-      avr_extract_return_value (valtype, regcache, readbuf);
+      for (i = 0; i < TYPE_LENGTH (valtype); i++)
+        regcache_cooked_read (regcache, lsb_reg + i, readbuf + i);
     }
 
-  if (struct_return)
-    return RETURN_VALUE_STRUCT_CONVENTION;
-  else
-    return RETURN_VALUE_REGISTER_CONVENTION;
+  return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
 
@@ -1191,15 +1189,13 @@ avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int regnum = AVR_ARGN_REGNUM;
   struct stack_item *si = NULL;
 
-#if 0
-  /* FIXME: TRoth/2003-06-18: Not sure what to do when returning a struct. */
   if (struct_return)
     {
-      fprintf_unfiltered (gdb_stderr, "struct_return: 0x%lx\n", struct_addr);
-      regcache_cooked_write_unsigned (regcache, argreg--, struct_addr & 0xff);
-      regcache_cooked_write_unsigned (regcache, argreg--, (struct_addr >>8) & 0xff);
+      regcache_cooked_write_unsigned (regcache, regnum--,
+                                      struct_addr & 0xff);
+      regcache_cooked_write_unsigned (regcache, regnum--,
+                                      (struct_addr >> 8) & 0xff);
     }
-#endif
 
   for (i = 0; i < nargs; i++)
     {