summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2006-06-05 14:51:35 +0000
committerNathan Sidwell <nathan@codesourcery.com>2006-06-05 14:51:35 +0000
commit0feedba6575f0200a743732aa988afd486308e4a (patch)
tree06d431fad39c5807e33d71408a6c3255527dde53
parent99974f2862809845f6c92aae4a78434bb5777ec0 (diff)
downloadgdb-0feedba6575f0200a743732aa988afd486308e4a.tar.gz
i * 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.
-rw-r--r--ChangeLog.csl18
-rw-r--r--gdb/configure.tgt1
-rw-r--r--gdb/m68k-tdep.c139
-rw-r--r--gdb/m68k-tdep.h2
-rw-r--r--gdb/m68kbsd-tdep.c3
-rw-r--r--gdb/m68klinux-tdep.c2
6 files changed, 141 insertions, 24 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index 5ccd8ced388..95f6f57ec9e 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -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
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 4e0f6f2c968..b0bdb7a1c83 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -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 ;;
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index 0f021273772..bfec932be79 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -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;
}
@@ -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);
diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h
index 94e90d72363..77cb003e93e 100644
--- a/gdb/m68k-tdep.h
+++ b/gdb/m68k-tdep.h
@@ -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 *);
/* Functions exported from m68kbsd-tdep.c. */
diff --git a/gdb/m68kbsd-tdep.c b/gdb/m68kbsd-tdep.c
index eb5dfe00349..c74b18acd27 100644
--- a/gdb/m68kbsd-tdep.c
+++ b/gdb/m68kbsd-tdep.c
@@ -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. */
diff --git a/gdb/m68klinux-tdep.c b/gdb/m68klinux-tdep.c
index 6da4d1514c4..29728688e9e 100644
--- a/gdb/m68klinux-tdep.c
+++ b/gdb/m68klinux-tdep.c
@@ -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);