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?] Implement ppc32 SYSV {extract,store} return value


Hello,

This adds a new ppc32 SYSV specific extract_return_value and store_return_value (while at the same time eliminating the e500 specific methods). The new functions also avoid some really bogus looking floating point code in the old rs6000 * return_value functions - I'm still trying to figure out how it worked ... ah, it's native only.

I've tested it in vanila GNU/Linux (no regressions) and NBSD (4 less structs fails) (i.e., no altivec nor e500).

If nothing else I'd really like a comment on the general approach taken - the netbsd function wrapping a more generic method, and a better word than "broken" I guess.

thoughts?
Andrew

PS: My comments refer to SYSV ppc32 but the change does also affect SYSV ppc64, "can I get back to you on that" :-)
2003-09-13  Andrew Cagney  <cagney@redhat.com>

	* rs6000-tdep.c (e500_store_return_value): Delete function.
	(e500_extract_return_value): Delete function.
	(rs6000_gdbarch_init): When SYSV, set "extract_return_value" and
	"restore_return_value" to "ppc_sysv_abi_extract_return_value" and
	"ppc_sysv_abi_restore_return_value" where applicable.
	* ppc-tdep.h: Re-organize so that functions from "ppc-sysv-tdep.c"
	are all the one place.
	(ppc_sysv_abi_store_return_value): Declare.
	(ppc_sysv_abi_extract_return_value): Declare.
	(ppc_sysv_abi_broken_store_return_value): Declare.
	(ppc_sysv_abi_broken_extract_return_value): Declare.
	* ppc-sysv-tdep.c (extract_return_value): New function.
	(store_return_value): New function.
	(ppc_sysv_abi_extract_return_value): New function.
	(ppc_sysv_abi_store_return_value): New function.
	(ppc_sysv_abi_broken_extract_return_value): New function.
	(ppc_sysv_abi_broken_store_return_value): New function.

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	17 Sep 2003 21:22:27 -0000
@@ -340,3 +340,228 @@
 
   return (TYPE_LENGTH (value_type) > 8);
 }   
