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]

[patch/rfc, rfa:doco] gdbarch return value


Hello,

This implements the "return_value" method I proposed earlier this week. It replaces USE_STRUCT_CONVENTION, EXTRACT_RETURN_VALUE, and STORE_RETURN_VALUE. The implementation is fallout from me fixing the ppc64 return code and finding that a single "reurn_value" method lead to more robust code.

Several things to note:

- The doco contains a number of maintainer notes. The intent is to provide something of a rationale for the current interface. That way future changes will have a reasonable base from which to work from. They are recommended reading.

- I've modified the "return small_struct" code so that, when an architecture doesn't implement return_value an internal_error and not an error is reported. With the introduction of return_value, it is possible to handle the "return small_struct" case so failing to do this is an a bug in GDB.

Comments. For reference, an implementation of the method looks like:

static enum return_value_convention
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 RETURN_VALUE_REGISTER_CONVENTION;
    }
  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 RETURN_VALUE_REGISTER_CONVENTION;
    }

Otherwize, I'll commit early next week.


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

	* infcmd.c: Include "gdb_assert.h".
	(print_return_value): When gdbarch_return_value_p, and using
	struct return, assume that the value is not available.
	* values.c (register_value_being_returned): Use
	"gdbarch_return_value" when available.
	(set_return_value): Ditto.  Call internal_error when an unhandled
	struct or union is encountered.
	(using_struct_return): Ditto.
	* defs.h (return_value_convention): Define.
	* gdbarch.sh (gdbarch_return_value): New predicate method.
	* gdbarch.h, gdbarch.c: Re-generate

Index: doc/ChangeLog
2003-10-02  Andrew Cagney  <cagney@redhat.com>

	* gdbint.texinfo (Target Architecture Definition): Document
	gdbarch_return_value.  Add cross references from
	USE_STRUCT_CONVENTION, EXTRACT_RETURN_VALUE, and
	STORE_RETURN_VALUE, and from/to EXTRACT_STRUCT_VALUE_ADDRESS.

Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.131
diff -u -r1.131 defs.h
--- defs.h	19 Sep 2003 16:22:38 -0000	1.131
+++ defs.h	2 Oct 2003 17:31:44 -0000
@@ -230,6 +230,21 @@
   AUTO_BOOLEAN_AUTO
 };
 
