Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [rfa:ppc64] Fix 64-bit PPC ELF function calls
@ 2003-09-21 23:38 Andrew Cagney
  2003-09-22 17:59 ` Andrew Cagney
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Cagney @ 2003-09-21 23:38 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 638 bytes --]

Hello,

This patch implements a 4-bit PPC ELF specific push_dummy_call method. 
It then adds a work-around (*_broken_push_dummy_call) for what would 
appear to be GCC bugs.  This fixes ~200 failures (give or take the 3 
fixed by the workaround).

Ok to commit?

Andrew

PS: The apparent bugs are:

- small odd structs get passed in memory instead of a register (ref 
structs.exp:Fun3).
- small even structs get passed right, instead of left, aligned in the 
register (ref structs.exp:Fun[12]).

PS: Backtraces are a bit sick.

PPS: Oh, note the "hack" to find the TOC from the function's entry point 
address.  Without it malloc() fails.

[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 13248 bytes --]

2003-09-21  Andrew Cagney  <cagney@redhat.com>

	* ppc-linux-tdep.c (ppc_linux_init_abi): When 64-bit, set
	"push_dummy_call" to "ppc64_sysv_abi_broken_push_dummy_call".
	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
	* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): New function.
	(ppc64_sysv_abi_broken_push_dummy_call): New function.
	(do_ppc64_sysv_abi_push_dummy_call): New function.
	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
	(ppc64_sysv_abi_broken_push_dummy_call): Declare.

Index: ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.40
diff -u -r1.40 ppc-linux-tdep.c
--- ppc-linux-tdep.c	16 Sep 2003 23:33:17 -0000	1.40
+++ ppc-linux-tdep.c	21 Sep 2003 23:31:14 -0000
@@ -1074,6 +1074,12 @@
       set_gdbarch_in_solib_call_trampoline
         (gdbarch, ppc64_in_solib_call_trampoline);
       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+
+      /* GCC, on GNU/Linux appears to screw up passing small struct
+         parameters.  Odd sized ones end up in memory (when they
+         should be in a register) and even-sized ones end up right
+         shifted (they should be left shifted) in a register.  */
+      set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_broken_push_dummy_call);
     }
 }
 
Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.11
diff -u -r1.11 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	16 Sep 2003 23:33:17 -0000	1.11
+++ ppc-sysv-tdep.c	21 Sep 2003 23:31:14 -0000
@@ -340,3 +340,266 @@
 
   return (TYPE_LENGTH (value_type) > 8);
 }   
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc 64 bit SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic. */
+
+static CORE_ADDR
+do_ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				   struct regcache *regcache, CORE_ADDR bp_addr,
+				   int nargs, struct value **args, CORE_ADDR sp,
+				   int struct_return, CORE_ADDR struct_addr,
+				   int broken_gcc)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* By this stage in the proceedings, SP has been decremented by "red
+     zone size" + "struct return size".  Fetch the stack-pointer from
+     before this and use that as the BACK_CHAIN.  */
+  const CORE_ADDR back_chain = read_sp ();
+  /* The address of the top of the parameter save region (typically
+     points at the local variable region).  On entry, the SP is
+     pointing at this.  */
+  const CORE_ADDR param_top = sp;
+  /* Address, on the stack, of the next general (integer, struct,
+     float, ...) parameter.  */
+  CORE_ADDR gparam = 0;
+  /* Address, on the stack, of the next vector.  */
+  CORE_ADDR vparam = 0;
+  /* First (computation) or second (write) pass over the parameter
+     list.  */
+  int write_pass;
+
+  /* Go through the argument list twice.
+
+     Pass 1: Figure out how much stack space is required for arguments
+     and pushed values.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
+
+  for (write_pass = 0; write_pass < 2; write_pass++)
+    {
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-vector (but possibly
+         float) arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+
+      /* If the function is returning a `struct', then there is an
+	 extra hidden parameter (which will be passed in r3)
+	 containing the address of that struct..  In that case we
+	 should advance one word and start from r4 register to copy
+	 parameters.  This also consumes one parameter space slot.  */
+      if (struct_return)
+	{
+	  if (write_pass)
+	    regcache_cooked_write_signed (regcache,
+					  tdep->ppc_gp0_regnum + greg,
+					  struct_addr);
+	  greg++;
+	  gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+	}
+
+      for (argno = 0; argno < nargs; argno++)
+	{
+	  struct value *arg = args[argno];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  char *val = VALUE_CONTENTS (arg);
+	  /* Floats and Doubles go in f1 .. f13.  They also consume a
+             left aligned GREG,, and can end up in memory.  */
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT
+	      && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  if (ppc_floating_point_unit_p (current_gdbarch)
+		      && freg <= 13)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      struct type *regtype = register_type (gdbarch,
+							    FP0_REGNUM);
+		      convert_typed_floating (val, type, regval, regtype);
+		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
+					     regval);
+		    }
+		  if (greg <= 10)
+		    {
+		      /* It goes into the register, left aligned (as
+                         far as I can tell).  */
+		      char regval[MAX_REGISTER_SIZE];
+		      memset (regval, 0, sizeof regval);
+		      memcpy (regval, val, TYPE_LENGTH (type));
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     regval);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      /* Always consume parameter stack space.  */
+	      freg++;
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+		   && tdep->ppc_vr0_regnum >= 0)
+	    {
+	      /* Vectors go in the vector registers v2 .. v13, or when
+                 that runs out, a vector annex which goes after all
+                 the registers.  NOTE: cagney/2003-09-21: This is a
+                 guess based on the PowerOpen Altivec ABI.  */
+	      if (vreg <= 13)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_vr0_regnum + vreg, val);
+		  vreg++;
+		}
+	      else
+		{
+		  if (write_pass)
+		    write_memory (vparam, val, TYPE_LENGTH (type));
+		  vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+		}
+	    }
+	  /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+             They can also end up in memory.  */
+	  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+		    || TYPE_CODE (type) == TYPE_CODE_ENUM)
+		   && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  /* Sign extend the value, then store it unsigned.  */
+		  ULONGEST word = unpack_long (type, val);
+		  if (greg <= 10)
+		    regcache_cooked_write_unsigned (regcache,
+						    tdep->ppc_gp0_regnum + greg,
+						    word);
+		  write_memory_unsigned_integer (gparam, tdep->wordsize, word);
+		}
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else
+	    {
+	      int byte;
+	      for (byte = 0; byte < TYPE_LENGTH (type); byte += tdep->wordsize)
+		{
+		  if (write_pass && greg <= 10)
+		    {
+		      int len = TYPE_LENGTH (type) - byte;
+		      if (len > tdep->wordsize)
+			len = tdep->wordsize;
+		      /* WARNING: cagney/2003-09-21: As best I can
+			 tell, the ABI specifies that the value be
+			 left aligned (it's talking about slot numbers
+			 and writing an entire word is as easy as a
+			 part word).  Unfortunatly, GCC doesn't do
+			 this.  It instead right aligns the value in a
+			 struct (if even), and gets the value from
+			 memory (if odd).  Arrrgh!  */
+		      if (broken_gcc)
+			regcache_cooked_write_part (regcache,
+						    tdep->ppc_gp0_regnum + greg,
+						    tdep->wordsize - len, len,
+						    val + byte);
+		      else
+			regcache_cooked_write_part (regcache,
+						    tdep->ppc_gp0_regnum + greg,
+						    0, len, val + byte);
+		    }
+		  greg++;
+		}
+	      if (write_pass)
+		/* WARNING: cagney/2003-09-21: Strictly speaking, this
+                   isn't necessary, however, since it makes the logic
+                   simpler it can't hurt eh?.  Oh, and bofore I
+                   forget, and GCC screws up the passing of odd sized
+                   struct parameters putting them in memory instead of
+                   in a register - this memory write hides the problem
+                   :-/ */
+		write_memory (gparam, val, TYPE_LENGTH (type));
+	      /* Always consume parameter stack space.  */
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	}
+
+      /* Compute the actual stack space requirements.  48 is lifted
+         direct from the ABI, it is ment to hold holds things like the
+         LR and CR.  */
+      if (!write_pass)
+	{
+	  vparam = align_down (param_top - vparam, 16);
+	  gparam = align_down (vparam - gparam, 16);
+	  sp = align_down (gparam - 48, 16);
+	}
+    }
+
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+  /* Point the inferior function call's return address at the dummy's
+     breakpoint.  */
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+  /* Find a value for the TOC register.  Every symbol should have both
+     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
+     F's descriptor, while ".FN" points at the entry point (which
+     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
+     FN's descriptor address.  */
+  {
+    /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+       have the name ".FN").  */
+    struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+    if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+      {
+	/* Now find the corresponding "FN" (dropping ".") minimal
+           symbol's address.  */
+	struct minimal_symbol *fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, NULL);
+	if (fn != NULL)
+	  {
+	    /* Got the address of that descriptor.  The TOC is the
+               second double word.  */
+	    CORE_ADDR toc = read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) + tdep->wordsize, tdep->wordsize);
+	    regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 2, toc);
+	  }
+      }
+  }
+
+  return sp;
+}
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				struct regcache *regcache, CORE_ADDR bp_addr,
+				int nargs, struct value **args, CORE_ADDR sp,
+				int struct_return, CORE_ADDR struct_addr)
+{
+  return do_ppc64_sysv_abi_push_dummy_call (gdbarch, func_addr, regcache, bp_addr,
+					    nargs, args, sp, struct_return,
+					    struct_addr, 0);
+}
+
+CORE_ADDR
+ppc64_sysv_abi_broken_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				       struct regcache *regcache, CORE_ADDR bp_addr,
+				       int nargs, struct value **args, CORE_ADDR sp,
+				       int struct_return, CORE_ADDR struct_addr)
+{
+  return do_ppc64_sysv_abi_push_dummy_call (gdbarch, func_addr, regcache, bp_addr,
+					    nargs, args, sp, struct_return,
+					    struct_addr, 1);
+}
+ 
Index: ppc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/ppc-tdep.h,v
retrieving revision 1.18
diff -u -r1.18 ppc-tdep.h
--- ppc-tdep.h	14 Sep 2003 02:04:44 -0000	1.18
+++ ppc-tdep.h	21 Sep 2003 23:31:14 -0000
@@ -42,6 +42,20 @@
 					struct value **args, CORE_ADDR sp,
 					int struct_return,
 					CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+					  CORE_ADDR func_addr,
