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]

Re: [rfa?] Implement ppc32 SYSV {extract,store} return value


On Sep 17, 5:54pm, Andrew Cagney wrote:


If nothing else I'd really like a comment on the general approach taken - the netbsd function wrapping a more generic method,


What are you referring to here?  I looked at the netbsd portion of
your patch and I don't see what you're referring to.  I do see
that your using the ppc_sys_v_abi_... version for extract_return_value
and store_return_value.  But I think that's okay until we find that
it's broken in ways not already handled by the code you've just added.

Just that. Wrapping the more generic method.


(This is different than the case that I commented on previously -- In
which it appeared that code for one ABI was reusable by another.  In
such a case, I think clearly distinguishing the code implementing the
two ABIs is a good idea.  For NetBSD, it's supposed to be implementing
the System V ABI, right?  That being the case, I think it's just fine
to do things the way you've arranged it.)


and a better word than "broken" I guess.


At the moment, I can't think of anything better.  (Or, to put it another
way, anything that I've thought of ends up being overly verbose.)

Anyway, your patch looks okay to me. Feel free to check it in.

Here is a revised version. It's now implemented using a wrapped ..._return_value.


Still ok?

Andrew

2003-10-03  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: (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_abi_broken_use_struct_convention:) Delete declaration.
	* ppc-sysv-tdep.c (do_ppc_sysv_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.
	(ppc_sysv_abi_use_struct_convention): Call
	do_ppc_sysv_return_value.

Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.13
diff -u -r1.13 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	3 Oct 2003 21:11:39 -0000	1.13
+++ ppc-sysv-tdep.c	4 Oct 2003 17:42:27 -0000
@@ -314,16 +314,256 @@
   return sp;
 }
 
+/* Potential ways that a function can return a value of a given type.  */
+enum return_value_convention
+{
+  /* Where the return value has been squeezed into one or more
+     registers.  */
+  RETURN_VALUE_REGISTER_CONVENTION,
+  /* Commonly known as the "struct return convention".  The caller
+     passes an additional hidden first parameter to the caller.  That
+     parameter contains the address at which the value being returned
+     should be stored.  While typically, and historically, used for
+     large structs, this is convention is applied to values of many
+     different types.  */
+  RETURN_VALUE_STRUCT_CONVENTION
+};
+
+static enum return_value_convention
+do_ppc_sysv_return_value (struct type *type, struct regcache *regcache,
+		       const void *inval, void *outval, int broken)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) <= 8
+      && ppc_floating_point_unit_p (current_gdbarch))
+    {
+      if (outval)
+	{
+	  /* 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, outval, type);
+	}
+      if (inval)
+	{
+	  /* 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);
+	  convert_typed_floating (inval, type, regval, regtype);
+	  regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  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))
+    {
+      if (outval)
+	{
+	  /* A long long, or a double stored in the 32 bit r3/r4.  */
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+				(bfd_byte *) outval + 0);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+				(bfd_byte *) outval + 4);
+	}
+      if (inval)
+	{
+	  /* A long long, or a double stored in the 32 bit r3/r4.  */
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+				 (bfd_byte *) inval + 0);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+				 (bfd_byte *) inval + 4);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_CODE (type) == TYPE_CODE_INT
+      && TYPE_LENGTH (type) <= tdep->wordsize)
+    {
+      if (outval)
+	{
+	  /* 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 (outval, TYPE_LENGTH (type), regval);
+	}
+      if (inval)
+	{
+	  /* 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, inval));
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) == 16
+      && TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type)
+      && tdep->ppc_vr0_regnum >= 0)
+    {
+      if (outval)
+	{
+	  /* Altivec places the return value in "v2".  */
+	  regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, outval);
+	}
+      if (inval)
+	{
+	  /* Altivec places the return value in "v2".  */
+	  regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, inval);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) == 8
+      && TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type)
+      && tdep->ppc_ev0_regnum >= 0)
+    {
+      if (outval)
+	{
+	  /* e500 places the return value in "ev2".  */
+	  regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 2, outval);
+	}
+      if (inval)
+	{
+	  /* e500 places the return value in "ev2".  */
+	  regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 2, inval);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (broken && TYPE_LENGTH (type) <= 8)
+    {
+      if (outval)
+	{
+	  /* 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 *) outval
+				       + word * tdep->wordsize),
+				      len, reg);
+	      word++;
+	    }
+	}
+      if (inval)
+	{
+	  /* 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 *) inval
+					       + word * tdep->wordsize),
+					      len);
+	      regcache_cooked_write_unsigned (regcache,
+					      tdep->ppc_gp0_regnum + 3 + word,
+					      reg);
+	      word++;
+	    }
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) <= 8)
+    {
+      if (outval)
+	{
+	  /* 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 (outval, regvals, TYPE_LENGTH (type));
+	}
+      if (inval)
+	{
+	  /* 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, inval, 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);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  return RETURN_VALUE_STRUCT_CONVENTION; 
+}
+
+void
+ppc_sysv_abi_extract_return_value (struct type *type,
+				   struct regcache *regcache,
+				   void *valbuf)
+{
+  do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 0);
+}
+
+void
+ppc_sysv_abi_broken_extract_return_value (struct type *type,
+					  struct regcache *regcache,
+					  void *valbuf)
+{
+  do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 1);
+}
+
+void
+ppc_sysv_abi_store_return_value (struct type *type, struct regcache *regcache,
+				 const void *valbuf)
+{
+  do_ppc_sysv_return_value (type, regcache, valbuf, NULL, 0);
+}
+
+void
+ppc_sysv_abi_broken_store_return_value (struct type *type,
+					struct regcache *regcache,
+					const void *valbuf)
+{
+  do_ppc_sysv_return_value (type, regcache, valbuf, NULL, 1);
+}
+
 /* Structures 8 bytes or less long are returned in the r3 & r4
    registers, according to the SYSV ABI. */
 int
-ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
+ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *type)
 {
-  if ((TYPE_LENGTH (value_type) == 16 || TYPE_LENGTH (value_type) == 8)
-      && TYPE_VECTOR (value_type))
-    return 0;
-
-  return (TYPE_LENGTH (value_type) > 8);
+  return (do_ppc_sysv_return_value (type, NULL, NULL, NULL, 0)
+	  == RETURN_VALUE_STRUCT_CONVENTION);
 }   
 
 
@@ -337,21 +577,6 @@
    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.  */
-
-/* Potential ways that a function can return a value of a given type.  */
-enum return_value_convention
-{
-  /* Where the return value has been squeezed into one or more
-     registers.  */
-  RETURN_VALUE_REGISTER_CONVENTION,
-  /* Commonly known as the "struct return convention".  The caller
-     passes an additional hidden first parameter to the caller.  That
-     parameter contains the address at which the value being returned
-     should be stored.  While typically, and historically, used for
-     large structs, this is convention is applied to values of many
-     different types.  */
-  RETURN_VALUE_STRUCT_CONVENTION
-};
 
 static enum return_value_convention
 ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
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	4 Oct 2003 17:42:27 -0000
@@ -34,7 +34,18 @@
 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 *);
+void ppc_sysv_abi_store_return_value (struct type *type,
+				      struct regcache *regcache,
+				      const void *valbuf);
+void ppc_sysv_abi_extract_return_value (struct type *type,
+					struct regcache *regcache,
+					void *valbuf);
+void ppc_sysv_abi_broken_store_return_value (struct type *type,
+					     struct regcache *regcache,
+					     const void *valbuf);
+void ppc_sysv_abi_broken_extract_return_value (struct type *type,
+					       struct regcache *regcache,
+					       void *valbuf);
 CORE_ADDR ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
 					CORE_ADDR func_addr,
 					struct regcache *regcache,
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	4 Oct 2003 17:42:27 -0000
@@ -226,8 +226,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.166
diff -u -r1.166 rs6000-tdep.c
--- rs6000-tdep.c	3 Oct 2003 21:11:39 -0000	1.166
+++ rs6000-tdep.c	4 Oct 2003 17:42: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 = DEPRECATED_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 = DEPRECATED_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 = DEPRECATED_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)
 {
@@ -2835,6 +2752,11 @@
       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 if (sysv_abi && wordsize == 4)
+    {
+      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_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
@@ -2873,8 +2795,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;

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