+
+static void
+extract_return_value (struct type *type,
+		      struct regcache *regcache,
+		      void *valbuf, int broken)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (using_struct_return (type, 1))
+    error ("Function return value unknown");
+  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+	   && TYPE_LENGTH (type) <= 8
+	   && ppc_floating_point_unit_p (current_gdbarch))
+    {
+      /* Floats and doubles stored in "f1".  Convert the value to the
+         required type.  */
+      char regval[MAX_REGISTER_SIZE];
+      struct type *regtype = register_type (current_gdbarch, FP0_REGNUM + 1);
+      regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
+      convert_typed_floating (regval, regtype, valbuf, type);
+    }
+  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+	    && TYPE_LENGTH (type) == 8
+	    && tdep->wordsize == 4)
+	   || (TYPE_CODE (type) == TYPE_CODE_FLT
+	       && TYPE_LENGTH (type) == 8
+	       && tdep->wordsize == 4))
+    {
+      /* A long long, or a double stored in r3/r4.  */
+      regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+			    (bfd_byte *) valbuf + 0);
+      regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+			    (bfd_byte *) valbuf + 4);
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_INT
+	   && TYPE_LENGTH (type) <= tdep->wordsize)
+    {
+      /* Some sort of integer stored in r3.  Since TYPE isn't bigger
+         than the register, sign extension isn't a problem - just do
+         everything unsigned.  */
+      ULONGEST regval;
+      regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+				     &regval);
+      store_unsigned_integer (valbuf, TYPE_LENGTH (type), regval);
+    }
+  else if (TYPE_LENGTH (type) == 16
+	   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+	   && TYPE_VECTOR (type)
+	   && tdep->ppc_vr0_regnum >= 0)
+    {
+      /* Altivec places the return value in "v2".  */
+      regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, valbuf);
+    }
+  else if (TYPE_LENGTH (type) == 8
+	   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+	   && TYPE_VECTOR (type)
+	   && tdep->ppc_ev0_regnum >= 0)
+    {
+      /* e500 places the return value in "ev2".  */
+      regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 2, valbuf);
+    }
+  else if (broken && TYPE_LENGTH (type) <= 8)
+    {
+      /* GCC screwed up.  The last register isn't "left" aligned.
+         Need to extract the least significant part of each register
+         and then store that.  */
+      /* Transfer any full words.  */
+      int word = 0;
+      while (1)
+	{
+	  ULONGEST reg;
+	  int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+	  if (len <= 0)
+	    break;
+	  if (len > tdep->wordsize)
+	    len = tdep->wordsize;
+	  regcache_cooked_read_unsigned (regcache,
+					 tdep->ppc_gp0_regnum + 3 + word,
+					 &reg);
+	  store_unsigned_integer ((bfd_byte *) valbuf + word * tdep->wordsize,
+				  len, reg);
+	  word++;
+	}
+    }
+  else if (TYPE_LENGTH (type) <= 8)
+    {
+      /* This matches SVr4 PPC, it does not match gcc.  */
+      /* The value is padded out to 8 bytes and then loaded, as two
+         "words" into r3/r3.  */
+      char regvals[MAX_REGISTER_SIZE * 2];
+      regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+			    regvals + 0 * tdep->wordsize);
+      if (TYPE_LENGTH (type) > tdep->wordsize)
+	regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+			      regvals + 1 * tdep->wordsize);
+      memcpy (valbuf, regvals, TYPE_LENGTH (type));
+    }
+  else
+    internal_error (__FILE__, __LINE__, "return type unhandled");
+}
+
+void
+ppc_sysv_abi_extract_return_value (struct type *type,
+				   struct regcache *regcache,
+				   void *valbuf)
+{
+  extract_return_value (type, regcache, valbuf, 0);
+}
+
+void
+ppc_sysv_abi_broken_extract_return_value (struct type *type,
+					  struct regcache *regcache,
+					  void *valbuf)
+{
+  extract_return_value (type, regcache, valbuf, 1);
+}
+
+static void
+store_return_value (struct type *type, struct regcache *regcache,
+		    const void *valbuf, int broken)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (using_struct_return (type, 1))
+    error ("Cannot return value");
+  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+	   && TYPE_LENGTH (type) <= 8
+	   && ppc_floating_point_unit_p (current_gdbarch))
+    {
+      /* Floats and doubles stored in "f1".  Convert the value to the
+         register's "double" type.  */
+      char regval[MAX_REGISTER_SIZE];
+      struct type *regtype = register_type (current_gdbarch, FP0_REGNUM + 1);
+      convert_typed_floating (valbuf, type, regval, regtype);
+      regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+    }
+  else if ((TYPE_CODE (type) == TYPE_CODE_INT
+	    && TYPE_LENGTH (type) == 8
+	    && tdep->wordsize == 4)
+	   || (TYPE_CODE (type) == TYPE_CODE_FLT
+	       && TYPE_LENGTH (type) == 8
+	       && tdep->wordsize == 4))
+    {
+      /* A long long, or a double stored in r3/r4.  */
+      regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+			     (bfd_byte *) valbuf + 0);
+      regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+			     (bfd_byte *) valbuf + 4);
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_INT
+	   && TYPE_LENGTH (type) <= tdep->wordsize)
+    {
+      /* Some sort of integer stored in r3.  Use unpack_long since
+         that should handle any required sign extension.  */
+      regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+				      unpack_long (type, valbuf));	      
+    }
+  else if (TYPE_LENGTH (type) == 16
+	   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+	   && TYPE_VECTOR (type)
+	   && tdep->ppc_vr0_regnum >= 0)
+    {
+      /* Altivec places the return value in "v2".  */
+      regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, valbuf);
+    }
+  else if (TYPE_LENGTH (type) == 8
+	   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+	   && TYPE_VECTOR (type)
+	   && tdep->ppc_ev0_regnum >= 0)
+    {
+      /* e500 places the return value in "ev2".  */
+      regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 2, valbuf);
+    }
+  else if (broken && TYPE_LENGTH (type) <= 8)
+    {
+      /* GCC screwed up.  The last register isn't "left" aligned.
+         Need to extract the least significant part of each register
+         and then store that.  */
+      /* Transfer any full words.  */
+      int word = 0;
+      while (1)
+	{
+	  ULONGEST reg;
+	  int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+	  if (len <= 0)
+	    break;
+	  if (len > tdep->wordsize)
+	    len = tdep->wordsize;
+	  reg = extract_unsigned_integer ((bfd_byte *) valbuf + word * tdep->wordsize, len);
+	  regcache_cooked_write_unsigned (regcache,
+					  tdep->ppc_gp0_regnum + 3 + word,
+					  reg);
+	  word++;
+	}
+    }
+  else if (TYPE_LENGTH (type) <= 8)
+    {
+      /* This matches SVr4 PPC, it does not match gcc.  */
+      /* The value is padded out to 8 bytes and then loaded, as two
+         "words" into r3/r3.  */
+      char regvals[MAX_REGISTER_SIZE * 2];
+      memset (regvals, 0, sizeof regvals);
+      memcpy (regvals, valbuf, TYPE_LENGTH (type));
+      regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+			     regvals + 0 * tdep->wordsize);
+      if (TYPE_LENGTH (type) > tdep->wordsize)
+	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+			       regvals + 1 * tdep->wordsize);
+    }
+  else
+    internal_error (__FILE__, __LINE__, "return type unhandled");
+}
+
+void
+ppc_sysv_abi_store_return_value (struct type *type, struct regcache *regcache,
+				 const void *valbuf)
+{
+  store_return_value (type, regcache, valbuf, 0);
+}
+
+void
+ppc_sysv_abi_broken_store_return_value (struct type *type,
+					struct regcache *regcache,
+					const void *valbuf)
+{
+  store_return_value (type, regcache, valbuf, 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	17 Sep 2003 21:22:27 -0000
@@ -33,20 +33,36 @@
 int ppc_linux_frameless_function_invocation (struct frame_info *);
 void ppc_linux_frame_init_saved_regs (struct frame_info *);
 CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
-int ppc_sysv_abi_use_struct_convention (int, struct type *);
-int ppc_sysv_abi_broken_use_struct_convention (int, struct type *);
-CORE_ADDR ppc_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);
 void ppc_linux_supply_fpregset (char *buf);
 
+
+/* From ppc-sysv-tdep.c... */
+extern CORE_ADDR ppc_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);
+
+extern int ppc_sysv_abi_use_struct_convention (int, struct type *);
+extern void ppc_sysv_abi_store_return_value (struct type *type,
+					     struct regcache *regcache,
+					     const void *valbuf);
+extern void ppc_sysv_abi_extract_return_value (struct type *type,
+					       struct regcache *regcache,
+					       void *valbuf);
+
+extern void ppc_sysv_abi_broken_store_return_value (struct type *type,
+						    struct regcache *regcache,
+						    const void *valbuf);
+extern void ppc_sysv_abi_broken_extract_return_value (struct type *type,
+						      struct regcache *regcache,
+						      void *valbuf);
 
 /* From rs6000-tdep.c... */
 CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi);