+					  struct regcache *regcache,
+					  CORE_ADDR bp_addr, int nargs,
+					  struct value **args, CORE_ADDR sp,
+					  int struct_return,
+					  CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_broken_push_dummy_call (struct gdbarch *gdbarch,
+						 CORE_ADDR func_addr,
+						 struct regcache *regcache,
+						 CORE_ADDR bp_addr, int nargs,
+						 struct value **args, CORE_ADDR sp,
+						 int struct_return,
+						 CORE_ADDR struct_addr);
 int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
 struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
 void ppc_linux_supply_gregset (char *buf);
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.160
diff -u -r1.160 rs6000-tdep.c
--- rs6000-tdep.c	16 Sep 2003 23:33:17 -0000	1.160
+++ rs6000-tdep.c	21 Sep 2003 23:31:15 -0000
@@ -2949,6 +2949,8 @@
      revisited.  */
   if (sysv_abi && wordsize == 4)
     set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call);
+  else if (sysv_abi && wordsize == 8)
+    set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call);
   else
     set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-09-21 23:38 [rfa:ppc64] Fix 64-bit PPC ELF function calls Andrew Cagney
@ 2003-09-22 17:59 ` Andrew Cagney
  2003-10-03 20:48   ` Andrew Cagney
  2003-10-03 21:22   ` Kevin Buettner
  0 siblings, 2 replies; 9+ messages in thread
From: Andrew Cagney @ 2003-09-22 17:59 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 877 bytes --]

> Hello,
> 
> This patch implements a 4-bit PPC ELF specific push_dummy_call method. It then adds a work-around (*_broken_push_dummy_call) for what would appear to be GCC bugs.  This fixes ~200 failures (give or take the 3 fixed by the workaround).

I've attached a simplified revision.

Since the two potential places (left/right register ends) for storing 
struct parameters didn't overlap, modified the code so that it stored 
the value at both ends ...

> Ok to commit?
> 
> Andrew
> 
> PS: The apparent bugs are:
> 
> - small odd structs get passed in memory instead of a register (ref structs.exp:Fun3).
> - small even structs get passed right, instead of left, aligned in the register (ref structs.exp:Fun[12]).
> 
> PS: Backtraces are a bit sick.
> 
> PPS: Oh, note the "hack" to find the TOC from the function's entry point address.  Without it malloc() fails.
> 
> 


[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 11072 bytes --]

2003-09-21  Andrew Cagney  <cagney@redhat.com>

	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
	* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): New function.
	(ppc64_sysv_abi_broken_push_dummy_call): New function.
	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
	(ppc64_sysv_abi_broken_push_dummy_call): Declare.

Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.12
diff -u -r1.12 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	19 Sep 2003 16:22:39 -0000	1.12
+++ ppc-sysv-tdep.c	22 Sep 2003 17:57:05 -0000
@@ -325,3 +325,241 @@
 
   return (TYPE_LENGTH (value_type) > 8);
 }   
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc 64 bit SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic. */
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				struct regcache *regcache, CORE_ADDR bp_addr,
+				int nargs, struct value **args, CORE_ADDR sp,
+				int struct_return, CORE_ADDR struct_addr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* By this stage in the proceedings, SP has been decremented by "red
+     zone size" + "struct return size".  Fetch the stack-pointer from
+     before this and use that as the BACK_CHAIN.  */
+  const CORE_ADDR back_chain = read_sp ();
+  /* The address of the top of the parameter save region (typically
+     points at the local variable region).  On entry, the SP is
+     pointing at this.  */
+  const CORE_ADDR param_top = sp;
+  /* Address, on the stack, of the next general (integer, struct,
+     float, ...) parameter.  */
+  CORE_ADDR gparam = 0;
+  /* Address, on the stack, of the next vector.  */
+  CORE_ADDR vparam = 0;
+  /* First (computation) or second (write) pass over the parameter
+     list.  */
+  int write_pass;
+
+  /* Go through the argument list twice.
+
+     Pass 1: Figure out how much stack space is required for arguments
+     and pushed values.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
+
+  for (write_pass = 0; write_pass < 2; write_pass++)
+    {
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-vector (but possibly
+         float) arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+
+      /* If the function is returning a `struct', then there is an
+	 extra hidden parameter (which will be passed in r3)
+	 containing the address of that struct..  In that case we
+	 should advance one word and start from r4 register to copy
+	 parameters.  This also consumes one parameter space slot.  */
+      if (struct_return)
+	{
+	  if (write_pass)
+	    regcache_cooked_write_signed (regcache,
+					  tdep->ppc_gp0_regnum + greg,
+					  struct_addr);
+	  greg++;
+	  gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+	}
+
+      for (argno = 0; argno < nargs; argno++)
+	{
+	  struct value *arg = args[argno];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  char *val = VALUE_CONTENTS (arg);
+	  /* Floats and Doubles go in f1 .. f13.  They also consume a
+             left aligned GREG,, and can end up in memory.  */
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT
+	      && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  if (ppc_floating_point_unit_p (current_gdbarch)
+		      && freg <= 13)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      struct type *regtype = register_type (gdbarch,
+							    FP0_REGNUM);
+		      convert_typed_floating (val, type, regval, regtype);
+		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
+					     regval);
+		    }
+		  if (greg <= 10)
+		    {
+		      /* It goes into the register, left aligned (as
+                         far as I can tell).  */
+		      char regval[MAX_REGISTER_SIZE];
+		      memset (regval, 0, sizeof regval);
+		      memcpy (regval, val, TYPE_LENGTH (type));
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     regval);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      /* Always consume parameter stack space.  */
+	      freg++;
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+		   && tdep->ppc_vr0_regnum >= 0)
+	    {
+	      /* Vectors go in the vector registers v2 .. v13, or when
+                 that runs out, a vector annex which goes after all
+                 the registers.  NOTE: cagney/2003-09-21: This is a
+                 guess based on the PowerOpen Altivec ABI.  */
+	      if (vreg <= 13)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_vr0_regnum + vreg, val);
+		  vreg++;
+		}
+	      else
+		{
+		  if (write_pass)
+		    write_memory (vparam, val, TYPE_LENGTH (type));
+		  vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+		}
+	    }
+	  /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+             They can also end up in memory.  */
+	  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+		    || TYPE_CODE (type) == TYPE_CODE_ENUM)
+		   && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  /* Sign extend the value, then store it unsigned.  */
+		  ULONGEST word = unpack_long (type, val);
+		  if (greg <= 10)
+		    regcache_cooked_write_unsigned (regcache,
+						    tdep->ppc_gp0_regnum + greg,
+						    word);
+		  write_memory_unsigned_integer (gparam, tdep->wordsize, word);
+		}
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else
+	    {
+	      int byte;
+	      for (byte = 0; byte < TYPE_LENGTH (type); byte += tdep->wordsize)
+		{
+		  if (write_pass && greg <= 10)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      int len = TYPE_LENGTH (type) - byte;
+		      if (len > tdep->wordsize)
+			len = tdep->wordsize;
+		      /* WARNING: cagney/2003-09-21: As best I can
+			 tell, the ABI specifies that the value should
+			 be left aligned.  Unfortunatly, GCC doesn't
+			 do this - it instead right aligns even sized
+			 values and puts odd sized values on the
+			 stack.  Work around that by putting both a
+			 left and right aligned value into the
+			 register (hopefully no one notices :-^).
+			 Arrrgh!  */
+		      memset (regval, 0, sizeof regval);
+		      /* Left aligned.  */
+		      memcpy (regval, val + byte, len);
+		      /* Right aligned (but only if even).  */
+		      if (len == 1 || len == 2 || len == 4)
+			memcpy (regval + tdep->wordsize - len,
+				val + byte, len);
+		    }
+		  greg++;
+		}
+	      if (write_pass)
+		/* WARNING: cagney/2003-09-21: Strictly speaking, this
+                   isn't necessary, unfortunatly, GCC appears to get
+                   struct parameter passing wrong putting odd sized
+                   structs in memory instead of a register.  Work
+                   around this by always writing the value to memory.
+                   Fortunatly, doing this simplifies the cost.  */
+		write_memory (gparam, val, TYPE_LENGTH (type));
+	      /* Always consume parameter stack space.  */
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	}
+
+      /* Compute the actual stack space requirements.  48 is lifted
+         direct from the ABI, it is ment to hold holds things like the
+         LR and CR.  */
+      if (!write_pass)
+	{
+	  vparam = align_down (param_top - vparam, 16);
+	  gparam = align_down (vparam - gparam, 16);
+	  sp = align_down (gparam - 48, 16);
+	}
+    }
+
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+  /* Point the inferior function call's return address at the dummy's
+     breakpoint.  */
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+  /* Find a value for the TOC register.  Every symbol should have both
+     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
+     F's descriptor, while ".FN" points at the entry point (which
+     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
+     FN's descriptor address.  */
+  {
+    /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+       have the name ".FN").  */
+    struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+    if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+      {
+	/* Now find the corresponding "FN" (dropping ".") minimal
+           symbol's address.  */
+	struct minimal_symbol *fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, NULL);
+	if (fn != NULL)
+	  {
+	    /* Got the address of that descriptor.  The TOC is the
+               second double word.  */
+	    CORE_ADDR toc = read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) + tdep->wordsize, tdep->wordsize);
+	    regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 2, toc);
+	  }
+      }
+  }
+
+  return sp;
+}
Index: ppc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/ppc-tdep.h,v
retrieving revision 1.18
diff -u -r1.18 ppc-tdep.h
--- ppc-tdep.h	14 Sep 2003 02:04:44 -0000	1.18
+++ ppc-tdep.h	22 Sep 2003 17:57:05 -0000
@@ -42,6 +42,13 @@
 					struct value **args, CORE_ADDR sp,
 					int struct_return,
 					CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+					  CORE_ADDR func_addr,
