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]

[RFA] Fix float argument passing in inferior function calls for ppc64


Hi,

The 64-bit PowerPC ELF ABI version 1.9 says that "single precision
floating point values are mapped to the second word in a single
doubleword". The ppc64_sysv_abi_push_dummy_call function in
ppc-sysv-tdep.c, however, implements version 1.7 of the ABI which says
that they should go in the first doubleword.

Because of this, if you are calling a function with many arguments and
some need to be passed on the stack, GDB will get it wrong for 32-bit
floats. This is why in Linux/ppc64 GDB fails the "Call function with
many float arguments" test posted here:

http://sourceware.org/ml/gdb-patches/2008-01/msg00291.html

This patch fixes the test. It makes GDB pass 32-bit floats in the second
word when passing them in the stack as stated in the current ABI.

I didn't touch the code which writes the float to a general register in
the first word because I'm not sure how to test it. It is probably
related to soft-float, I guess.

Tested on Linux/ppc64 with no regressions. I believe this will also fix
other operating systems supported by GDB on ppc64 since they use the
same push_dummy_call implementation (assuming they also follow the
current SysV ABI), but I don't have the means to test them either.

Maybe someone could test the patch and the testcase in *BSD? Luis' patch
which has the testcases would also need this testing.
-- 
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center
2008-01-14  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Use 64-bit slot
	to pass 32-bit float argument when writing it on the stack. Map it
	to second word in the doubleword.

diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
index 9238f26..e993d1b 100644
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -829,6 +829,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 	  struct value *arg = args[argno];
 	  struct type *type = check_typedef (value_type (arg));
 	  const bfd_byte *val = value_contents (arg);
+
 	  if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
 	    {
 	      /* Floats and Doubles go in f1 .. f13.  They also
@@ -836,11 +837,14 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 	         memory.  */
 	      if (write_pass)
 		{
+		  gdb_byte regval[MAX_REGISTER_SIZE];
+		  const gdb_byte *p;
+
 		  if (freg <= 13)
 		    {
-		      gdb_byte regval[MAX_REGISTER_SIZE];
 		      struct type *regtype
                         = register_type (gdbarch, tdep->ppc_fp0_regnum);
+
 		      convert_typed_floating (val, type, regval, regtype);
 		      regcache_cooked_write (regcache,
                                              tdep->ppc_fp0_regnum + freg,
@@ -856,20 +860,35 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 		         general registers").
 
 		         This code interprets that to mean: store it,
-		         left aligned, in the general register.  */
-		      gdb_byte regval[MAX_REGISTER_SIZE];
+		         left aligned, in the general register.
+
+		         NOTE: This was true in version 1.7 of the ABI,
+		         but it is not in version 1.9.  */
 		      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));
+
+		  /* "Single precision floating point values are mapped to
+		     the second word in a single doubleword."
+		     - 64-bit PowerPC ELF ABI version 1.9, page 16.  */
+		  if (TYPE_LENGTH (type) == 4)
+		    {
+		      memcpy (regval + 4, val, 4);
+		      p = regval;
+		    }
+		  else
+		    p = val;
+
+		  write_memory (gparam, p, 8);
 		}
-	      /* Always consume parameter stack space.  */
+
 	      freg++;
 	      greg++;
-	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	      /* Always consume parameter stack space.  */
+	      gparam = align_up (gparam + 8, tdep->wordsize);
 	    }
 	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
 		   && TYPE_LENGTH (type) == 16
diff --git a/gdb/testsuite/gdb.base/callfuncs.c b/gdb/testsuite/gdb.base/callfuncs.c
index 4903868..d546051 100644
--- a/gdb/testsuite/gdb.base/callfuncs.c
+++ b/gdb/testsuite/gdb.base/callfuncs.c
@@ -46,9 +46,35 @@ long long_val2 = -321;
 
 float float_val1 = 3.14159;
 float float_val2 = -2.3765;
+float float_val3 = 0.25;
+float float_val4 = 1.25;
+float float_val5 = 2.25;
+float float_val6 = 3.25;
+float float_val7 = 4.25;
+float float_val8 = 5.25;
+float float_val9 = 6.25;
+float float_val10 = 7.25;
+float float_val11 = 8.25;
+float float_val12 = 9.25;
+float float_val13 = 10.25;
+float float_val14 = 11.25;
+float float_val15 = 12.25;
 
 double double_val1 = 45.654;
 double double_val2 = -67.66;
+double double_val3 = 0.25;
+double double_val4 = 1.25;
+double double_val5 = 2.25;
+double double_val6 = 3.25;
+double double_val7 = 4.25;
+double double_val8 = 5.25;
+double double_val9 = 6.25;
+double double_val10 = 7.25;
+double double_val11 = 8.25;
+double double_val12 = 9.25;
+double double_val13 = 10.25;
+double double_val14 = 11.25;
+double double_val15 = 12.25;
 
 #define DELTA (0.001)
 
