From c5e656c1c7ab1e26ead1530b708af08ac272b95d Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Thu, 20 Nov 2003 22:37:50 +0000 Subject: [PATCH] * i386-tdep.c (i386_extract_return_value, i386_store_return_value): Add gdbarch argument. Use it instead of determining it from REGCACHE. Remove recursive call for structures with a single member. (i386_use_struct_convention): Remove. (i386_reg_struct_return_p): New function. (i386_return_value): New function. (i386_gdbarch_init): Set return_value, don't set extract_return_value, store_return_value and use_struct_convention. * x86-64-tdep.c (x86_64_init_abi): Set return_value to NULL. --- gdb/ChangeLog | 14 +++++++ gdb/i386-tdep.c | 101 +++++++++++++++++++++++++++++----------------- gdb/x86-64-tdep.c | 1 + 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index daa22a604b..400b025309 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2003-11-20 Mark Kettenis + + * i386-tdep.c (i386_extract_return_value, + i386_store_return_value): Add gdbarch argument. Use it instead of + determining it from REGCACHE. Remove recursive call for + structures with a single member. + (i386_use_struct_convention): Remove. + (i386_reg_struct_return_p): New function. + (i386_return_value): New function. + (i386_gdbarch_init): Set return_value, don't set + extract_return_value, store_return_value and + use_struct_convention. + * x86-64-tdep.c (x86_64_init_abi): Set return_value to NULL. + 2003-11-20 Jim Blandy * osabi.c (_initialize_gdb_osabi): Don't return before registering diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 120b78cff2..973fa63e43 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -1151,25 +1151,17 @@ i386_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, #define LOW_RETURN_REGNUM I386_EAX_REGNUM /* %eax */ #define HIGH_RETURN_REGNUM I386_EDX_REGNUM /* %edx */ -/* Extract from an array REGBUF containing the (raw) register state, a - function return value of TYPE, and copy that, in virtual format, - into VALBUF. */ +/* Read, for architecture GDBARCH, a function return value of TYPE + from REGCACHE, and copy that into VALBUF. */ static void -i386_extract_return_value (struct type *type, struct regcache *regcache, - void *valbuf) +i386_extract_return_value (struct gdbarch *gdbarch, struct type *type, + struct regcache *regcache, void *valbuf) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); int len = TYPE_LENGTH (type); char buf[I386_MAX_REGISTER_SIZE]; - if (TYPE_CODE (type) == TYPE_CODE_STRUCT - && TYPE_NFIELDS (type) == 1) - { - i386_extract_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf); - return; - } - if (TYPE_CODE (type) == TYPE_CODE_FLT) { if (tdep->st0_regnum < 0) @@ -1209,27 +1201,20 @@ i386_extract_return_value (struct type *type, struct regcache *regcache, } } -/* Write into the appropriate registers a function return value stored - in VALBUF of type TYPE, given in virtual format. */ +/* Write, for architecture GDBARCH, a function return value of TYPE + from VALBUF into REGCACHE. */ static void -i386_store_return_value (struct type *type, struct regcache *regcache, - const void *valbuf) +i386_store_return_value (struct gdbarch *gdbarch, struct type *type, + struct regcache *regcache, const void *valbuf) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); int len = TYPE_LENGTH (type); /* Define I387_ST0_REGNUM such that we use the proper definitions for the architecture. */ #define I387_ST0_REGNUM I386_ST0_REGNUM - if (TYPE_CODE (type) == TYPE_CODE_STRUCT - && TYPE_NFIELDS (type) == 1) - { - i386_store_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf); - return; - } - if (TYPE_CODE (type) == TYPE_CODE_FLT) { ULONGEST fstat; @@ -1314,20 +1299,62 @@ static const char *valid_conventions[] = }; static const char *struct_convention = default_struct_convention; +/* Return non-zero if TYPE, which is assumed to be a structure or + union type, should be returned in registers for architecture + GDBARCH. */ + static int -i386_use_struct_convention (int gcc_p, struct type *type) +i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) { - enum struct_return struct_return; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum type_code code = TYPE_CODE (type); + int len = TYPE_LENGTH (type); - if (struct_convention == default_struct_convention) - struct_return = gdbarch_tdep (current_gdbarch)->struct_return; - else if (struct_convention == pcc_struct_convention) - struct_return = pcc_struct_return; - else - struct_return = reg_struct_return; + gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION); - return generic_use_struct_convention (struct_return == reg_struct_return, - type); + if (struct_convention == pcc_struct_convention + || (struct_convention == default_struct_convention + && tdep->struct_return == pcc_struct_return)) + return 0; + + return (len == 1 || len == 2 || len == 4 || len == 8); +} + +/* Determine, for architecture GDBARCH, how a return value of TYPE + should be returned. If it is supposed to be returned in registers, + and READBUF is non-zero, read the appropriate value from REGCACHE, + and copy it into READBUF. If WRITEBUF is non-zero, write the value + from WRITEBUF into REGCACHE. */ + +static enum return_value_convention +i386_return_value (struct gdbarch *gdbarch, struct type *type, + struct regcache *regcache, void *readbuf, + const void *writebuf) +{ + enum type_code code = TYPE_CODE (type); + + if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) + && !i386_reg_struct_return_p (gdbarch, type)) + return RETURN_VALUE_STRUCT_CONVENTION; + + /* This special case is for structures consisting of a single + `float' or `double' member. These structures are returned in + %st(0). For these structures, we call ourselves recursively, + changing TYPE into the type of the first member of the structure. + Since that should work for all structures that have only one + member, we don't bother to check the member's type here. */ + if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1) + { + type = check_typedef (TYPE_FIELD_TYPE (type, 0)); + return i386_return_value (gdbarch, type, regcache, readbuf, writebuf); + } + + if (readbuf) + i386_extract_return_value (gdbarch, type, regcache, readbuf); + if (writebuf) + i386_store_return_value (gdbarch, type, regcache, writebuf); + + return RETURN_VALUE_REGISTER_CONVENTION; } @@ -1963,11 +1990,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_register_to_value (gdbarch, i386_register_to_value); set_gdbarch_value_to_register (gdbarch, i386_value_to_register); - set_gdbarch_extract_return_value (gdbarch, i386_extract_return_value); - set_gdbarch_store_return_value (gdbarch, i386_store_return_value); + set_gdbarch_return_value (gdbarch, i386_return_value); set_gdbarch_extract_struct_value_address (gdbarch, i386_extract_struct_value_address); - set_gdbarch_use_struct_convention (gdbarch, i386_use_struct_convention); set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue); diff --git a/gdb/x86-64-tdep.c b/gdb/x86-64-tdep.c index 5e6a7e1a2c..5f485abeef 100644 --- a/gdb/x86-64-tdep.c +++ b/gdb/x86-64-tdep.c @@ -1300,6 +1300,7 @@ x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_register_to_value (gdbarch, i387_register_to_value); set_gdbarch_value_to_register (gdbarch, i387_value_to_register); + set_gdbarch_return_value (gdbarch, NULL); set_gdbarch_extract_return_value (gdbarch, x86_64_extract_return_value); set_gdbarch_store_return_value (gdbarch, x86_64_store_return_value); /* Override, since this is handled by x86_64_extract_return_value. */