+					  struct regcache *regcache,
+					  CORE_ADDR bp_addr, int nargs,
+					  struct value **args, CORE_ADDR sp,
+					  int struct_return,
+					  CORE_ADDR struct_addr);
 int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
 struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
 void ppc_linux_supply_gregset (char *buf);
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.161
diff -u -r1.161 rs6000-tdep.c
--- rs6000-tdep.c	17 Sep 2003 14:24:30 -0000	1.161
+++ rs6000-tdep.c	22 Sep 2003 17:57:05 -0000
@@ -2949,6 +2949,8 @@
      revisited.  */
   if (sysv_abi && wordsize == 4)
     set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call);
+  else if (sysv_abi && wordsize == 8)
+    set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call);
   else
     set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-09-22 17:59 ` Andrew Cagney
@ 2003-10-03 20:48   ` Andrew Cagney
  2003-10-03 21:22   ` Kevin Buettner
  1 sibling, 0 replies; 9+ messages in thread
From: Andrew Cagney @ 2003-10-03 20:48 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 8 bytes --]

Kevin?


[-- Attachment #2: mailbox-message://ac131313@movemail/fsf/gdb/patches#9349229 --]
[-- Type: message/rfc822, Size: 15118 bytes --]

[-- Attachment #2.1.1: Type: text/plain, Size: 877 bytes --]

> Hello,
> 
> This patch implements a 4-bit PPC ELF specific push_dummy_call method. It then adds a work-around (*_broken_push_dummy_call) for what would appear to be GCC bugs.  This fixes ~200 failures (give or take the 3 fixed by the workaround).

I've attached a simplified revision.

Since the two potential places (left/right register ends) for storing 
struct parameters didn't overlap, modified the code so that it stored 
the value at both ends ...

> Ok to commit?
> 
> Andrew
> 
> PS: The apparent bugs are:
> 
> - small odd structs get passed in memory instead of a register (ref structs.exp:Fun3).
> - small even structs get passed right, instead of left, aligned in the register (ref structs.exp:Fun[12]).
> 
> PS: Backtraces are a bit sick.
> 
> PPS: Oh, note the "hack" to find the TOC from the function's entry point address.  Without it malloc() fails.
> 
> 


[-- Attachment #2.1.2: diffs --]
[-- Type: text/plain, Size: 11072 bytes --]

2003-09-21  Andrew Cagney  <cagney@redhat.com>

	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
	* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): New function.
	(ppc64_sysv_abi_broken_push_dummy_call): New function.
	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
	(ppc64_sysv_abi_broken_push_dummy_call): Declare.

Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.12
diff -u -r1.12 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	19 Sep 2003 16:22:39 -0000	1.12
+++ ppc-sysv-tdep.c	22 Sep 2003 17:57:05 -0000
@@ -325,3 +325,241 @@
 
   return (TYPE_LENGTH (value_type) > 8);
 }   
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc 64 bit SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic. */
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				struct regcache *regcache, CORE_ADDR bp_addr,
+				int nargs, struct value **args, CORE_ADDR sp,
+				int struct_return, CORE_ADDR struct_addr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* By this stage in the proceedings, SP has been decremented by "red
+     zone size" + "struct return size".  Fetch the stack-pointer from
+     before this and use that as the BACK_CHAIN.  */
+  const CORE_ADDR back_chain = read_sp ();
+  /* The address of the top of the parameter save region (typically
+     points at the local variable region).  On entry, the SP is
+     pointing at this.  */
+  const CORE_ADDR param_top = sp;
+  /* Address, on the stack, of the next general (integer, struct,
+     float, ...) parameter.  */
+  CORE_ADDR gparam = 0;
+  /* Address, on the stack, of the next vector.  */
+  CORE_ADDR vparam = 0;
+  /* First (computation) or second (write) pass over the parameter
+     list.  */
+  int write_pass;
+
+  /* Go through the argument list twice.
+
+     Pass 1: Figure out how much stack space is required for arguments
+     and pushed values.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
+
+  for (write_pass = 0; write_pass < 2; write_pass++)
+    {
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-vector (but possibly
+         float) arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+
+      /* If the function is returning a `struct', then there is an
+	 extra hidden parameter (which will be passed in r3)
+	 containing the address of that struct..  In that case we
+	 should advance one word and start from r4 register to copy
+	 parameters.  This also consumes one parameter space slot.  */
+      if (struct_return)
+	{
+	  if (write_pass)
+	    regcache_cooked_write_signed (regcache,
+					  tdep->ppc_gp0_regnum + greg,
+					  struct_addr);
+	  greg++;
+	  gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+	}
+
+      for (argno = 0; argno < nargs; argno++)
+	{
+	  struct value *arg = args[argno];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  char *val = VALUE_CONTENTS (arg);
+	  /* Floats and Doubles go in f1 .. f13.  They also consume a
+             left aligned GREG,, and can end up in memory.  */
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT
+	      && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  if (ppc_floating_point_unit_p (current_gdbarch)
+		      && freg <= 13)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      struct type *regtype = register_type (gdbarch,
+							    FP0_REGNUM);
+		      convert_typed_floating (val, type, regval, regtype);
+		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
+					     regval);
+		    }
+		  if (greg <= 10)
+		    {
+		      /* It goes into the register, left aligned (as
+                         far as I can tell).  */
+		      char regval[MAX_REGISTER_SIZE];
+		      memset (regval, 0, sizeof regval);
+		      memcpy (regval, val, TYPE_LENGTH (type));
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     regval);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      /* Always consume parameter stack space.  */
+	      freg++;
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+		   && tdep->ppc_vr0_regnum >= 0)
+	    {
+	      /* Vectors go in the vector registers v2 .. v13, or when
+                 that runs out, a vector annex which goes after all
+                 the registers.  NOTE: cagney/2003-09-21: This is a
+                 guess based on the PowerOpen Altivec ABI.  */
+	      if (vreg <= 13)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_vr0_regnum + vreg, val);
+		  vreg++;
+		}
+	      else
+		{
+		  if (write_pass)
+		    write_memory (vparam, val, TYPE_LENGTH (type));
+		  vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+		}
+	    }
+	  /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+             They can also end up in memory.  */
+	  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+		    || TYPE_CODE (type) == TYPE_CODE_ENUM)
+		   && TYPE_LENGTH (type) <= 8)
+	    {
+	      if (write_pass)
+		{
+		  /* Sign extend the value, then store it unsigned.  */
+		  ULONGEST word = unpack_long (type, val);
+		  if (greg <= 10)
+		    regcache_cooked_write_unsigned (regcache,
+						    tdep->ppc_gp0_regnum + greg,
+						    word);
+		  write_memory_unsigned_integer (gparam, tdep->wordsize, word);
+		}
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else
+	    {
+	      int byte;
+	      for (byte = 0; byte < TYPE_LENGTH (type); byte += tdep->wordsize)
+		{
+		  if (write_pass && greg <= 10)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      int len = TYPE_LENGTH (type) - byte;
+		      if (len > tdep->wordsize)
+			len = tdep->wordsize;
+		      /* WARNING: cagney/2003-09-21: As best I can
+			 tell, the ABI specifies that the value should
+			 be left aligned.  Unfortunatly, GCC doesn't
+			 do this - it instead right aligns even sized
+			 values and puts odd sized values on the
+			 stack.  Work around that by putting both a
+			 left and right aligned value into the
+			 register (hopefully no one notices :-^).
+			 Arrrgh!  */
+		      memset (regval, 0, sizeof regval);
+		      /* Left aligned.  */
+		      memcpy (regval, val + byte, len);
+		      /* Right aligned (but only if even).  */
+		      if (len == 1 || len == 2 || len == 4)
+			memcpy (regval + tdep->wordsize - len,
+				val + byte, len);
+		    }
+		  greg++;
+		}
+	      if (write_pass)
+		/* WARNING: cagney/2003-09-21: Strictly speaking, this
+                   isn't necessary, unfortunatly, GCC appears to get
+                   struct parameter passing wrong putting odd sized
+                   structs in memory instead of a register.  Work
+                   around this by always writing the value to memory.
+                   Fortunatly, doing this simplifies the cost.  */
+		write_memory (gparam, val, TYPE_LENGTH (type));
+	      /* Always consume parameter stack space.  */
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	}
+
+      /* Compute the actual stack space requirements.  48 is lifted
+         direct from the ABI, it is ment to hold holds things like the
+         LR and CR.  */
+      if (!write_pass)
+	{
+	  vparam = align_down (param_top - vparam, 16);
+	  gparam = align_down (vparam - gparam, 16);
+	  sp = align_down (gparam - 48, 16);
+	}
+    }
+
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+  /* Point the inferior function call's return address at the dummy's
+     breakpoint.  */
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+  /* Find a value for the TOC register.  Every symbol should have both
+     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
+     F's descriptor, while ".FN" points at the entry point (which
+     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
+     FN's descriptor address.  */
+  {
+    /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+       have the name ".FN").  */
+    struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+    if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+      {
+	/* Now find the corresponding "FN" (dropping ".") minimal
+           symbol's address.  */
+	struct minimal_symbol *fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, NULL);
+	if (fn != NULL)
+	  {
+	    /* Got the address of that descriptor.  The TOC is the
+               second double word.  */
+	    CORE_ADDR toc = read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) + tdep->wordsize, tdep->wordsize);
+	    regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 2, toc);
+	  }
+      }
+  }
+
+  return sp;
+}
Index: ppc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/ppc-tdep.h,v
retrieving revision 1.18
diff -u -r1.18 ppc-tdep.h
--- ppc-tdep.h	14 Sep 2003 02:04:44 -0000	1.18
+++ ppc-tdep.h	22 Sep 2003 17:57:05 -0000
@@ -42,6 +42,13 @@
 					struct value **args, CORE_ADDR sp,
 					int struct_return,
 					CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+					  CORE_ADDR func_addr,