+/* 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
+};
+
 /* the cleanup list records things that have to be undone
    if an error happens (descriptors to be closed, memory to be freed, etc.)
    Each link in the chain records a function to call and an
Index: gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.274
diff -u -r1.274 gdbarch.sh
--- gdbarch.sh	30 Sep 2003 19:12:18 -0000	1.274
+++ gdbarch.sh	2 Oct 2003 17:31:46 -0000
@@ -593,19 +593,33 @@
 f:2:ADDRESS_TO_POINTER:void:address_to_pointer:struct type *type, void *buf, CORE_ADDR addr:type, buf, addr:::unsigned_address_to_pointer::0
 F:2:INTEGER_TO_ADDRESS:CORE_ADDR:integer_to_address:struct type *type, void *buf:type, buf
 #
-f:2:RETURN_VALUE_ON_STACK:int:return_value_on_stack:struct type *type:type:::generic_return_value_on_stack_not::0
 F:2:DEPRECATED_POP_FRAME:void:deprecated_pop_frame:void:-
 # NOTE: cagney/2003-03-24: Replaced by PUSH_ARGUMENTS.
 F:2:DEPRECATED_STORE_STRUCT_RETURN:void:deprecated_store_struct_return:CORE_ADDR addr, CORE_ADDR sp:addr, sp
-#
+
+# It has been suggested that this, well actually its predecessor,
+# should take the type/value of the function to be called and not the
+# return type.  This is left as an exercise for the reader.
+
+M:::enum return_value_convention:return_value:struct type *valtype, struct regcache *regcache, const void *inval, void *outval:valtype, regcache, inval, outval
+
+# The deprecated methods RETURN_VALUE_ON_STACK, EXTRACT_RETURN_VALUE,
+# STORE_RETURN_VALUE and USE_STRUCT_CONVENTION have all been folded
+# into RETURN_VALUE.  For the moment do not try to fold in
+# EXTRACT_STRUCT_VALUE_ADDRESS as, dependant on the ABI, the debug
+# info, and the level of effort, it may well be possible to find the
+# address of a structure being return on the stack.  Someone else can
+# make that change.
+
+f:2:RETURN_VALUE_ON_STACK:int:return_value_on_stack:struct type *type:type:::generic_return_value_on_stack_not::0
 f:2:EXTRACT_RETURN_VALUE:void:extract_return_value:struct type *type, struct regcache *regcache, void *valbuf:type, regcache, valbuf:::legacy_extract_return_value::0
 f:2:STORE_RETURN_VALUE:void:store_return_value:struct type *type, struct regcache *regcache, const void *valbuf:type, regcache, valbuf:::legacy_store_return_value::0
 f:2:DEPRECATED_EXTRACT_RETURN_VALUE:void:deprecated_extract_return_value:struct type *type, char *regbuf, char *valbuf:type, regbuf, valbuf
 f:2:DEPRECATED_STORE_RETURN_VALUE:void:deprecated_store_return_value:struct type *type, char *valbuf:type, valbuf
-#
+f:2:USE_STRUCT_CONVENTION:int:use_struct_convention:int gcc_p, struct type *value_type:gcc_p, value_type:::generic_use_struct_convention::0
+
 F:2:EXTRACT_STRUCT_VALUE_ADDRESS:CORE_ADDR:extract_struct_value_address:struct regcache *regcache:regcache
 F:2:DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS:CORE_ADDR:deprecated_extract_struct_value_address:char *regbuf:regbuf
-f:2:USE_STRUCT_CONVENTION:int:use_struct_convention:int gcc_p, struct type *value_type:gcc_p, value_type:::generic_use_struct_convention::0
 #
 F:2:DEPRECATED_FRAME_INIT_SAVED_REGS:void:deprecated_frame_init_saved_regs:struct frame_info *frame:frame
 F:2:DEPRECATED_INIT_EXTRA_FRAME_INFO:void:deprecated_init_extra_frame_info:int fromleaf, struct frame_info *frame:fromleaf, frame
Index: infcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/infcmd.c,v
retrieving revision 1.95
diff -u -r1.95 infcmd.c
--- infcmd.c	2 Oct 2003 04:40:58 -0000	1.95
+++ infcmd.c	2 Oct 2003 17:31:46 -0000
@@ -44,6 +44,7 @@
 #include "reggroups.h"
 #include "block.h"
 #include <ctype.h>
+#include "gdb_assert.h"
 
 /* Functions exported for general use, in inferior.h: */
 
@@ -1079,25 +1080,34 @@
       ui_out_field_stream (uiout, "return-value", stb);
       ui_out_text (uiout, "\n");
     }
-  else
-    {
-      /* FIXME: 2003-09-27: When returning from a nested inferior
-         function call, it's possible (with no help from the
-         architecture vector) to locate and return/print a "struct
-         return" value.  This is just a more complicated case of what
-         is already being done in in the inferior function call code.
-         In fact, when inferior function calls are made async, this
-         will likely be made the norm.  */
-      /* We cannot determine the contents of the structure because
-	 it is on the stack, and we don't know where, since we did not
-	 initiate the call, as opposed to the call_function_by_hand case */
+  /* FIXME: 2003-09-27: When returning from a nested inferior function
+     call, it's possible (with no help from the architecture vector)
+     to locate and return/print a "struct return" value.  This is just
+     a more complicated case of what is already being done in in the
+     inferior function call code.  In fact, when inferior function
+     calls are made async, this will likely be made the norm.  */
 #ifdef DEPRECATED_VALUE_RETURNED_FROM_STACK
-      value = 0;
+#define DEPRECATED_VALUE_RETURNED_FROM_STACK_P 1
+#else
+#define DEPRECATED_VALUE_RETURNED_FROM_STACK_P 0
+#endif
+  else if (gdbarch_return_value_p (current_gdbarch)
+	   || DEPRECATED_VALUE_RETURNED_FROM_STACK_P)
+    /* We cannot determine the contents of the structure because it is
+       on the stack, and we don't know where, since we did not
+       initiate the call, as opposed to the call_function_by_hand
+       case.  */
+    {
+      gdb_assert (gdbarch_return_value (current_gdbarch, value_type, NULL, NULL, NULL)
+		  == RETURN_VALUE_STRUCT_CONVENTION);
       ui_out_text (uiout, "Value returned has type: ");
       ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type));
       ui_out_text (uiout, ".");
       ui_out_text (uiout, " Cannot determine contents\n");