Index: ppcnbsd-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppcnbsd-tdep.c,v
retrieving revision 1.8
diff -u -r1.8 ppcnbsd-tdep.c
--- ppcnbsd-tdep.c	17 Sep 2003 20:10:48 -0000	1.8
+++ ppcnbsd-tdep.c	17 Sep 2003 21:22:27 -0000
@@ -204,6 +204,7 @@
   return (nbsd_pc_in_sigtramp (pc, func_name));
 }
 
+
 /* NetBSD is confused.  It appears that 1.5 was using the correct SVr4
    convention but, 1.6 switched to the below broken convention.  For
    the moment use the broken convention.  Ulgh!.  */
@@ -226,8 +227,11 @@
                   struct gdbarch *gdbarch)
 {
   set_gdbarch_pc_in_sigtramp (gdbarch, ppcnbsd_pc_in_sigtramp);
-
+  /* For NetBSD, this is an on again, off again thing.  Some systems
+     do use the broken struct convention, and some don't.  */
   set_gdbarch_use_struct_convention (gdbarch, ppcnbsd_use_struct_convention);
+  set_gdbarch_extract_return_value (gdbarch, ppc_sysv_abi_broken_extract_return_value);
+  set_gdbarch_store_return_value (gdbarch, ppc_sysv_abi_broken_store_return_value);
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
                                 nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
 }
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	17 Sep 2003 21:22:28 -0000
@@ -1313,65 +1313,6 @@
   return sp;
 }
 
