This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[m68k] fix return value extraction


I discovered gdb's idea of how values are returned differed significantly from how gcc actually returned things. Although gcc might be at variance from the ABI specification, I didn't want to change gcc's behaviour and thereby introduce ABI incompatibilities there. AFAICT gcc's behaviour has been unchanged for a while.

*) GCC passes smalls structs that have an integral mode in a register, not small structs per se. It is annoying that an implementation detail of gcc's internals is affecting the ABI this way. I've reproduced what I think is an equivalent algorithm, so gdb can determine this.

*) GCC never sets %a0 to point to a returned structure. Neither does it return pointer values in %a0.

*) coldfire chips really need the stack to be aligned to a 4 byte boundary.

*) In order for bare metal elf to work, I've defaulted gdb's configuration to be that, and added an os initialization routine for a.out.

*) I've enabled the linux sniffers for a uclinux target.

tested on a coldfire target board bare metal.

ok?

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

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.

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	5 Jun 2006 15:16: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	5 Jun 2006 15:16:56 -0000
*************** m68k_svr4_extract_return_value (struct t
*** 252,259 ****
--- 252,262 ----
        regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
        convert_typed_floating (buf, builtin_type_m68881_ext, 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);
  }
*************** 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
--- 313,409 ----
    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
--- 457,467 ----
    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 ****
--- 496,504 ----
    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;
  }
  
  
--- 1178,1199 ----
    /* 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;
+ }
+ 
+ /* 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;
  }
  
  
*************** 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);
--- 1241,1253 ----
    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;
  
    /* 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);
--- 1258,1263 ----
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	5 Jun 2006 15:16:56 -0000
*************** struct gdbarch_tdep
*** 80,85 ****
--- 80,87 ----
  
  /* 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	5 Jun 2006 15:16: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	5 Jun 2006 15:16: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);
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]