This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[patch/rfc, rfa:doco] gdbarch return value
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Thu, 02 Oct 2003 13:40:27 -0400
- Subject: [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,
®val);
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