This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[wip] return value architecture method
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Sun, 28 Sep 2003 12:53:54 -0400
- Subject: [wip] return value architecture method
Hello,
This is a work-in-progress version of a "return_value" architecture
method. This new method replaces:
USE_STRUCT_CONVENTION
STORE_RETURN_VALUE
EXTRACT_RETURN_VALUE
RETURN_VALUE_ON_STACK
The idea, as illustrated in my recent patch to ppc64:
http://sources.redhat.com/ml/gdb-patches/2003-09/msg00435.html
is to put all the logic needed to determine how return values are
handled is written only once.
Notes:
I need to write doco.
It doesn't try to replace EXTRACT_STRUCT_VALUE_ADDRESS. I'm not sure
what to do with that one. I've a strong suspision that the
architectures that do implement it are actually broken - the callee
invalidates the register that contains the needed address so this
function can't work. The change does at least clean up the logic
though, only calling EXTRACT_STRUCT_VALUE_ADDRESS after consulting
RETURN_VALUE.
This doesn't take a GCC_P parameter, but still takes the function's
return type. There's a proposal to pass a function "struct value"
instead of the return type, but I think that can/should be made separatly.
At present it is modifying value_being_returned. As noted in another
post, some of this logic is going to be moved to print_return_value so
the final post will end up tweaking that as well.
This also finally makes it possible to fix:
http://sources.redhat.com/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=659
along with many many other cases where GDB was incorrectly claiming that
it wasn't able to find a return value.
anyway, thoughts?
Andrew
2003-09-28 Andrew Cagney <cagney@redhat.com>
* values.c (value_being_returned): Use "gdbarch_return_value" when
available.
(set_return_value): Ditto.
* defs.h (return_value_convention): Define.
* gdbarch.sh (gdbarch_return_value): New predicate method.
* gdbarch.h, gdbarch.c: Re-generate
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 28 Sep 2003 16:19:47 -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.272
diff -u -r1.272 gdbarch.sh
--- gdbarch.sh 18 Sep 2003 22:39:21 -0000 1.272
+++ gdbarch.sh 28 Sep 2003 16:20:11 -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: values.c
===================================================================
RCS file: /cvs/src/src/gdb/values.c,v
retrieving revision 1.57
diff -u -r1.57 values.c
--- values.c 21 Sep 2003 01:26:45 -0000 1.57
+++ values.c 28 Sep 2003 16:20:14 -0000
@@ -1216,18 +1216,60 @@
0 when it is using the value returning conventions (this often
means returning pointer to where structure is vs. returning value). */
+/* FIXME: cagney/2003-09-27: The parameter "struct_return" here is
+ totally redundant. It's value can be determined from "valtype" and
+ a call to gdbarch_return_value (nee using_struct_return). */
+
struct value *
value_being_returned (struct type *valtype, struct regcache *retbuf,
int struct_return)
{
struct value *val;
- CORE_ADDR addr;
+
+ if (gdbarch_return_value_p (current_gdbarch))
+ {
+ /* If the function returns void, don't bother fetching the
+ return value. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_VOID)
+ return allocate_value (valtype);
+
+ /* See if the architecture can find the return value. */
+ switch (gdbarch_return_value (current_gdbarch, valtype,
+ NULL, NULL, NULL))
+ {
+ case RETURN_VALUE_REGISTER_CONVENTION:
+ /* Register values are always found. */
+ gdbarch_return_value (current_gdbarch, valtype, retbuf,
+ NULL, VALUE_CONTENTS_RAW (val));
+ return val;
+ case RETURN_VALUE_STRUCT_CONVENTION:
+ /* NOTE: Being able to find a value being returned using
+ "struct convention" is very very a-typical. This is
+ because the ABI typically passes the address in via a
+ scratch register and by the time GDB tries to find that
+ register's value, it has well and truely been lost. */
+ if (EXTRACT_STRUCT_VALUE_ADDRESS_P ())
+ {
+ CORE_ADDR struct_addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf);
+ if (struct_addr != 0)
+ return value_at (valtype, struct_addr, NULL);
+ }
+ /* FIXME: cagney/2003-09-27: Was this a nested inferior
+ function call? If it was, it is still possible to find
+ the return value - but of course this assumes that the
+ STRUCT_ADDR has previously been saved in the inferior
+ function call stack. */
+ error ("Function return value unknown.");
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
/* If this is not defined, just use EXTRACT_RETURN_VALUE instead. */
if (EXTRACT_STRUCT_VALUE_ADDRESS_P ())
if (struct_return)
{
- addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf);
+ CORE_ADDR addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf);
if (!addr)
error ("Function return value unknown.");
return value_at (valtype, addr, NULL);
@@ -1238,7 +1280,7 @@
if (struct_return)
{
char *buf = deprecated_grub_regcache_for_registers (retbuf);
- addr = DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (buf);
+ CORE_ADDR addr = DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (buf);
if (!addr)
error ("Function return value unknown.");
return value_at (valtype, addr, NULL);
@@ -1291,6 +1333,14 @@
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);
+ }
+
if (code == TYPE_CODE_STRUCT
|| code == TYPE_CODE_UNION
|| code == TYPE_CODE_ARRAY
@@ -1312,6 +1362,25 @@
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. */