-#else
+      return;
+    }
+  else
+    {
       if (EXTRACT_STRUCT_VALUE_ADDRESS_P ())
 	{
 	  CORE_ADDR addr = EXTRACT_STRUCT_VALUE_ADDRESS (stop_registers);
@@ -1133,7 +1143,6 @@
       value_print (value, stb->stream, 0, Val_no_prettyprint);
       ui_out_field_stream (uiout, "return-value", stb);
       ui_out_text (uiout, "\n");
-#endif
     }
 }
 
Index: values.c
===================================================================
RCS file: /cvs/src/src/gdb/values.c,v
retrieving revision 1.59
diff -u -r1.59 values.c
--- values.c	2 Oct 2003 04:40:58 -0000	1.59
+++ values.c	2 Oct 2003 17:31:46 -0000
@@ -1216,11 +1216,22 @@
 register_value_being_returned (struct type *valtype, struct regcache *retbuf)
 {
   struct value *val = allocate_value (valtype);
-  CHECK_TYPEDEF (valtype);
+
   /* If the function returns void, don't bother fetching the return
      value.  */
-  if (TYPE_CODE (valtype) != TYPE_CODE_VOID)
-    EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val));
+  if (TYPE_CODE (valtype) == TYPE_CODE_VOID)
+    return val;
+
+  if (gdbarch_return_value_p (current_gdbarch))
+    {
+      gdb_assert (gdbarch_return_value (current_gdbarch, valtype, NULL, NULL, NULL)
+		  == RETURN_VALUE_REGISTER_CONVENTION);
+      gdbarch_return_value (current_gdbarch, valtype, retbuf,
+			    NULL, VALUE_CONTENTS_RAW (val));
+    }
+
+  CHECK_TYPEDEF (valtype);
+  EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val));
   return val;
 }
 
@@ -1262,6 +1273,16 @@
   if (code == TYPE_CODE_ERROR)
     error ("Function return type unknown.");
 
+  if (gdbarch_return_value_p (current_gdbarch))
+    {
+      /* Probe the architecture for the return-value convention.  */
+      return (gdbarch_return_value (current_gdbarch, value_type,
+				    NULL, NULL, NULL)
+	      == RETURN_VALUE_STRUCT_CONVENTION);
+    }
+
+  /* FIXME: cagney/2003-10-01: The below is dead.  Instead an
+     architecture should implement "gdbarch_return_value".  */
   if (code == TYPE_CODE_STRUCT
       || code == TYPE_CODE_UNION
       || code == TYPE_CODE_ARRAY
@@ -1284,9 +1305,29 @@
   if (code == TYPE_CODE_ERROR)
     error ("Function return type unknown.");
 
+  if (gdbarch_return_value_p (current_gdbarch))
+    {
+      switch (gdbarch_return_value (current_gdbarch, type, NULL, NULL, NULL))
+	{
+	case RETURN_VALUE_REGISTER_CONVENTION:
+	  /* Success.  The architecture can deal with it, write it to
+             the regcache.  */
+	  gdbarch_return_value (current_gdbarch, type, current_regcache,
+				VALUE_CONTENTS (val), NULL);
+	  return;
+	case RETURN_VALUE_STRUCT_CONVENTION:
+	  /* Failure.  For the moment, assume that it is not possible
+             to find the location, on the stack, at which the "struct
+             return" value should be stored.  */
+	  error ("Location of return value unknown");
+	}
+    }
+
+
   if (code == TYPE_CODE_STRUCT
-      || code == TYPE_CODE_UNION)	/* FIXME, implement struct return.  */
-    error ("GDB does not support specifying a struct or union return value.");
+      || code == TYPE_CODE_UNION)
+    /* The architecture needs to implement gdbarch_return_value.  */
+    internal_error (__FILE__, __LINE__, "This architecture does not yet support specifying a struct or union return value.");
 
   STORE_RETURN_VALUE (type, current_regcache, VALUE_CONTENTS (val));
 }
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v
retrieving revision 1.171
diff -u -r1.171 gdbint.texinfo
--- doc/gdbint.texinfo	30 Sep 2003 19:12:19 -0000	1.171
+++ doc/gdbint.texinfo	2 Oct 2003 17:31:49 -0000
@@ -3186,13 +3186,17 @@
 the raw register state @var{regbuf} and copy that, in virtual format,
 into @var{valbuf}.
  
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
+
 @item EXTRACT_STRUCT_VALUE_ADDRESS(@var{regbuf})
 @findex EXTRACT_STRUCT_VALUE_ADDRESS
