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:ppc64] Fix return value


Hello,

The attached impements PPC64 SYSV specific versions of:

	use_struct_convention
	extract_return_value
	store_return_value

It fixes:

gdb.base/return2.exp: char value returned successfully
gdb.base/return2.exp: int value returned successfully
gdb.base/return2.exp: short value returned successfully
gdb.base/structs.exp: p fun1
gdb.base/structs.exp: p fun2
gdb.base/structs.exp: p fun3
gdb.base/structs.exp: p fun4
gdb.base/structs.exp: p fun5
gdb.base/structs.exp: p fun6
gdb.base/structs.exp: p fun7
gdb.base/structs.exp: p fun8
gdb.c++/userdef.exp: print !one
gdb.c++/userdef.exp: print -one
gdb.c++/userdef.exp: print one != two
gdb.c++/userdef.exp: print one % two
gdb.c++/userdef.exp: print one & two
gdb.c++/userdef.exp: print one && two
gdb.c++/userdef.exp: print one * two
gdb.c++/userdef.exp: print one + two
gdb.c++/userdef.exp: print one - two
gdb.c++/userdef.exp: print one / two
gdb.c++/userdef.exp: print one < two
gdb.c++/userdef.exp: print one << 31
gdb.c++/userdef.exp: print one <= two
gdb.c++/userdef.exp: print one == two
gdb.c++/userdef.exp: print one > two
gdb.c++/userdef.exp: print one >= two
gdb.c++/userdef.exp: print one >> 31
gdb.c++/userdef.exp: print one ^ two
gdb.c++/userdef.exp: print one | two
gdb.c++/userdef.exp: print one || two
gdb.c++/userdef.exp: print ~one
gdb.c++/userdef.exp: re-selected 'main' frame after inferior call

Note the way I implemented it - the above wrap a generic ppc64_sysv_abi_return_value function and that handles all cases. I was finding that the more traditional technique (per my ppc post) was too error proned. Converting it to this style caused several mysterious regressions to mysteriously disappear.

I'm thinking of proposing that this technique become the norm.

Anyway, ok to commit?
Andrew

PS: I should note that PPC64's call function code is still on life support - it's not in a good shape at all.
2003-09-20  Andrew Cagney  <cagney@redhat.com>

	* rs6000-tdep.c (rs6000_gdbarch_init): When the 64 bit SysV ABI,
	set extract_return_value, store_return_value and
	use_struct_convention to ppc64_sysv_abi_extract_return_value,
	ppc64_sysv_abi_store_return_value and
	ppc64_sysv_abi_use_struct_convention.
	* ppc-tdep.h (ppc64_sysv_abi_extract_return_value): Declare.
	(ppc64_sysv_abi_store_return_value): Declare.
	(ppc64_sysv_abi_use_struct_convention): Declare.
	* ppc-sysv-tdep.c (ppc64_sysv_abi_extract_return_value): New
	function.
	(ppc64_sysv_abi_store_return_value): New function.
	(ppc64_sysv_abi_use_struct_convention): New function.
	(ppc64_sysv_abi_return_value): New function.

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	21 Sep 2003 00:06:28 -0000
@@ -325,3 +325,180 @@
 
   return (TYPE_LENGTH (value_type) > 8);
 }   
