From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4722 invoked by alias); 3 Oct 2003 21:10:05 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 4702 invoked from network); 3 Oct 2003 21:10:03 -0000 Received: from unknown (HELO localhost.redhat.com) (66.30.197.194) by sources.redhat.com with SMTP; 3 Oct 2003 21:10:03 -0000 Received: from redhat.com (localhost [127.0.0.1]) by localhost.redhat.com (Postfix) with ESMTP id 3C6482B89; Fri, 3 Oct 2003 17:10:03 -0400 (EDT) Message-ID: <3F7DE5AB.7000904@redhat.com> Date: Fri, 03 Oct 2003 21:10:00 -0000 From: Andrew Cagney User-Agent: Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.0.2) Gecko/20030820 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Kevin Buettner Cc: gdb-patches@sources.redhat.com Subject: Re: [rfa:ppc64] Fix return value References: <3F6CF27D.9040500@redhat.com> <1030922232300.ZM30081@localhost.localdomain> Content-Type: multipart/mixed; boundary="------------010407000104070401020100" X-SW-Source: 2003-10/txt/msg00058.txt.bz2 This is a multi-part message in MIME format. --------------010407000104070401020100 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-length: 755 > On Sep 20, 8:36pm, Andrew Cagney wrote: > > >> Note the way I implemented it - the above wrap a generic >> ppc64_sysv_abi_return_value function and that handles all cases. I was > > > Nice. > > >> finding that the more traditional technique (per my ppc post) was too >> error proned. Converting it to this style caused several mysterious >> regressions to mysteriously disappear. >> >> I'm thinking of proposing that this technique become the norm. >> >> Anyway, ok to commit? > > > Yes, okay. I've committed it with one tweak. The ..._return_value() method now returns "enum return_value_convention" instead of an int. This is to better align its function signature with the new gdbarch_return_value method I've posted. Andrew --------------010407000104070401020100 Content-Type: text/plain; name="diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diffs" Content-length: 10131 2003-10-03 Andrew Cagney * rs6000-tdep.c (rs6000_gdbarch_init): When the 64 bit SysV ABI, set extract_return_value, store_return_value and use_struct_convention to ppc64_sysv_abi_extract_return_value, ppc64_sysv_abi_store_return_value and ppc64_sysv_abi_use_struct_convention. * ppc-tdep.h (ppc64_sysv_abi_extract_return_value): Declare. (ppc64_sysv_abi_store_return_value): Declare. (ppc64_sysv_abi_use_struct_convention): Declare. * ppc-sysv-tdep.c (enum return_value_convention): Define. (ppc64_sysv_abi_extract_return_value): New function. (ppc64_sysv_abi_store_return_value): New function. (ppc64_sysv_abi_use_struct_convention): New function. (ppc64_sysv_abi_return_value): New function. Index: ppc-sysv-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v retrieving revision 1.12 diff -u -r1.12 ppc-sysv-tdep.c --- ppc-sysv-tdep.c 19 Sep 2003 16:22:39 -0000 1.12 +++ ppc-sysv-tdep.c 3 Oct 2003 21:02:58 -0000 @@ -325,3 +325,197 @@ return (TYPE_LENGTH (value_type) > 8); } + + +/* The 64 bit ABI retun value convention. + + Return non-zero if the return-value is stored in a register, return + 0 if the return-value is instead stored on the stack (a.k.a., + struct return convention). + + For a return-value stored in a register: when INVAL is non-NULL, + 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, + 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; + } + /* All pointers live in r3. */ + if (TYPE_CODE (valtype) == TYPE_CODE_PTR) + { + /* All pointers live in r3. */ + if (inval != NULL) + regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, inval); + if (outval != NULL) + regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, outval); + return RETURN_VALUE_REGISTER_CONVENTION; + } + if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY + && TYPE_LENGTH (valtype) <= 8 + && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT + && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1) + { + /* Small character arrays are returned, right justified, in r3. */ + int offset = (register_size (current_gdbarch, tdep->ppc_gp0_regnum + 3) + - TYPE_LENGTH (valtype)); + if (inval != NULL) + regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3, + offset, TYPE_LENGTH (valtype), inval); + if (outval != NULL) + regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3, + offset, TYPE_LENGTH (valtype), outval); + return RETURN_VALUE_REGISTER_CONVENTION; + } + /* Big floating point values get stored in adjacent floating + point registers. */ + if (TYPE_CODE (valtype) == TYPE_CODE_FLT + && (TYPE_LENGTH (valtype) == 16 + || TYPE_LENGTH (valtype) == 32)) + { + if (inval || outval != NULL) + { + int i; + for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++) + { + if (inval != NULL) + regcache_cooked_write (regcache, FP0_REGNUM + 1 + i, + (const bfd_byte *) inval + i * 8); + if (outval != NULL) + regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, + (bfd_byte *) outval + i * 8); + } + } + return RETURN_VALUE_REGISTER_CONVENTION; + } + /* Complex values get returned in f1:f2, need to convert. */ + if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX + && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16)) + { + if (regcache != NULL) + { + int i; + for (i = 0; i < 2; i++) + { + char regval[MAX_REGISTER_SIZE]; + struct type *regtype = register_type (current_gdbarch, FP0_REGNUM); + if (inval != NULL) + { + convert_typed_floating ((const bfd_byte *) inval + i * (TYPE_LENGTH (valtype) / 2), + valtype, regval, regtype); + regcache_cooked_write (regcache, FP0_REGNUM + 1 + i, regval); + } + if (outval != NULL) + { + regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval); + convert_typed_floating (regval, regtype, + (bfd_byte *) outval + i * (TYPE_LENGTH (valtype) / 2), + valtype); + } + } + } + return RETURN_VALUE_REGISTER_CONVENTION; + } + /* Big complex values get stored in f1:f4. */ + if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX + && TYPE_LENGTH (valtype) == 32) + { + if (regcache != NULL) + { + int i; + for (i = 0; i < 4; i++) + { + if (inval != NULL) + regcache_cooked_write (regcache, FP0_REGNUM + 1 + i, + (const bfd_byte *) inval + i * 8); + if (outval != NULL) + regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, + (bfd_byte *) outval + i * 8); + } + } + return RETURN_VALUE_REGISTER_CONVENTION; + } + return RETURN_VALUE_STRUCT_CONVENTION; +} + +int +ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type) +{ + return (ppc64_sysv_abi_return_value (value_type, NULL, NULL, NULL) + == RETURN_VALUE_STRUCT_CONVENTION); +} + +void +ppc64_sysv_abi_extract_return_value (struct type *valtype, + struct regcache *regbuf, + void *valbuf) +{ + if (ppc64_sysv_abi_return_value (valtype, regbuf, NULL, valbuf) + != RETURN_VALUE_REGISTER_CONVENTION) + error ("Function return value unknown"); +} + +void +ppc64_sysv_abi_store_return_value (struct type *valtype, + struct regcache *regbuf, + const void *valbuf) +{ + if (!ppc64_sysv_abi_return_value (valtype, regbuf, valbuf, NULL)) + error ("Function return value location unknown"); +} Index: ppc-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/ppc-tdep.h,v retrieving revision 1.18 diff -u -r1.18 ppc-tdep.h --- ppc-tdep.h 14 Sep 2003 02:04:44 -0000 1.18 +++ ppc-tdep.h 3 Oct 2003 21:02:58 -0000 @@ -47,6 +47,14 @@ void ppc_linux_supply_gregset (char *buf); void ppc_linux_supply_fpregset (char *buf); +int ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type); +void ppc64_sysv_abi_extract_return_value (struct type *valtype, + struct regcache *regbuf, + void *valbuf); +void ppc64_sysv_abi_store_return_value (struct type *valtype, + struct regcache *regbuf, + const void *valbuf); + /* From rs6000-tdep.c... */ CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi); Index: rs6000-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v retrieving revision 1.165 diff -u -r1.165 rs6000-tdep.c --- rs6000-tdep.c 2 Oct 2003 20:28:30 -0000 1.165 +++ rs6000-tdep.c 3 Oct 2003 21:02:59 -0000 @@ -2830,9 +2830,16 @@ set_gdbarch_pc_regnum (gdbarch, 64); set_gdbarch_sp_regnum (gdbarch, 1); set_gdbarch_deprecated_fp_regnum (gdbarch, 1); - set_gdbarch_deprecated_extract_return_value (gdbarch, - rs6000_extract_return_value); - set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value); + if (sysv_abi && wordsize == 8) + { + 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 + { + set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value); + set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value); + } if (v->arch == bfd_arch_powerpc) switch (v->mach) @@ -2967,9 +2974,11 @@ /* Not sure on this. FIXMEmgo */ set_gdbarch_frame_args_skip (gdbarch, 8); - if (sysv_abi) + if (sysv_abi && wordsize == 4) set_gdbarch_use_struct_convention (gdbarch, ppc_sysv_abi_use_struct_convention); + else if (sysv_abi && wordsize == 8) + set_gdbarch_use_struct_convention (gdbarch, ppc64_sysv_abi_use_struct_convention); else set_gdbarch_use_struct_convention (gdbarch, rs6000_use_struct_convention); --------------010407000104070401020100--