]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
i * gdb/configure.tgt (gdb_osabi): uclinux is like linux.
authorNathan Sidwell <nathan@codesourcery.com>
Mon, 5 Jun 2006 14:51:35 +0000 (14:51 +0000)
committerNathan Sidwell <nathan@codesourcery.com>
Mon, 5 Jun 2006 14:51:35 +0000 (14:51 +0000)
* gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Return value
is never in %a0.
(m68k_reg_struct_return_p): Duplicate gcc's struct mode algorithm.
(m68k_svr4_return_value) Use VALUE_STRUCT_CONVENTION.  do not rely
on %a0.
(m68k_push_dummy_call): Force stack alignment.
(m68k_svr4_init_abi): Set struct_return convention.
(m68k_aout_init_abi): New.
(m68k_gdbarch_init): Default to bare elf ABI that gcc provides.
* gdb/m68k-tdep.h (m68k_aout_init_abi): Declare.
* gdb/m68kbsd-tdep.c (m68kbsd_aout_init_abi): Use m68k_aout_init_abi.
(m68kbsd_elf_init_abi): Add comment.
* gdb/m68klinux-tdep.c (m68k_linux_init_abi): Just set the struct
pointer register here.

ChangeLog.csl
gdb/configure.tgt
gdb/m68k-tdep.c
gdb/m68k-tdep.h
gdb/m68kbsd-tdep.c
gdb/m68klinux-tdep.c

index 5ccd8ced388de61065cc5e37634000b00ae17d11..95f6f57ec9e11bda36664f78287b5f27d5dd11c8 100644 (file)
@@ -1,3 +1,21 @@
+2006-06-05  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * gdb/configure.tgt (gdb_osabi): uclinux is like linux.
+       * gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Return value
+       is never in %a0.
+       (m68k_reg_struct_return_p): Duplicate gcc's struct mode algorithm.
+       (m68k_svr4_return_value) Use VALUE_STRUCT_CONVENTION.  do not rely
+       on %a0.
+       (m68k_push_dummy_call): Force stack alignment.
+       (m68k_svr4_init_abi): Set struct_return convention.
+       (m68k_aout_init_abi): New.
+       (m68k_gdbarch_init): Default to bare elf ABI that gcc provides.
+       * gdb/m68k-tdep.h (m68k_aout_init_abi): Declare.
+       * gdb/m68kbsd-tdep.c (m68kbsd_aout_init_abi): Use m68k_aout_init_abi.
+       (m68kbsd_elf_init_abi): Add comment.
+       * gdb/m68klinux-tdep.c (m68k_linux_init_abi): Just set the struct
+       pointer register here.
+
 2006-06-01  Nathan Sidwell  <nathan@codesourcery.com>
 
        * gdb/breakpoint.c (insert_bp_location): Remember the failing
index 4e0f6f2c96853c2ad2748a557be8743961721f63..b0bdb7a1c83102d5cf2b35cdabca3cead4ec7bc3 100644 (file)
@@ -225,6 +225,7 @@ esac
 case "${target}" in
 *-*-freebsd*)  gdb_osabi=GDB_OSABI_FREEBSD_ELF ;;
 *-*-linux*)    gdb_osabi=GDB_OSABI_LINUX ;;
+*-*-ulinux*)   gdb_osabi=GDB_OSABI_LINUX ;;
 *-*-nto*)      gdb_osabi=GDB_OSABI_QNXNTO ;;
 m68*-*-openbsd* | m88*-*-openbsd* | vax-*-openbsd*) ;;
 *-*-openbsd*)  gdb_osabi=GDB_OSABI_OPENBSD_ELF ;;
index 0f021273772bfbebdea7bb4597b1a585bbab35b9..bfec932be79b933673220fffeee6359e46151d7d 100644 (file)
@@ -264,8 +264,11 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache,
       regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
       convert_typed_floating (buf, M68K_FPREG_TYPE, valbuf, type);
     }
+#if 0
+  /* GCC never differentiates pointer return types this way.  */
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
     regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