+@anchor{EXTRACT_STRUCT_VALUE_ADDRESS}
 When defined, extract from the array @var{regbuf} (containing the raw
 register state) the @code{CORE_ADDR} at which a function should return
 its structure value.
 
-If not defined, @code{EXTRACT_RETURN_VALUE} is used.
+@xref{gdbarch_return_value}.
 
 @item EXTRACT_STRUCT_VALUE_ADDRESS_P()
 @findex EXTRACT_STRUCT_VALUE_ADDRESS_P
@@ -3785,6 +3789,48 @@
 Define this to convert sdb register numbers into @value{GDBN} regnums.  If not
 defined, no conversion will be done.
 
+@item enum return_value_convention gdbarch_return_value (struct gdbarch *@var{gdbarch}, struct type *@var{valtype}, struct regcache *@var{regcache}, const void *@var{inval}, void *@var{outval})
+@findex gdbarch_return_value
+@anchor{gdbarch_return_value} @value{GDBN} currently recognizes two
+function return-value conventions:
+@code{RETURN_VALUE_REGISTER_CONVENTION} where the return value is found
+in registers; and @code{RETURN_VALUE_STRUCT_CONVENTION} where the return
+value is found in memory and the address of that memory location is
+passed in as the function's first parameter.
+
+Given a function with a return-value of type @var{rettype}, return which
+return-value convention that function would use.
+
+If the register convention is being used, and @var{inval} is
+non-@code{NULL}, also copy the return-value in @var{inval} into
+@var{regcache}.
+
+If the register convention is being used, and @var{outval} is
+non-@code{NULL}, also copy the return value from @var{regcache} into
+@var{outval} (@var{regcache} contains a copy of the registers from the
+just returned function).
+
+@xref{EXTRACT_STRUCT_VALUE_ADDRESS}, for a description of how
+return-values that use the struct convention are handled.
+
+@emph{Maintainer note: This method replaces separate predicate, extract,
+store methods.  By having only one method, the logic needed to determine
+the return-value convention need only be implemented in one place.  If
+@value{GDBN} were written in an @sc{oo} language, this method would
+instead return an object that knew how to perform the register
+return-value extract and store.}
+
+@emph{Maintainer note: This method does not take a @var{gcc_p}
+parameter, and such a parameter should not be added.  If an architecture
+that requires per-compiler or per-function information be identified,
+then the replacement of @var{rettype} with @code{struct value}
+@var{function} should be persued.}
+
+@emph{Maintainer note: The @var{regcache} parameter limits this methods
+to the inner most frame.  While replacing @var{regcache} with a
+@code{struct frame_info} @var{frame} parameter would remove that
+limitation there has yet to be a demonstrated need for such a change.}
+
 @item SKIP_PERMANENT_BREAKPOINT
 @findex SKIP_PERMANENT_BREAKPOINT
 Advance the inferior's PC past a permanent breakpoint.  @value{GDBN} normally
@@ -3843,6 +3889,9 @@
 @var{valbuf}, into the @var{regcache}.  @var{type} is the type of the
 value that is to be returned.
 
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
+
 @item SUN_FIXED_LBRAC_BUG
 @findex SUN_FIXED_LBRAC_BUG
 (Used only for Sun-3 and Sun-4 targets.)
@@ -3977,6 +4026,9 @@
 being considered is known to have been compiled by GCC; this is helpful
 for systems where GCC is known to use different calling convention than
 other compilers.
+
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
 
 @item VALUE_TO_REGISTER(@var{type}, @var{regnum}, @var{from}, @var{to})
 @findex VALUE_TO_REGISTER

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