-/* Extract a function return value of type TYPE from raw register array
-   REGBUF, and copy that return value into VALBUF in virtual format.  */
-static void
-e500_extract_return_value (struct type *valtype, struct regcache *regbuf, void *valbuf)
-{
-  int offset = 0;
-  int vallen = TYPE_LENGTH (valtype);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
-      && vallen == 8
-      && TYPE_VECTOR (valtype))
-    {
-      regcache_raw_read (regbuf, tdep->ppc_ev0_regnum + 3, valbuf);
-    }
-  else
-    {
-      /* Return value is copied starting from r3.  Note that r3 for us
-         is a pseudo register.  */
-      int offset = 0;
-      int return_regnum = tdep->ppc_gp0_regnum + 3;
-      int reg_size = REGISTER_RAW_SIZE (return_regnum);
-      int reg_part_size;
-      char *val_buffer;
-      int copied = 0;
-      int i = 0;
-
-      /* Compute where we will start storing the value from.  */ 
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
-        {
-	  if (vallen <= reg_size)
-	    offset = reg_size - vallen;
-	  else
-	    offset = reg_size + (reg_size - vallen);
-        }
-
-      /* How big does the local buffer need to be?  */
-      if (vallen <= reg_size)
-	val_buffer = alloca (reg_size);
-      else
-	val_buffer = alloca (vallen);
-
-      /* Read all we need into our private buffer.  We copy it in
-         chunks that are as long as one register, never shorter, even
-         if the value is smaller than the register.  */
-      while (copied < vallen)
-        {
-          reg_part_size = REGISTER_RAW_SIZE (return_regnum + i);
-	  /* It is a pseudo/cooked register.  */
-          regcache_cooked_read (regbuf, return_regnum + i,
-				val_buffer + copied);
-          copied += reg_part_size;
-          i++;
-        }
-      /* Put the stuff in the return buffer.  */
-      memcpy (valbuf, val_buffer + offset, vallen);
-    }
-}
-
 /* PowerOpen always puts structures in memory.  Vectors, which were
    added later, do get returned in a register though.  */
 
@@ -2046,30 +1987,6 @@
   return regnum;
 }
 
-/* Write into appropriate registers a function return value
-   of type TYPE, given in virtual format.  */
-static void
-e500_store_return_value (struct type *type, char *valbuf)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  /* Everything is returned in GPR3 and up.  */
-  int copied = 0;
-  int i = 0;
-  int len = TYPE_LENGTH (type);
-  while (copied < len)
-    {
-      int regnum = gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + 3 + i;
-      int reg_size = REGISTER_RAW_SIZE (regnum);
-      char *reg_val_buf = alloca (reg_size);
-
-      memcpy (reg_val_buf, valbuf + copied, reg_size);
-      copied += reg_size;
-      deprecated_write_register_gen (regnum, reg_val_buf);
-      i++;
-    }
-}
-
 static void
 rs6000_store_return_value (struct type *type, char *valbuf)
 {
@@ -2830,9 +2747,6 @@
   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 (v->arch == bfd_arch_powerpc)
     switch (v->mach)
@@ -2866,8 +2780,6 @@
         set_gdbarch_dwarf2_reg_to_regnum (gdbarch, e500_dwarf2_reg_to_regnum);
         set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read);
         set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write);
-        set_gdbarch_extract_return_value (gdbarch, e500_extract_return_value);
-        set_gdbarch_deprecated_store_return_value (gdbarch, e500_store_return_value);
 	break;
       default:
 	tdep->ppc_vr0_regnum = -1;
@@ -2965,11 +2877,17 @@
   set_gdbarch_frame_args_skip (gdbarch, 8);
 
   if (sysv_abi)
-    set_gdbarch_use_struct_convention (gdbarch,
-    				       ppc_sysv_abi_use_struct_convention);
+    {
+      set_gdbarch_use_struct_convention (gdbarch, ppc_sysv_abi_use_struct_convention);
+      set_gdbarch_extract_return_value (gdbarch, ppc_sysv_abi_extract_return_value);
+      set_gdbarch_store_return_value (gdbarch, ppc_sysv_abi_store_return_value);
+    }
   else
-    set_gdbarch_use_struct_convention (gdbarch,
-				       rs6000_use_struct_convention);
+    {
+      set_gdbarch_use_struct_convention (gdbarch, rs6000_use_struct_convention);
+      set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
+      set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value);
+    }
 
   set_gdbarch_frameless_function_invocation (gdbarch,
                                          rs6000_frameless_function_invocation);

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