+					  struct regcache *regcache,
+					  CORE_ADDR bp_addr, int nargs,
+					  struct value **args, CORE_ADDR sp,
+					  int struct_return,
+					  CORE_ADDR struct_addr);
 int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
 struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
 void ppc_linux_supply_gregset (char *buf);
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.161
diff -u -r1.161 rs6000-tdep.c
--- rs6000-tdep.c	17 Sep 2003 14:24:30 -0000	1.161
+++ rs6000-tdep.c	22 Sep 2003 17:57:05 -0000
@@ -2949,6 +2949,8 @@
      revisited.  */
   if (sysv_abi && wordsize == 4)
     set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call);
+  else if (sysv_abi && wordsize == 8)
+    set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call);
   else
     set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-09-22 17:59 ` Andrew Cagney
  2003-10-03 20:48   ` Andrew Cagney
@ 2003-10-03 21:22   ` Kevin Buettner
  2003-10-06 22:19     ` Andrew Cagney
  1 sibling, 1 reply; 9+ messages in thread
From: Kevin Buettner @ 2003-10-03 21:22 UTC (permalink / raw)
  To: Andrew Cagney, gdb-patches

Sorry for not replying sooner.  I thought I had replied to this already...

On Sep 22,  1:59pm, Andrew Cagney wrote:

> > PS: The apparent bugs are:
> > 
> > - small odd structs get passed in memory instead of a register
> >   (ref structs.exp:Fun3).
> > - small even structs get passed right, instead of left, aligned in
> >   the register (ref structs.exp:Fun[12]).

These are all GCC bugs, right?  And, if they get fixed in GCC, then GDB
will be broken?

> > PS: Backtraces are a bit sick.

In what way?

> > PPS:  Oh, note the "hack" to find the TOC from the function's
> >       entry point address.  Without it malloc() fails.

Calls to other library functions would fail too.

Is the TOC symbol name vs entry point name (i.e, FN vs..FN) convention
mandated by the ABI, or is this something that's Linux specific?

I notice some 80+ character lines in ppc64_sysv_abi_push_dummy_call().
Could you adjust these so that they're 80 characters or less?

Also, a minor nit: in the comment...

  /* Find a value for the TOC register.  Every symbol should have both
     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
     F's descriptor, while ".FN" points at the entry point (which
     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
     FN's descriptor address.  */

...at the beginning of the third line down, shouldn't that be:

     FN's descriptor, [...]

If not, what does `F' refer to?

Kevin


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-10-03 21:22   ` Kevin Buettner
@ 2003-10-06 22:19     ` Andrew Cagney
  2003-10-09  5:02       ` Kevin Buettner
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Cagney @ 2003-10-06 22:19 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

> Sorry for not replying sooner.  I thought I had replied to this already...
> 
> On Sep 22,  1:59pm, Andrew Cagney wrote:
> 
> 
>> > PS: The apparent bugs are:
>> > 
>> > - small odd structs get passed in memory instead of a register
>> >   (ref structs.exp:Fun3).
>> > - small even structs get passed right, instead of left, aligned in
>> >   the register (ref structs.exp:Fun[12]).
> 
> 
> These are all GCC bugs, right?  And, if they get fixed in GCC, then GDB
> will be broken?

Yes, as far as I know (but you would be wize to cross check my 
interpretation of the ABI).

No.  The patch gets around the problem thus:

+		      /* WARNING: cagney/2003-09-21: As best I can
+			 tell, the ABI specifies that the value should
+			 be left aligned.  Unfortunatly, GCC doesn't
+			 do this - it instead right aligns even sized
+			 values and puts odd sized values on the
+			 stack.  Work around that by putting both a
+			 left and right aligned value into the
+			 register (hopefully no one notices :-^).
+			 Arrrgh!  */

>> > PS: Backtraces are a bit sick.
> 
> 
> In what way?

They don't work.  All the backtrace tests I glanced at failed (and this 
is independant of the current fixes).

>> > PPS:  Oh, note the "hack" to find the TOC from the function's
>> >       entry point address.  Without it malloc() fails.
> 
> 
> Calls to other library functions would fail too.
> 
> Is the TOC symbol name vs entry point name (i.e, FN vs..FN) convention
> mandated by the ABI, or is this something that's Linux specific?

It in the 64-bit ELF ABI.

> I notice some 80+ character lines in ppc64_sysv_abi_push_dummy_call().
> Could you adjust these so that they're 80 characters or less?

I'll run the file through gdb_indent.sh, as a separate commit.

> Also, a minor nit: in the comment...
> 
>   /* Find a value for the TOC register.  Every symbol should have both
>      ".FN" and "FN" in the minimal symbol table.  "FN" points at the
>      F's descriptor, while ".FN" points at the entry point (which
>      matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
>      FN's descriptor address.  */
> 
> ...at the beginning of the third line down, shouldn't that be:
> 
>      FN's descriptor, [...]
> 
> If not, what does `F' refer to?

It's a tipo, thanks.  The term "FN" is used in the ABI.

ok?
Andrew



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-10-06 22:19     ` Andrew Cagney
@ 2003-10-09  5:02       ` Kevin Buettner
  2003-10-10  1:27         ` Andrew Cagney
  0 siblings, 1 reply; 9+ messages in thread
From: Kevin Buettner @ 2003-10-09  5:02 UTC (permalink / raw)
  To: Andrew Cagney, Kevin Buettner; +Cc: gdb-patches

On Oct 6,  6:19pm, Andrew Cagney wrote:

> > I notice some 80+ character lines in ppc64_sysv_abi_push_dummy_call().
> > Could you adjust these so that they're 80 characters or less?
> 
> I'll run the file through gdb_indent.sh, as a separate commit.

I see that you've already done it.  Don't forget to do it again
after you commit your ppc64_sysv_abi_push_dummy_call() changes.