+#endif
   else
     m68k_extract_return_value (type, regcache, valbuf);
 }
@@ -322,13 +325,97 @@ m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum type_code code = TYPE_CODE (type);
   int len = TYPE_LENGTH (type);
+  int align;
+  int ix;
+  struct type *union_field_type = NULL;
 
   gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION);
 
   if (tdep->struct_return == pcc_struct_return)
     return 0;
 
-  return (len == 1 || len == 2 || len == 4 || len == 8);
+  /* Unfortunately GCC incorrectly implements this optimization.
+     Rather than simply return all small structs, or even just those
+     of size 2^N, it uses the mode of the structure to determine this.
+     BLKmode structs will be returned by memory and QI,HI,SI,DI,SF&DF
+     mode structs will be returned by register.  For m68k a struct is
+     BLKmode unless it's size is 2^N and the mode for that size does
+     not need a greater alignment than the structure itself.  Unions
+     will get the mode of last member whose size matches that of the
+     union itself.  This is horrible.  */
+  
+  if (len > 8 || (len & -len) != len)
+    /* Length is not 2^n or is too big. */
+    return 0;
+
+  align = len > 4 ? 4 : len;
+  for (ix = 0; ix != TYPE_NFIELDS (type); ix++)
+    {
+      struct type *field_type;
+      int field_len;
+      
+      if (TYPE_FIELD_STATIC (type, ix))
+       /* Skip static fields.  */
+       continue;
+
+      field_type = TYPE_FIELD_TYPE (type, ix);
+      field_type = check_typedef (field_type);
+      field_len = TYPE_LENGTH (field_type);
+      
+      if (code == TYPE_CODE_STRUCT)
+       {
+         /* Look through arrays.  */
+         while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY)
+           {
+             field_type = TYPE_TARGET_TYPE (field_type);
+             field_type = check_typedef (field_type);
+             field_len = TYPE_LENGTH (field_type);
+           }
+         
+         /* If the field's alignment is finer than the structs, we
+            won't be in registers. */
+         if (field_len < align)
+           return 0;
+
+         /* If the field itself is a struct or union, then check it
+            can be passed in registers.  */
+         if ((TYPE_CODE (field_type) == TYPE_CODE_STRUCT
+              || TYPE_CODE (field_type) == TYPE_CODE_UNION)
+             && !m68k_reg_struct_return_p (gdbarch, field_type))
+           return 0;
+       }
+      else
+       {
+         /* If this field accounts for the whole union, remember it.
+            Note that we remember the last such field to match GCC's
+            algorithm.  */
+         if (field_len == len)
+           union_field_type = field_type;
+       }
+    }
+
+  if (code == TYPE_CODE_UNION)
+    {
+      if (!union_field_type)
+       return 0;
+      /* Look through arrays. */
+      while (TYPE_CODE (union_field_type) == TYPE_CODE_ARRAY)
+       {
+         union_field_type = TYPE_TARGET_TYPE (union_field_type);
+         union_field_type = check_typedef (union_field_type);
+       }
+      /* If this field's alignment is too small, then we won't be in
+        registers.  */
+      if (TYPE_LENGTH (union_field_type) < align)
+       return 0;
+      
+      if (TYPE_CODE (union_field_type) == TYPE_CODE_STRUCT
+         || TYPE_CODE (union_field_type) == TYPE_CODE_UNION)
+       return m68k_reg_struct_return_p (gdbarch, union_field_type);
+    }
+  
+  /* It will be returned in registers */
+  return 1;
 }
 
 /* Determine, for architecture GDBARCH, how a return value of TYPE
@@ -382,25 +469,11 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *type,
   if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
       && !m68k_reg_struct_return_p (gdbarch, type))
     {
-      /* The System V ABI says that:
-
-        "A function returning a structure or union also sets %a0 to
-        the value it finds in %a0.  Thus when the caller receives
-        control again, the address of the returned object resides in
-        register %a0."
-
-        So the ABI guarantees that we can always find the return
-        value just after the function has returned.  */
-
-      if (readbuf)
-       {
-         ULONGEST addr;
-
-         regcache_raw_read_unsigned (regcache, M68K_A0_REGNUM, &addr);
-         read_memory (addr, readbuf, TYPE_LENGTH (type));
-       }
-
-      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+      /* Although they SYSV ABI specifies that a function returning a
+        structure this way should preserve %a0, GCC doesn't do that.
+        Furthermore there's no point changeing GCC to make it do it,
+        as that would just be bloat. */
+      return RETURN_VALUE_STRUCT_CONVENTION;
     }
 
   /* This special case is for structures consisting of a single
@@ -435,6 +508,9 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   gdb_byte buf[4];
   int i;
 
+  /* Align the stack down to 4 bytes.  Needed for coldfire. */
+  sp &= ~3;
+  
   /* Push arguments in reverse order.  */
   for (i = nargs - 1; i >= 0; i--)
     {
@@ -1114,8 +1190,22 @@ m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* SVR4 uses a different calling convention.  */
   set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
 
-  /* SVR4 uses %a0 instead of %a1.  */
+  /* SVR4 uses %a0.  */
   tdep->struct_value_regnum = M68K_A0_REGNUM;
+  tdep->struct_return = reg_struct_return;
+}
+
+/* a.out */
+
+void
+m68k_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  set_gdbarch_return_value (gdbarch, m68k_return_value);
+
+  tdep->struct_value_regnum = M68K_A1_REGNUM;
+  tdep->struct_return = reg_struct_return;
 }
 \f
 
