This is the mail archive of the gdb-patches@sources.redhat.com 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]

[RFA] Generic solution for store_struct_address


This patch lets store_struct_address save the struct_addr in a LIFO
queue, 
from which extract_struct_value_address can then pull it out.  The value
of SP is used as a confidence check, to make sure each struct_addr goes
to the right stack frame.  If the struct_addr isn't found on the queue, 
then the target can fall back to extracting it from a register.

I'm pretty sure this works -- I've tested it on mips, arm, d10v and
i386.
Kevin, would you by any chance be in a position to test it on ia64
and/or
rs6000?

I've included patches for all of the targets that use the infamous
"horrid kludge" from rs6000-tdep.c.  Those will of course have to
be approved by individual maintainers, but the shared code could go
in before then.

Andrew, OK for mips?  Tested, of course...

Michael
2002-08-21  Michael Snyder  <msnyder@redhat.com>

	* arch-utils.c (generic_push_struct_return, 
	generic_pop_struct_return): New functions, helpers for 
	store_struct_return and extract_struct_value_address.
	* arch-utils.h: External interface to the above.
	* cris-tdep.c (cris_store_struct_return): Use above.
	(cris_extract_struct_value_address): Ditto.
	* ia64-tdep.c (ia64_store_struct_return): Use above.
	(ia64_extract_struct_value_address): Ditto.
	* mips-tdep.c (mips_store_struct_return): Use above.
	(mips_extract_struct_value_address): Ditto.
	* ia64-tdep.c (ia64_store_struct_return): Use above.
	(ia64_extract_struct_value_address): Ditto.

Index: arch-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/arch-utils.h,v
retrieving revision 1.40
diff -c -3 -p -r1.40 arch-utils.h
*** arch-utils.h	20 Aug 2002 23:01:28 -0000	1.40
--- arch-utils.h	22 Aug 2002 02:26:47 -0000
*************** extern int generic_register_size (int re
*** 156,161 ****
--- 156,165 ----
  /* Assume that the world is sane, the registers are all adjacent.  */
  extern int generic_register_byte (int regnum);
  
+ /* A stack of struct_returns.  */
+ extern void generic_push_struct_return (CORE_ADDR addr, CORE_ADDR sp);
+ extern CORE_ADDR generic_pop_struct_return (CORE_ADDR sp);
+ 
  /* Prop up old targets that use various IN_SIGTRAMP() macros.  */
  extern int legacy_pc_in_sigtramp (CORE_ADDR pc, char *name);
  
Index: arch-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/arch-utils.c,v
retrieving revision 1.66
diff -c -3 -p -r1.66 arch-utils.c
*** arch-utils.c	20 Aug 2002 23:01:28 -0000	1.66
--- arch-utils.c	22 Aug 2002 02:26:47 -0000
*************** generic_register_byte (int regnum)
*** 453,458 ****
--- 453,504 ----
  }
  
  