+
+
+/* The 64 bit ABI retun value convention.
+
+   Return non-zero if the return-value is stored in a register, return
+   0 if the return-value is instead stored on the stack (a.k.a.,
+   struct return convention).
+
+   For a return-value stored in a register: when INVAL is non-NULL,
+   copy the buffer to the corresponding register return-value location
+   location; when OUTVAL is non-NULL, fill the buffer from the
+   corresponding register return-value location.  */
+
+static int
+ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
+			     const void *inval, void *outval)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* Floats and doubles in F1.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT
+      && TYPE_LENGTH (valtype) <= 8)
+    {
+      char regval[MAX_REGISTER_SIZE];
+      struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
+      if (inval != NULL)
+	{
+	  convert_typed_floating (inval, valtype, regval, regtype);
+	  regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+	}
+      if (outval != NULL)
+	{
+	  regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
+	  convert_typed_floating (regval, regtype, outval, valtype);
+	}
+      return 1;
+    }
+  if (TYPE_CODE (valtype) == TYPE_CODE_INT
+      && TYPE_LENGTH (valtype) <= 8)
+    {
+      /* Integers in r3.  */
+      if (inval != NULL)
+	{
+	  /* Be careful to sign extend the value.  */
+	  regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+					  unpack_long (valtype, inval));
+	}
+      if (outval != NULL)
+	{
+	  /* Extract the integer from r3.  Since this is truncating the
+	     value, there isn't a sign extension problem.  */
+	  ULONGEST regval;
+	  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+					 &regval);
+	  store_unsigned_integer (outval, TYPE_LENGTH (valtype), regval);
+	}
+      return 1;
+    }
+  /* All pointers live in r3.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
+    {
+      /* All pointers live in r3.  */
+      if (inval != NULL)
+	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, inval);
+      if (outval != NULL)
+	regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, outval);
+      return 1;
+    }
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+      && TYPE_LENGTH (valtype) <= 8
+      && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
+      && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
+    {
+      /* Small character arrays are returned, right justified, in r3.  */
+      int offset = (register_size (current_gdbarch, tdep->ppc_gp0_regnum + 3)
+		    - TYPE_LENGTH (valtype));
+      if (inval != NULL)
+	regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
+				    offset, TYPE_LENGTH (valtype), inval);
+      if (outval != NULL)
+	regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
+				   offset, TYPE_LENGTH (valtype), outval);
+      return 1;
+    }
+  /* Big floating point values get stored in adjacent floating
+     point registers.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT
+      && (TYPE_LENGTH (valtype) == 16
+	  || TYPE_LENGTH (valtype) == 32))
+    {
+      if (inval || outval != NULL)
+	{
+	  int i;
+	  for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
+	    {
+	      if (inval != NULL)
+		regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+				       (const bfd_byte *) inval + i * 8);
+	      if (outval != NULL)
+		regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
+				      (bfd_byte *) outval + i * 8);
+	    }
+	}
+      return 1;
+    }
+  /* Complex values get returned in f1:f2, need to convert.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
+      && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
+    {
+      if (regcache != NULL)
+	{
+	  int i;
+	  for (i = 0; i < 2; i++)
+	    {
+	      char regval[MAX_REGISTER_SIZE];
+	      struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
+	      if (inval != NULL)
+		{
+		  convert_typed_floating ((const bfd_byte *) inval + i * (TYPE_LENGTH (valtype) / 2),
+					  valtype, regval, regtype);
+		  regcache_cooked_write (regcache, FP0_REGNUM + 1 + i, regval);
+		}
+	      if (outval != NULL)
+		{
+		  regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval);
+		  convert_typed_floating (regval, regtype,
+					  (bfd_byte *) outval + i * (TYPE_LENGTH (valtype) / 2),
+					  valtype);
+		}
+	    }
+	}
+      return 1;
+    }
+  /* Big complex values get stored in f1:f4.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
+      && TYPE_LENGTH (valtype) == 32)
+    {
+      if (regcache != NULL)
+	{
+	  int i;
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (inval != NULL)
+		regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+				       (const bfd_byte *) inval + i * 8);
+	      if (outval != NULL)
+		regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
+				      (bfd_byte *) outval + i * 8);
+	    }
+	}
+      return 1;
+    }
+  return 0;
+}
+
+int
+ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
+{
+  return !ppc64_sysv_abi_return_value (value_type, NULL, NULL, NULL);
+}
+
+void
+ppc64_sysv_abi_extract_return_value (struct type *valtype,
+				     struct regcache *regbuf,
+				     void *valbuf)
+{
+  if (!ppc64_sysv_abi_return_value (valtype, regbuf, NULL, valbuf))
+    error ("Function return value unknown");
+}
+
+void
+ppc64_sysv_abi_store_return_value (struct type *valtype,
+				   struct regcache *regbuf,
+				   const void *valbuf)
+{
+  if (!ppc64_sysv_abi_return_value (valtype, regbuf, valbuf, NULL))
+    error ("Function return value location unknown");
+}
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 00:06:28 -0000
@@ -47,6 +47,14 @@
 void ppc_linux_supply_gregset (char *buf);
 void ppc_linux_supply_fpregset (char *buf);
 
+int ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type);
+void ppc64_sysv_abi_extract_return_value (struct type *valtype,
+					  struct regcache *regbuf,
+					  void *valbuf);
+void ppc64_sysv_abi_store_return_value (struct type *valtype,
+					struct regcache *regbuf,
+					const void *valbuf);
+
 
 /* From rs6000-tdep.c... */
 CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi);
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	21 Sep 2003 00:06:29 -0000
@@ -2830,9 +2830,16 @@
   set_gdbarch_pc_regnum (gdbarch, 64);
   set_gdbarch_sp_regnum (gdbarch, 1);
   set_gdbarch_deprecated_fp_regnum (gdbarch, 1);
-  set_gdbarch_deprecated_extract_return_value (gdbarch,
-					       rs6000_extract_return_value);
-  set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value);
+  if (sysv_abi && wordsize == 8)
+    {
+      set_gdbarch_extract_return_value (gdbarch, ppc64_sysv_abi_extract_return_value);
+      set_gdbarch_store_return_value (gdbarch, ppc64_sysv_abi_store_return_value);
+    }
+  else
+    {
+      set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
+      set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value);
+    }
 
   if (v->arch == bfd_arch_powerpc)
     switch (v->mach)
@@ -2964,9 +2971,11 @@
   /* Not sure on this. FIXMEmgo */
   set_gdbarch_frame_args_skip (gdbarch, 8);
 
-  if (sysv_abi)
+  if (sysv_abi && wordsize == 4)
     set_gdbarch_use_struct_convention (gdbarch,
     				       ppc_sysv_abi_use_struct_convention);
+  else if (sysv_abi && wordsize == 8)
+    set_gdbarch_use_struct_convention (gdbarch, ppc64_sysv_abi_use_struct_convention);
   else
     set_gdbarch_use_struct_convention (gdbarch,
 				       rs6000_use_struct_convention);

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