@@ -1163,8 +1253,13 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_to_value (gdbarch,  m68k_register_to_value);
   set_gdbarch_value_to_register (gdbarch, m68k_value_to_register);
 
+  /* Function call & return */
   set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
-  set_gdbarch_return_value (gdbarch, m68k_return_value);
+  /* These values are for bare metal -- os specific ABIs can override
+     them */
+  set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
+  tdep->struct_value_regnum = M68K_A0_REGNUM;
+  tdep->struct_return = reg_struct_return;
 
   /* Disassembler.  */
   set_gdbarch_print_insn (gdbarch, print_insn_m68k);
index 94e90d7236302c977a700c02e2e14efa189dbcfa..77cb003e93e4cd89b4f87a828015386b6f045f33 100644 (file)
@@ -80,6 +80,8 @@ struct gdbarch_tdep
 
 /* Initialize a SVR4 architecture variant.  */
 extern void m68k_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
+/* Initialize a aout architecture variant.   */
+extern void m68k_aout_init_abi (struct gdbarch_info, struct gdbarch *);
 \f
 
 /* Functions exported from m68kbsd-tdep.c.  */
index eb5dfe003497b10957769be88595f2aec47da5d1..c74b18acd27631c5b5b0c3ac2c662a0950f57bce 100644 (file)
@@ -206,7 +206,7 @@ m68kbsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   m68kbsd_init_abi (info, gdbarch);
 
-  tdep->struct_return = reg_struct_return;
+  m68k_aout_init_abi (info, gdbarch);
 
   tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp);
 }
@@ -222,6 +222,7 @@ m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   /* NetBSD ELF uses the SVR4 ABI.  */
   m68k_svr4_init_abi (info, gdbarch);
+  /* But with pcc structure return */
   tdep->struct_return = pcc_struct_return;
 
   /* NetBSD ELF uses SVR4-style shared libraries.  */
index 6da4d1514c41a94bde4186da448da74453ca92a3..29728688e9ee0b9f44108846b1957a0c72b0f1f2 100644 (file)
@@ -291,8 +291,8 @@ m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
      address to store a structure value.  It also returns small
      structures in registers instead of memory.  */
   m68k_svr4_init_abi (info, gdbarch);
+  /* But the struct pointer is in %a1 */
   tdep->struct_value_regnum = M68K_A1_REGNUM;
-  tdep->struct_return = reg_struct_return;
 
   frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);