+ /* A simple stack of struct return addresses, stored by
+    store_struct_return and fetched by extract_struct_value_address.
+    Uses the stack pointer value as a key/identifier.  */
+ 
+ struct struct_return_stack {
+   CORE_ADDR addr;
+   CORE_ADDR sp;
+ };
+ 
+ static struct struct_return_stack *struct_return_stack = NULL;
+ static int struct_return_stack_depth = 0;
+ static int struct_return_tos = 0;
+ 
+ enum { STRUCT_RETURN_STACK_CHUNK = 128 };
+ 
+ void
+ generic_push_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+ {
+   if (struct_return_tos >= struct_return_stack_depth)
+     {
+       struct_return_stack_depth += STRUCT_RETURN_STACK_CHUNK;
+       struct_return_stack = xrealloc (struct_return_stack, 
+ 				      struct_return_stack_depth * 
+ 				      sizeof (struct struct_return_stack));
+     }
+   struct_return_stack[struct_return_tos].addr = addr;
+   struct_return_stack[struct_return_tos].sp = sp;
+   struct_return_tos++;
+ }
+ 
+ CORE_ADDR
+ generic_pop_struct_return (CORE_ADDR sp)
+ {
+   /* Stack empty?  */
+   if (struct_return_tos == 0)
+     return 0;
+ 
+   /* Does this SP match the one on the top of our stack?  */
+   if (sp != struct_return_stack[struct_return_tos - 1].sp)
+     return 0;
+ 
+   /* Top-of-stack is a valid struct_return value.  Return it.  */
+   return struct_return_stack[--struct_return_tos].addr;
+ }
+ 
+ 
  int
  legacy_pc_in_sigtramp (CORE_ADDR pc, char *name)
  {
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.76
diff -c -3 -p -r1.76 rs6000-tdep.c
*** rs6000-tdep.c	21 Aug 2002 22:56:02 -0000	1.76
--- rs6000-tdep.c	22 Aug 2002 02:26:47 -0000
*************** rs6000_extract_return_value (struct type
*** 1193,1200 ****
     living.  This only allows a single nested call to a structure-returning
     function.  Come on, guys!  -- gnu@cygnus.com, Aug 92  */
  
- static CORE_ADDR rs6000_struct_return_address;
- 
  /* Return whether handle_inferior_event() should proceed through code
     starting at PC in function NAME when stepping.
  
--- 1193,1198 ----
*************** rs6000_stab_reg_to_regnum (int num)
*** 1789,1802 ****
  
     In RS/6000, struct return addresses are passed as an extra parameter in r3.
     In function return, callee is not responsible of returning this address
!    back.  Since gdb needs to find it, we will store in a designated variable
!    `rs6000_struct_return_address'.  */
  
  static void
  rs6000_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
    write_register (3, addr);
-   rs6000_struct_return_address = addr;
  }
  
  /* Write into appropriate registers a function return value
--- 1787,1800 ----
  
     In RS/6000, struct return addresses are passed as an extra parameter in r3.
     In function return, callee is not responsible of returning this address
!    back.  Since gdb needs to find it, we will store in a LIFO queue of
!    struct-return addresses.  */
  
  static void
  rs6000_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
+   generic_push_struct_return (addr, sp);
    write_register (3, addr);
  }
  
  /* Write into appropriate registers a function return value
*************** rs6000_store_return_value (struct type *
*** 1833,1841 ****
     as a CORE_ADDR (or an expression that can be used as one).  */
  
  static CORE_ADDR
! rs6000_extract_struct_value_address (char *regbuf)
  {
!   return rs6000_struct_return_address;
  }
  
  /* Return whether PC is in a dummy function call.
--- 1831,1848 ----
     as a CORE_ADDR (or an expression that can be used as one).  */
  
  static CORE_ADDR
! rs6000_extract_struct_value_address (struct regcache *regcache)
  {
!   ULONGEST ret, sp;
! 
!   /* First try to fetch a struct_return from the cache.  */
!   regcache_cooked_read_unsigned (regcache, SP_REGNUM, &sp);
!   ret = generic_pop_struct_return (sp);
!   /* Failing that, get it from register 3.  FIXME name?  constant?  */
!   if (ret == 0)
!     regcache_cooked_read_unsigned (regcache, 3, &ret);
! 
!   return ret;
  }
  
  /* Return whether PC is in a dummy function call.
*************** rs6000_gdbarch_init (struct gdbarch_info
*** 2684,2690 ****
  
    set_gdbarch_store_struct_return (gdbarch, rs6000_store_struct_return);
    set_gdbarch_store_return_value (gdbarch, rs6000_store_return_value);
!   set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
    set_gdbarch_pop_frame (gdbarch, rs6000_pop_frame);
  
    set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
--- 2691,2697 ----
  
    set_gdbarch_store_struct_return (gdbarch, rs6000_store_struct_return);
    set_gdbarch_store_return_value (gdbarch, rs6000_store_return_value);
!   set_gdbarch_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
    set_gdbarch_pop_frame (gdbarch, rs6000_pop_frame);
  
    set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.118
diff -c -3 -p -r1.118 mips-tdep.c
*** mips-tdep.c	21 Aug 2002 22:39:26 -0000	1.118
--- mips-tdep.c	22 Aug 2002 02:26:47 -0000
*************** mips_eabi_push_arguments (int nargs,
*** 2622,2628 ****
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_eabi_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       write_register (argreg++, struct_addr);
      }
  
    /* Now load as many as possible of the first arguments into
--- 2622,2628 ----
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_eabi_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       argreg++;		/* Reg reserved for passing struct_addr.  */
      }
  
    /* Now load as many as possible of the first arguments into
*************** mips_n32n64_push_arguments (int nargs,
*** 2873,2879 ****
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       write_register (argreg++, struct_addr);
      }
  
    /* Now load as many as possible of the first arguments into
--- 2873,2879 ----
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       argreg++;		/* Reg reserved for passing struct_addr.  */
      }
  
    /* Now load as many as possible of the first arguments into
*************** mips_o32_push_arguments (int nargs,
*** 3099,3105 ****
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_o32_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       write_register (argreg++, struct_addr);
        stack_offset += MIPS_STACK_ARGSIZE;
      }
  
--- 3099,3105 ----
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_o32_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       argreg++;		/* Reg reserved for passing struct_addr.  */
        stack_offset += MIPS_STACK_ARGSIZE;
      }
  