> > Also, a minor nit: in the comment...
> > 
> >   /* Find a value for the TOC register.  Every symbol should have both
> >      ".FN" and "FN" in the minimal symbol table.  "FN" points at the
> >      F's descriptor, while ".FN" points at the entry point (which
> >      matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
> >      FN's descriptor address.  */
> > 
> > ...at the beginning of the third line down, shouldn't that be:
> > 
> >      FN's descriptor, [...]
> > 
> > If not, what does `F' refer to?
> 
> It's a tipo, thanks.  The term "FN" is used in the ABI.

Here's another typo:

+      /* Compute the actual stack space requirements.  48 is lifted
+         direct from the ABI, it is ment to hold holds things like the

s/ment/meant/

And another:

+		/* WARNING: cagney/2003-09-21: Strictly speaking, this
+                   isn't necessary, unfortunatly, GCC appears to get
+                   struct parameter passing wrong putting odd sized
+                   structs in memory instead of a register.  Work
+                   around this by always writing the value to memory.
+                   Fortunatly, doing this simplifies the cost.  */

s/Fortunatly/Fortunately/

> ok?

Not yet.

Please add

  gdb_assert (tdep->wordsize == 8)

somewhere early in ppc64_sysv_abi_push_dummy_call().

I don't mind seeing tdep->wordsize used in the calls to align_up(),
align_down(), etc.  because this makes it easier to reuse this code
(in a copy/paste sense) in the future, but it is a 64-bit ABI and
asserting that the wordsize is 8 bytes at some point makes it easier
to verify that this function is correct without having to do a
non-local analysis to figure out the possible values of
tdep->wordsize.

....

+  /* The address of the top of the parameter save region (typically
+     points at the local variable region).  On entry, the SP is
+     pointing at this.  */
+  const CORE_ADDR param_top = sp;

I find this name confusing.  If I understand the rest of the code
correctly, this actually ends up being the bottom of the parameter
save area - since the stack grows from high to low addresses.  (Of
course, if you draw a picture, it might be topmost in the picture...)

Anyway, in this instance, I think it's advisable to avoid the names
"top" and "bottom" altogether.  Perhaps ``param_end'' is a more
appropriate name?

....

+  /* Address, on the stack, of the next general (integer, struct,
+     float, ...) parameter.  */
+  CORE_ADDR gparam = 0;
+  /* Address, on the stack, of the next vector.  */
+  CORE_ADDR vparam = 0;

These are addresses when write_pass == 1, but merely a running
total of the number of words needed when write_pass == 0.  Calling
them addresses is misleading.

+  /* Go through the argument list twice.
+
+     Pass 1: Figure out how much stack space is required for arguments
+     and pushed values.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */

Perhaps you could explain the dual roles of gparam and vparam in the
above comment?

....

+      if (!write_pass)
+	{
+	  vparam = align_down (param_top - vparam, 16);
+	  gparam = align_down (vparam - gparam, 16);
+	  sp = align_down (gparam - 48, 16);
+	}

The ABI says:

    The parameter save area, which is located at a fixed offset of 48
    bytes from the stack pointer, is reserved in each stack frame for use
    as an argument list.  A minimum of 8 doublewords is always reserved.

I don't see where you've accounted for this 8 doubleword minimum. 
Perhaps revise this to something along the following lines?

       if (!write_pass)
 	{
 	  vparam = align_down (param_top - vparam, 16);
	  if (gparam < 8 * tdep->wordsize)
	    gparam = 8 * tdep->wordsize;
 	  gparam = align_down (vparam - gparam, 16);
 	  sp = align_down (gparam - 48, 16);
 	}

I'm not sure this is right either since that alters the vector save
area.  I don't happen to have a copy of the Altivec ABI though.

....

+		  if (greg <= 10)
+		    {
+		      /* It goes into the register, left aligned (as
+                         far as I can tell).  */

I can't find anything in the ABI to contradict this, but I found it
surprising that floating point arguments would be left aligned.  If
I'm not mistaken (for big endian), this'll mean that the the float
is stored in the most significant half of the register.

Kevin


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-10-09  5:02       ` Kevin Buettner
@ 2003-10-10  1:27         ` Andrew Cagney
  2003-10-10  5:20           ` Kevin Buettner
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Cagney @ 2003-10-10  1:27 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]

> On Oct 6,  6:19pm, Andrew Cagney wrote:
> 
> 
>> > I notice some 80+ character lines in ppc64_sysv_abi_push_dummy_call().
>> > Could you adjust these so that they're 80 characters or less?
> 
>> 
>> I'll run the file through gdb_indent.sh, as a separate commit.
> 
> 
> I see that you've already done it.

Yes, obvious.

> Don't forget to do it again
> after you commit your ppc64_sysv_abi_push_dummy_call() changes.

The attached has already been re-indented.  Otherwize the diff ends up 
containing unnecessary white space changes.

> Here's another typo:
[...]
> s/ment/meant/
[...]
> s/Fortunatly/Fortunately/

Fixed, along with a few others.

> Not yet.
> 
> Please add
> 
>   gdb_assert (tdep->wordsize == 8)
> 
> somewhere early in ppc64_sysv_abi_push_dummy_call().

Added, along with your comments.

> Anyway, in this instance, I think it's advisable to avoid the names
> "top" and "bottom" altogether.  Perhaps ``param_end'' is a more
> appropriate name?

I replaced that variable with vparam_size and gparam_size.

> +  /* Address, on the stack, of the next general (integer, struct,
> +     float, ...) parameter.  */
> +  CORE_ADDR gparam = 0;
> +  /* Address, on the stack, of the next vector.  */
> +  CORE_ADDR vparam = 0;
> 
> These are addresses when write_pass == 1, but merely a running
> total of the number of words needed when write_pass == 0.  Calling
> them addresses is misleading.
> 
> +  /* Go through the argument list twice.
> +
> +     Pass 1: Figure out how much stack space is required for arguments
> +     and pushed values.
> +
> +     Pass 2: Replay the same computation but this time also write the
> +     values out to the target.  */
> 
> Perhaps you could explain the dual roles of gparam and vparam in the
> above comment?

Yes but slightly further down where they are computed.

> +      if (!write_pass)
> +	{
> +	  vparam = align_down (param_top - vparam, 16);
> +	  gparam = align_down (vparam - gparam, 16);
> +	  sp = align_down (gparam - 48, 16);
> +	}
> 
> The ABI says:
> 
>     The parameter save area, which is located at a fixed offset of 48
>     bytes from the stack pointer, is reserved in each stack frame for use
>     as an argument list.  A minimum of 8 doublewords is always reserved.
> 
> I don't see where you've accounted for this 8 doubleword minimum. 
> Perhaps revise this to something along the following lines?

Good point.

>        if (!write_pass)
>  	{
>  	  vparam = align_down (param_top - vparam, 16);
> 	  if (gparam < 8 * tdep->wordsize)
> 	    gparam = 8 * tdep->wordsize;
>  	  gparam = align_down (vparam - gparam, 16);
>  	  sp = align_down (gparam - 48, 16);
>  	}
> 
> I'm not sure this is right either since that alters the vector save
> area.  I don't happen to have a copy of the Altivec ABI though.

Done (but also rearanged).  The vector save area can be zero in size.