@@ -298,6 +324,39 @@ t_float_values2 (float float_arg1, float float_arg2)
 	  && (float_arg2 - float_val2) > -DELTA);
 }
 
+/* This function has many arguments to force some of them to be passed via
+   the stack instead of registers, to test that GDB can construct correctly
+   the parameter save area. Note that Linux/ppc32 has 8 float registers to use
+   for float parameter passing and Linux/ppc64 has 13, so the number of
+   arguments has to be at least 14 to contemplate these platforms.  */
+
+float
+#ifdef NO_PROTOTYPES
+t_float_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13,
+		   f14, f15)
+     float f1, float f2, float f3, float f4, float f5, float f6, float f7,
+     float f8, float f9, float f10, float f11, float f12, float f13, float f14,
+     float f15;
+#else
+t_float_many_args (float f1, float f2, float f3, float f4, float f5, float f6,
+		   float f7, float f8, float f9, float f10, float f11,
+		   float f12, float f13, float f14, float f15)
+#endif
+{
+  float sum_args;
+  float sum_values;
+
+  sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12
+	     + f13 + f14 + f15;
+  sum_values = float_val1 + float_val2 + float_val3 + float_val4 + float_val5
+	       + float_val6 + float_val7 + float_val8 + float_val9
+	       + float_val10 + float_val11 + float_val12 + float_val13
+	       + float_val14 + float_val15;
+
+  return ((sum_args - sum_values) < DELTA
+	  && (sum_args - sum_values) > -DELTA);
+}
+
 #ifdef PROTOTYPES
 int t_double_values (double double_arg1, double double_arg2)
 #else
@@ -311,6 +370,39 @@ double double_arg1, double_arg2;
 	  && (double_arg2 - double_val2) > -DELTA);
 }
 
+/* This function has many arguments to force some of them to be passed via
+   the stack instead of registers, to test that GDB can construct correctly
+   the parameter save area. Note that Linux/ppc32 has 8 float registers to use
+   for float parameter passing and Linux/ppc64 has 13, so the number of
+   arguments has to be at least 14 to contemplate these platforms.  */
+
+double
+#ifdef NO_PROTOTYPES
+t_double_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13,
+		   f14, f15)
+     double f1, double f2, double f3, double f4, double f5, double f6,
+     double f7, double f8, double f9, double f10, double f11, double f12,
+     double f13, double f14, double f15;
+#else
+t_double_many_args (double f1, double f2, double f3, double f4, double f5,
+		    double f6, double f7, double f8, double f9, double f10,
+		    double f11, double f12, double f13, double f14, double f15)
+#endif
+{
+  double sum_args;
+  double sum_values;
+
+  sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12
+	     + f13 + f14 + f15;
+  sum_values = double_val1 + double_val2 + double_val3 + double_val4
+	       + double_val5 + double_val6 + double_val7 + double_val8
+	       + double_val9 + double_val10 + double_val11 + double_val12
+	       + double_val13 + double_val14 + double_val15;
+
+  return ((sum_args - sum_values) < DELTA
+	  && (sum_args - sum_values) > -DELTA);
+}
+
 #ifdef PROTOTYPES
 int t_string_values (char *string_arg1, char *string_arg2)
 #else
diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp
index 7f605fd..6b53d82 100644
--- a/gdb/testsuite/gdb.base/callfuncs.exp
+++ b/gdb/testsuite/gdb.base/callfuncs.exp
@@ -155,6 +155,8 @@ proc do_function_calls {} {
         
 	gdb_test "p t_float_values2(3.14159,float_val2)" " = 1"
 
+	gdb_test "p t_float_many_args (float_val1, float_val2, float_val3, float_val4, float_val5, float_val6, float_val7, float_val8, float_val9, float_val10, float_val11, float_val12, float_val13, float_val14, float_val15)" " = 1" "Call function with many float arguments."
+
 	gdb_test "p t_small_values(1,2,3,4,5,6,7,8,9,10)" " = 55"
 
 	gdb_test "p t_double_values(0.0,0.0)" " = 0"
@@ -163,6 +165,8 @@ proc do_function_calls {} {
 	gdb_test "p t_double_values(45.654,double_val2)" " = 1"
 	gdb_test "p t_double_values(double_val1,-67.66)" " = 1"
 
+	gdb_test "p t_double_many_args (double_val1, double_val2, double_val3, double_val4, double_val5, double_val6, double_val7, double_val8, double_val9, double_val10, double_val11, double_val12, double_val13, double_val14, double_val15)" " = 1" "Call function with many double arguments."
+
 	gdb_test "p t_double_int(99.0, 1)" " = 0"
 	gdb_test "p t_double_int(99.0, 99)" " = 1"
 	gdb_test "p t_int_double(99, 1.0)" " = 0"

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