*************** mips_o64_push_arguments (int nargs,
*** 3398,3404 ****
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_o64_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       write_register (argreg++, struct_addr);
        stack_offset += MIPS_STACK_ARGSIZE;
      }
  
--- 3398,3404 ----
  	fprintf_unfiltered (gdb_stdlog,
  			    "mips_o64_push_arguments: struct_return reg=%d 0x%s\n",
  			    argreg, paddr_nz (struct_addr));
!       argreg++;		/* Reg reserved for passing struct_addr.  */
        stack_offset += MIPS_STACK_ARGSIZE;
      }
  
*************** mips_n32n64_store_return_value (struct t
*** 4902,4917 ****
  static void
  mips_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
!   /* Nothing to do -- push_arguments does all the work.  */
  }
  
  static CORE_ADDR
! mips_extract_struct_value_address (struct regcache *ignore)
  {
!   /* FIXME: This will only work at random.  The caller passes the
!      struct_return address in V0, but it is not preserved.  It may
!      still be there, or this may be a random value.  */
!   return read_register (V0_REGNUM);
  }
  
  /* Exported procedure: Is PC in the signal trampoline code */
--- 4902,4926 ----
  static void
  mips_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
!   /* Save the struct_return address in a LIFO stack.  */
!   addr = ROUND_DOWN (addr, 16);
!   generic_push_struct_return (addr, sp);
!   write_register (A0_REGNUM, addr);
  }
  
  static CORE_ADDR
! mips_extract_struct_value_address (struct regcache *regcache)
  {
!   ULONGEST ret, sp;
! 
!   /* First try to fetch a struct_return from the cache.  */
!   regcache_cooked_read_unsigned (regcache, SP_REGNUM, &sp);
!   ret = generic_pop_struct_return (sp);
!   /* Failing that, get it from V0.  */
!   if (ret == 0)
!     regcache_cooked_read_unsigned (regcache, V0_REGNUM, &ret);
! 
!   return ret;
  }
  
  /* Exported procedure: Is PC in the signal trampoline code */
Index: cris-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/cris-tdep.c,v
retrieving revision 1.20
diff -c -3 -p -r1.20 cris-tdep.c
*** cris-tdep.c	11 Jul 2002 19:25:13 -0000	1.20
--- cris-tdep.c	22 Aug 2002 02:26:47 -0000
*************** cris_abi (void)
*** 173,181 ****
    return (gdbarch_tdep (current_gdbarch)->cris_abi);
  }
  
- /* For saving call-clobbered contents in R9 when returning structs.  */
- static CORE_ADDR struct_return_address;
- 
  struct frame_extra_info
  {
    CORE_ADDR return_pc;
--- 173,178 ----
*************** void
*** 1085,1091 ****
  cris_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
    write_register (STR_REGNUM, addr);
!   struct_return_address = addr;
  }
  
  /* Extract from regbuf the address where a function should return a 
--- 1082,1088 ----
  cris_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
    write_register (STR_REGNUM, addr);
!   generic_push_return_address (addr, sp);
  }
  
  /* Extract from regbuf the address where a function should return a 
*************** cris_store_struct_return (CORE_ADDR addr
*** 1093,1101 ****
     way.  */
  
  CORE_ADDR