> +		  if (greg <= 10)
> +		    {
> +		      /* It goes into the register, left aligned (as
> +                         far as I can tell).  */
> 
> I can't find anything in the ABI to contradict this, but I found it
> surprising that floating point arguments would be left aligned.  If
> I'm not mistaken (for big endian), this'll mean that the the float
> is stored in the most significant half of the register.

It now reads:

		      /* The ABI states "Single precision floating
		         point values are mapped to the first word in
		         a single doubleword" and "... floating point
		         values mapped to the first eight doublewords
		         of the parameter save area are also passed in
		         general registers").

			 This code interprets that to mean: store it,
			 left aligned, in the general register.  */


Andrew

[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 14085 bytes --]

2003-10-09  Andrew Cagney  <cagney@redhat.com>

	* Makefile.in (ppc-sysv-tdep.o): Add $(gdb_assert_h).
	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
	* ppc-sysv-tdep.c: Include "gdb_assert.h".
	(ppc64_sysv_abi_push_dummy_call): New function.
	(ppc64_sysv_abi_broken_push_dummy_call): New function.
	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
	(ppc64_sysv_abi_broken_push_dummy_call): Declare.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.452
diff -u -r1.452 Makefile.in
--- Makefile.in	6 Oct 2003 21:56:40 -0000	1.452
+++ Makefile.in	10 Oct 2003 01:25:03 -0000
@@ -2114,7 +2114,7 @@
 	$(target_h) $(breakpoint_h) $(value_h) $(osabi_h) $(ppc_tdep_h) \
 	$(ppcnbsd_tdep_h) $(nbsd_tdep_h) $(solib_svr4_h)
 ppc-sysv-tdep.o: ppc-sysv-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) \
-	$(regcache_h) $(value_h) $(gdb_string_h) $(ppc_tdep_h)
+	$(regcache_h) $(value_h) $(gdb_string_h) $(gdb_assert_h) $(ppc_tdep_h)
 printcmd.o: printcmd.c $(defs_h) $(gdb_string_h) $(frame_h) $(symtab_h) \
 	$(gdbtypes_h) $(value_h) $(language_h) $(expression_h) $(gdbcore_h) \
 	$(gdbcmd_h) $(target_h) $(breakpoint_h) $(demangle_h) $(valprint_h) \
Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.14
diff -u -r1.14 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	6 Oct 2003 22:23:47 -0000	1.14
+++ ppc-sysv-tdep.c	10 Oct 2003 01:25:03 -0000
@@ -26,7 +26,7 @@
 #include "regcache.h"
 #include "value.h"
 #include "gdb_string.h"
-
+#include "gdb_assert.h"
 #include "ppc-tdep.h"
 
 /* Pass the arguments in either registers, or in the stack. Using the
@@ -315,6 +315,295 @@
     return 0;
 
   return (TYPE_LENGTH (value_type) > 8);
+}
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc 64 bit SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic. */
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+				struct regcache *regcache, CORE_ADDR bp_addr,
+				int nargs, struct value **args, CORE_ADDR sp,
+				int struct_return, CORE_ADDR struct_addr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* By this stage in the proceedings, SP has been decremented by "red
+     zone size" + "struct return size".  Fetch the stack-pointer from
+     before this and use that as the BACK_CHAIN.  */
+  const CORE_ADDR back_chain = read_sp ();
+  /* See for-loop comment below.  */
+  int write_pass;
+  /* Size of the Altivec's vector parameter region, the final value is
+     computed in the for-loop below.  */
+  LONGEST vparam_size = 0;
+  /* Size of the general parameter region, the final value is computed
+     in the for-loop below.  */
+  LONGEST gparam_size = 0;
+  /* Kevin writes ... I don't mind seeing tdep->wordsize used in the
+     calls to align_up(), align_down(), etc.  because this makes it
+     easier to reuse this code (in a copy/paste sense) in the future,
+     but it is a 64-bit ABI and asserting that the wordsize is 8 bytes
+     at some point makes it easier to verify that this function is
+     correct without having to do a non-local analysis to figure out
+     the possible values of tdep->wordsize.  */
+  gdb_assert (tdep->wordsize == 8);
+
+  /* Go through the argument list twice.
+
+     Pass 1: Compute the function call's stack space and register
+     requirements.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
+
+  for (write_pass = 0; write_pass < 2; write_pass++)
+    {
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-vector (but possibly
+         float) arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+      /* The address, at which the next general purpose parameter
+         (integer, struct, float, ...) should be saved.  */
+      CORE_ADDR gparam;
+      /* Address, at which the next Altivec vector parameter should be
+         saved.  */
+      CORE_ADDR vparam;
+
+      if (!write_pass)
+	{
+	  /* During the first pass, GPARAM and VPARAM are more like
+	     offsets (start address zero) than addresses.  That way
+	     the accumulate the total stack space each region
+	     requires.  */
+	  gparam = 0;
+	  vparam = 0;
+	}
+      else
+	{
+	  /* Decrement the stack pointer making space for the Altivec
+	     and general on-stack parameters.  Set vparam and gparam
+	     to their corresponding regions.  */
+	  vparam = align_down (sp - vparam_size, 16);
+	  gparam = align_down (vparam - gparam_size, 16);
+	  /* Add in space for the TOC, link editor double word,
+	     compiler double word, LR save area, CR save area.  */
+	  sp = align_down (gparam - 48, 16);
+	}
+
+      /* If the function is returning a `struct', then there is an
+         extra hidden parameter (which will be passed in r3)
+         containing the address of that struct..  In that case we
+         should advance one word and start from r4 register to copy
+         parameters.  This also consumes one on-stack parameter slot.  */
+      if (struct_return)
+	{
+	  if (write_pass)
+	    regcache_cooked_write_signed (regcache,
+					  tdep->ppc_gp0_regnum + greg,
+					  struct_addr);
+	  greg++;
+	  gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+	}
+
+      for (argno = 0; argno < nargs; argno++)
+	{
+	  struct value *arg = args[argno];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  char *val = VALUE_CONTENTS (arg);
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
+	    {
+	      /* Floats and Doubles go in f1 .. f13.  They also
+	         consume a left aligned GREG,, and can end up in
+	         memory.  */
+	      if (write_pass)
+		{
+		  if (ppc_floating_point_unit_p (current_gdbarch)
+		      && freg <= 13)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      struct type *regtype = register_type (gdbarch,
+							    FP0_REGNUM);
+		      convert_typed_floating (val, type, regval, regtype);
+		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
+					     regval);
+		    }
+		  if (greg <= 10)
+		    {
+		      /* The ABI states "Single precision floating
+		         point values are mapped to the first word in
+		         a single doubleword" and "... floating point
+		         values mapped to the first eight doublewords
+		         of the parameter save area are also passed in
+		         general registers").
+
+		         This code interprets that to mean: store it,
+		         left aligned, in the general register.  */
+		      char regval[MAX_REGISTER_SIZE];
+		      memset (regval, 0, sizeof regval);
+		      memcpy (regval, val, TYPE_LENGTH (type));
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     regval);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      /* Always consume parameter stack space.  */
+	      freg++;
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+		   && tdep->ppc_vr0_regnum >= 0)
+	    {
+	      /* In the Altivec ABI, vectors go in the vector
+	         registers v2 .. v13, or when that runs out, a vector
+	         annex which goes above all the normal parameters.
+	         NOTE: cagney/2003-09-21: This is a guess based on the
+	         PowerOpen Altivec ABI.  */
+	      if (vreg <= 13)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_vr0_regnum + vreg, val);
+		  vreg++;
+		}
+	      else
+		{
+		  if (write_pass)
+		    write_memory (vparam, val, TYPE_LENGTH (type));
+		  vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+		}
+	    }
+	  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+		    || TYPE_CODE (type) == TYPE_CODE_ENUM)
+		   && TYPE_LENGTH (type) <= 8)
+	    {
+	      /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+	         They can also end up in memory.  */
+	      if (write_pass)
+		{
+		  /* Sign extend the value, then store it unsigned.  */
+		  ULONGEST word = unpack_long (type, val);
+		  if (greg <= 10)
+		    regcache_cooked_write_unsigned (regcache,
+						    tdep->ppc_gp0_regnum +
+						    greg, word);
+		  write_memory_unsigned_integer (gparam, tdep->wordsize,
+						 word);
+		}
+	      greg++;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	  else
+	    {
+	      int byte;
+	      for (byte = 0; byte < TYPE_LENGTH (type);
+		   byte += tdep->wordsize)
+		{
+		  if (write_pass && greg <= 10)
+		    {
+		      char regval[MAX_REGISTER_SIZE];
+		      int len = TYPE_LENGTH (type) - byte;
+		      if (len > tdep->wordsize)
+			len = tdep->wordsize;
+		      memset (regval, 0, sizeof regval);
+		      /* WARNING: cagney/2003-09-21: As best I can
+		         tell, the ABI specifies that the value should
+		         be left aligned.  Unfortunately, GCC doesn't
+		         do this - it instead right aligns even sized
+		         values and puts odd sized values on the
+		         stack.  Work around that by putting both a
+		         left and right aligned value into the
+		         register (hopefully no one notices :-^).
+		         Arrrgh!  */
+		      /* Left aligned (8 byte values such as pointers
+		         fill the buffer).  */
+		      memcpy (regval, val + byte, len);
+		      /* Right aligned (but only if even).  */
+		      if (len == 1 || len == 2 || len == 4)
+			memcpy (regval + tdep->wordsize - len,
+				val + byte, len);
+		      regcache_cooked_write (regcache, greg, regval);
+		    }
+		  greg++;
+		}
+	      if (write_pass)
+		/* WARNING: cagney/2003-09-21: Strictly speaking, this
+		   isn't necessary, unfortunately, GCC appears to get
+		   "struct convention" parameter passing wrong putting
+		   odd sized structures in memory instead of in a
+		   register.  Work around this by always writing the
+		   value to memory.  Fortunately, doing this
+		   simplifies the code.  */
+		write_memory (gparam, val, TYPE_LENGTH (type));
+	      /* Always consume parameter stack space.  */
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
+	}
+
+      if (!write_pass)
+	{
+	  /* Save the true region sizes ready for the second pass.  */
+	  vparam_size = vparam;
+	  /* Make certain that the general parameter save area is at
+	     least the minimum 8 registers (or doublewords) in size.  */
+	  if (greg < 8)
+	    gparam_size = 8 * tdep->wordsize;
+	  else
+	    gparam_size = gparam;
+	}
+    }
+
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+  /* Point the inferior function call's return address at the dummy's
+     breakpoint.  */
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+  /* Find a value for the TOC register.  Every symbol should have both
+     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
+     FN's descriptor, while ".FN" points at the entry point (which
+     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
+     FN's descriptor address.  */
+  {
+    /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+       have the name ".FN").  */
+    struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+    if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+      {
+	/* Now find the corresponding "FN" (dropping ".") minimal
+	   symbol's address.  */
+	struct minimal_symbol *fn =
+	  lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
+				 NULL);
+	if (fn != NULL)
+	  {
+	    /* Got the address of that descriptor.  The TOC is the
+	       second double word.  */
+	    CORE_ADDR toc =
+	      read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) +
+					    tdep->wordsize, tdep->wordsize);
+	    regcache_cooked_write_unsigned (regcache,
+					    tdep->ppc_gp0_regnum + 2, toc);
+	  }
+      }
+  }
+
+  return sp;
 }
 
 
