This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [m68k] fix return value extraction
Andreas Schwab wrote:
Nathan Sidwell <nathan@codesourcery.com> writes:
*) GCC never sets %a0 to point to a returned structure. Neither does it
return pointer values in %a0.
On m68k-linux, which uses the SVR4 ABI (or a close variant thereof) it
does return pointer values in %a0.
ah, yes. this variant of my patch adds a ptr_value_regnum field to the tdep
structure to account for this difference.
ok?
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
2006-06-06 Nathan Sidwell <nathan@codesourcery.com>
* gdb/configure.tgt (gdb_osabi): uclinux is like linux.
* gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Use
tdep->ptr_value_regnum for pointer returns.
(m68k_svr4_store_return_value): Likewise.
(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 & pointer value
regnum.
(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.
(struct gdbarch_tdep): Add ptr_value_regnum field.
* 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.
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.172
diff -c -3 -p -r1.172 configure.tgt
*** configure.tgt 20 Apr 2006 23:18:48 -0000 1.172
--- configure.tgt 6 Jun 2006 10:15:55 -0000
*************** esac
*** 223,228 ****
--- 223,229 ----
case "${target}" in
*-*-freebsd*) gdb_osabi=GDB_OSABI_FREEBSD_ELF ;;
*-*-linux*) gdb_osabi=GDB_OSABI_LINUX ;;
+ *-*-uclinux*) 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: m68k-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/m68k-tdep.c,v
retrieving revision 1.105
diff -c -3 -p -r1.105 m68k-tdep.c
*** m68k-tdep.c 17 Dec 2005 22:34:01 -0000 1.105
--- m68k-tdep.c 6 Jun 2006 10:15:56 -0000
*************** m68k_svr4_extract_return_value (struct t
*** 253,259 ****
convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
! regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
else
m68k_extract_return_value (type, regcache, valbuf);
}
--- 253,261 ----
convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
! regcache_raw_read (regcache,
! gdbarch_tdep (current_gdbarch)->ptr_value_regnum,
! valbuf);
else
m68k_extract_return_value (type, regcache, valbuf);
}
*************** m68k_svr4_store_return_value (struct typ
*** 292,301 ****
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
! {
! regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
! regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf);
! }
else
m68k_store_return_value (type, regcache, valbuf);
}
--- 294,302 ----
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
! regcache_raw_write (regcache,
! gdbarch_tdep (current_gdbarch)->ptr_value_regnum,
! valbuf);
else
m68k_store_return_value (type, regcache, valbuf);
}
*************** m68k_reg_struct_return_p (struct gdbarch
*** 310,322 ****
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
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);
}
/* Determine, for architecture GDBARCH, how a return value of TYPE
--- 311,407 ----
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;
! /* 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
*************** m68k_svr4_return_value (struct gdbarch *
*** 370,394 ****
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;
}
/* This special case is for structures consisting of a single
--- 455,465 ----
if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
&& !m68k_reg_struct_return_p (gdbarch, type))
{
! /* 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
*************** m68k_push_dummy_call (struct gdbarch *gd
*** 423,428 ****
--- 494,502 ----
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--)
{
*************** m68k_svr4_init_abi (struct gdbarch_info
*** 1102,1109 ****
/* SVR4 uses a different calling convention. */
set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
! /* SVR4 uses %a0 instead of %a1. */
tdep->struct_value_regnum = M68K_A0_REGNUM;
}
--- 1176,1202 ----
/* SVR4 uses a different calling convention. */
set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
! /* SVR4 uses %a0. */
tdep->struct_value_regnum = M68K_A0_REGNUM;
+ tdep->struct_return = reg_struct_return;
+ /* Pointers are returned in %a0 */
+ tdep->ptr_value_regnum = M68K_A0_REGNUM;
+ }
+
+ /* 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);
+
+ /* aout uses %a1 */
+ tdep->struct_value_regnum = M68K_A1_REGNUM;
+ tdep->struct_return = reg_struct_return;
+ /* Pointers are returned in %a0 */
+ tdep->ptr_value_regnum = M68K_A0_REGNUM;
}
*************** m68k_gdbarch_init (struct gdbarch_info i
*** 1151,1158 ****
set_gdbarch_register_to_value (gdbarch, m68k_register_to_value);
set_gdbarch_value_to_register (gdbarch, m68k_value_to_register);
set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
! set_gdbarch_return_value (gdbarch, m68k_return_value);
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_m68k);
--- 1244,1257 ----
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);
! /* 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;
! tdep->ptr_value_regnum = M68K_D0_REGNUM;
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_m68k);
*************** m68k_gdbarch_init (struct gdbarch_info i
*** 1163,1170 ****
#else
tdep->jb_pc = -1;
#endif
- tdep->struct_value_regnum = M68K_A1_REGNUM;
- tdep->struct_return = reg_struct_return;
/* Frame unwinder. */
set_gdbarch_unwind_dummy_id (gdbarch, m68k_unwind_dummy_id);
--- 1262,1267 ----
Index: m68k-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/m68k-tdep.h,v
retrieving revision 1.10
diff -c -3 -p -r1.10 m68k-tdep.h
*** m68k-tdep.h 17 Dec 2005 22:34:01 -0000 1.10
--- m68k-tdep.h 6 Jun 2006 10:15:56 -0000
*************** struct gdbarch_tdep
*** 76,85 ****
--- 76,90 ----
/* Convention for returning structures. */
enum struct_return struct_return;
+
+ /* Register in which pointers are returned. */
+ int ptr_value_regnum;
};
/* 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. */
Index: m68kbsd-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/m68kbsd-tdep.c,v
retrieving revision 1.7
diff -c -3 -p -r1.7 m68kbsd-tdep.c
*** m68kbsd-tdep.c 17 Dec 2005 22:34:01 -0000 1.7
--- m68kbsd-tdep.c 6 Jun 2006 10:15:56 -0000
*************** m68kbsd_aout_init_abi (struct gdbarch_in
*** 206,212 ****
m68kbsd_init_abi (info, gdbarch);
! tdep->struct_return = reg_struct_return;
tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp);
}
--- 206,212 ----
m68kbsd_init_abi (info, gdbarch);
! m68k_aout_init_abi (info, gdbarch);
tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp);
}
*************** m68kbsd_elf_init_abi (struct gdbarch_inf
*** 222,227 ****
--- 222,228 ----
/* 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: m68klinux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/m68klinux-tdep.c,v
retrieving revision 1.18
diff -c -3 -p -r1.18 m68klinux-tdep.c
*** m68klinux-tdep.c 20 Apr 2006 17:29:47 -0000 1.18
--- m68klinux-tdep.c 6 Jun 2006 10:15:56 -0000
*************** m68k_linux_init_abi (struct gdbarch_info
*** 291,298 ****
address to store a structure value. It also returns small
structures in registers instead of memory. */
m68k_svr4_init_abi (info, gdbarch);
tdep->struct_value_regnum = M68K_A1_REGNUM;
- tdep->struct_return = reg_struct_return;
frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);
--- 291,298 ----
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;
frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);