! cris_extract_struct_value_address (char *regbuf)
  {
!   return struct_return_address;
  }
  
  /* Returns 1 if a value of the given type being returned from a function 
--- 1090,1107 ----
     way.  */
  
  CORE_ADDR
! cris_extract_struct_value_address (struct regcache *regcache)
  {
!   ULONGEST ret, sp;
! 
!   /* First try to fetch a struct_return from the cache.  */
!   regcache_cooked_read_unsigned (regcache, SP_REGNUM, &sp);
!   ret = generic_pop_struct_return (sp);
!   /* Failing that, get it from STR_REGNUM.  */
!   if (ret == 0)
!     regcache_cooked_read_unsigned (regcache, STR_REGNUM, &ret);
! 
!   return ret;
  }
  
  /* Returns 1 if a value of the given type being returned from a function 
*************** cris_gdbarch_init (struct gdbarch_info i
*** 4297,4303 ****
    set_gdbarch_pop_frame (gdbarch, cris_pop_frame);
  
    set_gdbarch_store_struct_return (gdbarch, cris_store_struct_return);
!   set_gdbarch_deprecated_extract_struct_value_address
      (gdbarch, cris_extract_struct_value_address);
    set_gdbarch_use_struct_convention (gdbarch, cris_use_struct_convention);
  
--- 4303,4309 ----
    set_gdbarch_pop_frame (gdbarch, cris_pop_frame);
  
    set_gdbarch_store_struct_return (gdbarch, cris_store_struct_return);
!   set_gdbarch_extract_struct_value_address
      (gdbarch, cris_extract_struct_value_address);
    set_gdbarch_use_struct_convention (gdbarch, cris_use_struct_convention);
  
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.32
diff -c -3 -p -r1.32 ia64-tdep.c
*** ia64-tdep.c	17 Jun 2002 23:32:31 -0000	1.32
--- ia64-tdep.c	22 Aug 2002 02:26:47 -0000
*************** ia64_extract_return_value (struct type *
*** 1428,1451 ****
  	    TYPE_LENGTH (type));
  }
  
- /* FIXME: Turn this into a stack of some sort.  Unfortunately, something
-    like this is necessary though since the IA-64 calling conventions specify
-    that r8 is not preserved. */
- static CORE_ADDR struct_return_address;
- 
  CORE_ADDR
! ia64_extract_struct_value_address (char *regbuf)
  {
!   /* FIXME: See above. */
!   return struct_return_address;
  }
  
  void
  ia64_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
-   /* FIXME: See above. */
    /* Note that most of the work was done in ia64_push_arguments() */
!   struct_return_address = addr;
  }
  
  int
--- 1428,1453 ----
  	    TYPE_LENGTH (type));
  }
  
  CORE_ADDR
! ia64_extract_struct_value_address (struct regcache *regcache)
  {
!   ULONGEST ret, sp;
! 
!   /* First try to fetch a struct_return from the cache.  */
!   regcache_cooked_read_unsigned (regcache, SP_REGNUM, &sp);
!   ret = generic_pop_struct_return (sp);
!   /* Failing that, get it from GR8.  */
!   if (ret == 0)
!     regcache_cooked_read_unsigned (regcache, IA64_GR8_REGNUM, &ret);
! 
!   return ret;
  }
  
  void
  ia64_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
  {
    /* Note that most of the work was done in ia64_push_arguments() */
!   generic_push_struct_return (addr, sp);
  }
  
  int
*************** ia64_gdbarch_init (struct gdbarch_info i
*** 2194,2200 ****
  
    set_gdbarch_store_struct_return (gdbarch, ia64_store_struct_return);
    set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
!   set_gdbarch_deprecated_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
  
    set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
    set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
--- 2196,2203 ----
  
    set_gdbarch_store_struct_return (gdbarch, ia64_store_struct_return);
    set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
!   set_gdbarch_extract_struct_value_address (gdbarch, 
! 					    ia64_extract_struct_value_address);
  
    set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
    set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);

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