Index: ppc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/ppc-tdep.h,v
retrieving revision 1.19
diff -u -r1.19 ppc-tdep.h
--- ppc-tdep.h	3 Oct 2003 21:11:39 -0000	1.19
+++ ppc-tdep.h	10 Oct 2003 01:25:03 -0000
@@ -42,6 +42,13 @@
 					struct value **args, CORE_ADDR sp,
 					int struct_return,
 					CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+					  CORE_ADDR func_addr,
+					  struct regcache *regcache,
+					  CORE_ADDR bp_addr, int nargs,
+					  struct value **args, CORE_ADDR sp,
+					  int struct_return,
+					  CORE_ADDR struct_addr);
 int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
 struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
 void ppc_linux_supply_gregset (char *buf);
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.166
diff -u -r1.166 rs6000-tdep.c
--- rs6000-tdep.c	3 Oct 2003 21:11:39 -0000	1.166
+++ rs6000-tdep.c	10 Oct 2003 01:25:04 -0000
@@ -2959,6 +2959,8 @@
      revisited.  */
   if (sysv_abi && wordsize == 4)
     set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call);
+  else if (sysv_abi && wordsize == 8)
+    set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call);
   else
     set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-10-10  1:27         ` Andrew Cagney
@ 2003-10-10  5:20           ` Kevin Buettner
  2003-10-10 18:30             ` Andrew Cagney
  0 siblings, 1 reply; 9+ messages in thread
From: Kevin Buettner @ 2003-10-10  5:20 UTC (permalink / raw)
  To: Andrew Cagney, Kevin Buettner; +Cc: gdb-patches

On Oct 9,  9:27pm, Andrew Cagney wrote:

>	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
>	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
>	* ppc-sysv-tdep.c: Include "gdb_assert.h".
>	(ppc64_sysv_abi_push_dummy_call): New function.
>	(ppc64_sysv_abi_broken_push_dummy_call): New function.
>	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
>	(ppc64_sysv_abi_broken_push_dummy_call): Declare.

Okay.  Thanks for reworking it.

Kevin


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [rfa:ppc64] Fix 64-bit PPC ELF function calls
  2003-10-10  5:20           ` Kevin Buettner
@ 2003-10-10 18:30             ` Andrew Cagney
  0 siblings, 0 replies; 9+ messages in thread
From: Andrew Cagney @ 2003-10-10 18:30 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

> On Oct 9,  9:27pm, Andrew Cagney wrote:
> 
> 
>>	* rs6000-tdep.c (rs6000_gdbarch_init): When 64 bit SysV ABI, set
>>	push_dummy_call to ppc64_sysv_abi_push_dummy_call.
>>	* ppc-sysv-tdep.c: Include "gdb_assert.h".
>>	(ppc64_sysv_abi_push_dummy_call): New function.
>>	(ppc64_sysv_abi_broken_push_dummy_call): New function.
>>	* ppc-tdep.h (ppc64_sysv_abi_push_dummy_call): Declare.
>>	(ppc64_sysv_abi_broken_push_dummy_call): Declare.
> 
> 
> Okay.

I've checked this in.

Andrew



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2003-10-10 18:30 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-21 23:38 [rfa:ppc64] Fix 64-bit PPC ELF function calls Andrew Cagney
2003-09-22 17:59 ` Andrew Cagney
2003-10-03 20:48   ` Andrew Cagney
2003-10-03 21:22   ` Kevin Buettner
2003-10-06 22:19     ` Andrew Cagney
2003-10-09  5:02       ` Kevin Buettner
2003-10-10  1:27         ` Andrew Cagney
2003-10-10  5:20           ` Kevin Buettner
2003-10-10 18:30             ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox