diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2012-05-16 14:35:09 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@linux-mips.org> | 2012-05-16 14:35:09 +0000 |
commit | 6a3a010ba62de90c4fb166550a6bcff4782542db (patch) | |
tree | 1bb049f951dc805ada9d03df84a57bdaa00ce652 /gdb/mips-tdep.c | |
parent | 691bf19c4ea5b2f5d615c4116649daf32f81cc7d (diff) | |
download | gdb-6a3a010ba62de90c4fb166550a6bcff4782542db.zip gdb-6a3a010ba62de90c4fb166550a6bcff4782542db.tar.gz gdb-6a3a010ba62de90c4fb166550a6bcff4782542db.tar.bz2 |
gdb/
* breakpoint.h (bp_location): Add related_address member.
* inferior.h (get_return_value): Take a pointer to struct value
instead of struct type for the function requested.
* value.h (using_struct_return): Likewise.
* gdbarch.sh (return_value): Take a pointer to struct value
instead of struct type for the function requested.
* breakpoint.c (set_breakpoint_location_function): Initialize
related_address for bp_gnu_ifunc_resolver breakpoints.
* elfread.c (elf_gnu_ifunc_resolver_return_stop): Pass the
requested function's address to gdbarch_return_value.
* eval.c (evaluate_subexp_standard): Pass the requested
function's address to using_struct_return.
* infcall.c (call_function_by_hand): Pass the requested
function's address to using_struct_return and
gdbarch_return_value.
* infcmd.c (get_return_value): Take a pointer to struct value
instead of struct type for the function requested.
(print_return_value): Update accordingly.
(finish_command_continuation): Likewise.
* stack.c (return_command): Pass the requested function's
address to using_struct_return and gdbarch_return_value.
* value.c (using_struct_return): Take a pointer to struct value
instead of struct type for the function requested. Pass the
requested function's address to gdbarch_return_value.
* python/py-finishbreakpoint.c (finish_breakpoint_object):
New function_value member, replacing function_type.
(bpfinishpy_dealloc): Update accordingly.
(bpfinishpy_pre_stop_hook): Likewise.
(bpfinishpy_init): Likewise. Record the requested function's
address.
* mips-tdep.c (mips_fval_reg): New enum.
(mips_o32_push_dummy_call): For MIPS16 FP doubles do not swap
words put in GP registers.
(mips_o64_push_dummy_call): Update a comment.
(mips_o32_return_value): Take a pointer to struct value instead
of struct type for the function requested and use it to check if
using the MIPS16 calling convention. Return the designated
general purpose registers for floating-point values returned in
MIPS16 mode.
(mips_o64_return_value): Likewise.
* ppc-tdep.h (ppc_sysv_abi_return_value): Update prototype.
(ppc_sysv_abi_broken_return_value): Likewise.
(ppc64_sysv_abi_return_value): Likewise.
* alpha-tdep.c (alpha_return_value): Take a pointer to struct
value instead of struct type for the function requested.
* amd64-tdep.c (amd64_return_value): Likewise.
* amd64-windows-tdep.c (amd64_windows_return_value): Likewise.
* arm-tdep.c (arm_return_value): Likewise.
* avr-tdep.c (avr_return_value): Likewise.
* bfin-tdep.c (bfin_return_value): Likewise.
* cris-tdep.c (cris_return_value): Likewise.
* frv-tdep.c (frv_return_value): Likewise.
* h8300-tdep.c (h8300_return_value): Likewise.
(h8300h_return_value): Likewise.
* hppa-tdep.c (hppa32_return_value): Likewise.
(hppa64_return_value): Likewise.
* i386-tdep.c (i386_return_value): Likewise.
* ia64-tdep.c (ia64_return_value): Likewise.
* iq2000-tdep.c (iq2000_return_value): Likewise.
* lm32-tdep.c (lm32_return_value): Likewise.
* m32c-tdep.c (m32c_return_value): Likewise.
* m32r-tdep.c (m32r_return_value): Likewise.
* m68hc11-tdep.c (m68hc11_return_value): Likewise.
* m68k-tdep.c (m68k_return_value): Likewise.
(m68k_svr4_return_value): Likewise.
* m88k-tdep.c (m88k_return_value): Likewise.
* mep-tdep.c (mep_return_value): Likewise.
* microblaze-tdep.c (microblaze_return_value): Likewise.
* mn10300-tdep.c (mn10300_return_value): Likewise.
* moxie-tdep.c (moxie_return_value): Likewise.
* mt-tdep.c (mt_return_value): Likewise.
* ppc-linux-tdep.c (ppc_linux_return_value): Likewise.
* ppc-sysv-tdep.c (ppc_sysv_abi_return_value): Likewise.
(ppc_sysv_abi_broken_return_value): Likewise.
(ppc64_sysv_abi_return_value): Likewise.
* ppcnbsd-tdep.c (ppcnbsd_return_value): Likewise.
* rl78-tdep.c (rl78_return_value): Likewise.
* rs6000-aix-tdep.c (rs6000_return_value): Likewise.
* rx-tdep.c (rx_return_value): Likewise.
* s390-tdep.c (s390_return_value): Likewise.
* score-tdep.c (score_return_value): Likewise.
* sh-tdep.c (sh_return_value_nofpu): Likewise.
(sh_return_value_fpu): Likewise.
* sh64-tdep.c (sh64_return_value): Likewise.
* sparc-tdep.c (sparc32_return_value): Likewise.
* sparc64-tdep.c (sparc64_return_value): Likewise.
* spu-tdep.c (spu_return_value): Likewise.
* tic6x-tdep.c (tic6x_return_value): Likewise.
* v850-tdep.c (v850_return_value): Likewise.
* vax-tdep.c (vax_return_value): Likewise.
* xstormy16-tdep.c (xstormy16_return_value): Likewise.
* xtensa-tdep.c (xtensa_return_value): Likewise.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
gdb/testsuite/
* gdb.base/return-nodebug.exp: Also test float and double types.
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 258 |
1 files changed, 180 insertions, 78 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index d68782c..28fec27 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -3332,7 +3332,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Determine the return value convention being used. */ static enum return_value_convention -mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type, +mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { @@ -3722,7 +3722,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } static enum return_value_convention -mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type, +mips_n32n64_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { @@ -3890,6 +3890,20 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type, } } +/* Which registers to use for passing floating-point values between + function calls, one of floating-point, general and both kinds of + registers. O32 and O64 use different register kinds for standard + MIPS and MIPS16 code; to make the handling of cases where we may + not know what kind of code is being used (e.g. no debug information) + easier we sometimes use both kinds. */ + +enum mips_fval_reg +{ + mips_fval_fpr, + mips_fval_gpr, + mips_fval_both +}; + /* O32 ABI stuff. */ static CORE_ADDR @@ -3980,8 +3994,8 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* 32-bit ABIs always start floating point arguments in an even-numbered floating point register. Round the FP register up before the check to see if there are any FP registers - left. O32/O64 targets also pass the FP in the integer - registers so also round up normal registers. */ + left. O32 targets also pass the FP in the integer registers + so also round up normal registers. */ if (fp_register_arg_p (gdbarch, typecode, arg_type)) { if ((float_argreg & 1)) @@ -3989,46 +4003,48 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } /* Floating point arguments passed in registers have to be - treated specially. On 32-bit architectures, doubles - are passed in register pairs; the even register gets - the low word, and the odd register gets the high word. - On O32/O64, the first two floating point arguments are - also copied to general registers, because MIPS16 functions - don't use float registers for arguments. This duplication of - arguments in general registers can't hurt non-MIPS16 functions - because those registers are normally skipped. */ + treated specially. On 32-bit architectures, doubles are + passed in register pairs; the even FP register gets the + low word, and the odd FP register gets the high word. + On O32, the first two floating point arguments are also + copied to general registers, following their memory order, + because MIPS16 functions don't use float registers for + arguments. This duplication of arguments in general + registers can't hurt non-MIPS16 functions, because those + registers are normally skipped. */ if (fp_register_arg_p (gdbarch, typecode, arg_type) && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch)) { if (register_size (gdbarch, float_argreg) < 8 && len == 8) { - int low_offset = gdbarch_byte_order (gdbarch) - == BFD_ENDIAN_BIG ? 4 : 0; + int freg_offset = gdbarch_byte_order (gdbarch) + == BFD_ENDIAN_BIG ? 1 : 0; unsigned long regval; - /* Write the low word of the double to the even register(s). */ - regval = extract_unsigned_integer (val + low_offset, - 4, byte_order); + /* First word. */ + regval = extract_unsigned_integer (val, 4, byte_order); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s", - float_argreg, phex (regval, 4)); + float_argreg + freg_offset, + phex (regval, 4)); regcache_cooked_write_unsigned (regcache, - float_argreg++, regval); + float_argreg++ + freg_offset, + regval); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s", argreg, phex (regval, 4)); regcache_cooked_write_unsigned (regcache, argreg++, regval); - /* Write the high word of the double to the odd register(s). */ - regval = extract_unsigned_integer (val + 4 - low_offset, - 4, byte_order); + /* Second word. */ + regval = extract_unsigned_integer (val + 4, 4, byte_order); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s", - float_argreg, phex (regval, 4)); + float_argreg - freg_offset, + phex (regval, 4)); regcache_cooked_write_unsigned (regcache, - float_argreg++, regval); - + float_argreg++ - freg_offset, + regval); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s", argreg, phex (regval, 4)); @@ -4203,12 +4219,16 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } static enum return_value_convention -mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type, +mips_o32_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { + CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0; struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int mips16 = mips_pc_is_mips16 (func_addr); + enum mips_fval_reg fval_reg; + fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both; if (TYPE_CODE (type) == TYPE_CODE_STRUCT || TYPE_CODE (type) == TYPE_CODE_UNION || TYPE_CODE (type) == TYPE_CODE_ARRAY) @@ -4216,54 +4236,110 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type, else if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 4 && tdep->mips_fpu_type != MIPS_FPU_NONE) { - /* A single-precision floating-point value. It fits in the - least significant part of FP0. */ + /* A single-precision floating-point value. If reading in or copying, + then we get it from/put it to FP0 for standard MIPS code or GPR2 + for MIPS16 code. If writing out only, then we put it to both FP0 + and GPR2. We do not support reading in with no function known, if + this safety check ever triggers, then we'll have to try harder. */ + gdb_assert (function || !readbuf); if (mips_debug) - fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n"); - mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0), - TYPE_LENGTH (type), - gdbarch_byte_order (gdbarch), - readbuf, writebuf, 0); + switch (fval_reg) + { + case mips_fval_fpr: + fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n"); + break; + case mips_fval_gpr: + fprintf_unfiltered (gdb_stderr, "Return float in $2\n"); + break; + case mips_fval_both: + fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n"); + break; + } + if (fval_reg != mips_fval_gpr) + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0), + TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + if (fval_reg != mips_fval_fpr) + mips_xfer_register (gdbarch, regcache, + gdbarch_num_regs (gdbarch) + 2, + TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); return RETURN_VALUE_REGISTER_CONVENTION; } else if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8 && tdep->mips_fpu_type != MIPS_FPU_NONE) { - /* A double-precision floating-point value. The most - significant part goes in FP1, and the least significant in - FP0. */ + /* A double-precision floating-point value. If reading in or copying, + then we get it from/put it to FP1 and FP0 for standard MIPS code or + GPR2 and GPR3 for MIPS16 code. If writing out only, then we put it + to both FP1/FP0 and GPR2/GPR3. We do not support reading in with + no function known, if this safety check ever triggers, then we'll + have to try harder. */ + gdb_assert (function || !readbuf); if (mips_debug) - fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n"); - switch (gdbarch_byte_order (gdbarch)) + switch (fval_reg) + { + case mips_fval_fpr: + fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n"); + break; + case mips_fval_gpr: + fprintf_unfiltered (gdb_stderr, "Return float in $2/$3\n"); + break; + case mips_fval_both: + fprintf_unfiltered (gdb_stderr, + "Return float in $fp1/$fp0 and $2/$3\n"); + break; + } + if (fval_reg != mips_fval_gpr) { - case BFD_ENDIAN_LITTLE: - mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0 + 0), - 4, gdbarch_byte_order (gdbarch), - readbuf, writebuf, 0); - mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0 + 1), - 4, gdbarch_byte_order (gdbarch), - readbuf, writebuf, 4); - break; - case BFD_ENDIAN_BIG: + /* The most significant part goes in FP1, and the least significant + in FP0. */ + switch (gdbarch_byte_order (gdbarch)) + { + case BFD_ENDIAN_LITTLE: + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0 + 0), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0 + 1), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 4); + break; + case BFD_ENDIAN_BIG: + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0 + 1), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0 + 0), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 4); + break; + default: + internal_error (__FILE__, __LINE__, _("bad switch")); + } + } + if (fval_reg != mips_fval_fpr) + { + /* The two 32-bit parts are always placed in GPR2 and GPR3 + following these registers' memory order. */ mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0 + 1), + gdbarch_num_regs (gdbarch) + 2, 4, gdbarch_byte_order (gdbarch), readbuf, writebuf, 0); mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0 + 0), + gdbarch_num_regs (gdbarch) + 3, 4, gdbarch_byte_order (gdbarch), readbuf, writebuf, 4); - break; - default: - internal_error (__FILE__, __LINE__, _("bad switch")); } return RETURN_VALUE_REGISTER_CONVENTION; } @@ -4459,14 +4535,14 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } /* Floating point arguments passed in registers have to be - treated specially. On 32-bit architectures, doubles - are passed in register pairs; the even register gets - the low word, and the odd register gets the high word. - On O32/O64, the first two floating point arguments are - also copied to general registers, because MIPS16 functions - don't use float registers for arguments. This duplication of - arguments in general registers can't hurt non-MIPS16 functions - because those registers are normally skipped. */ + treated specially. On 32-bit architectures, doubles are + passed in register pairs; the even FP register gets the + low word, and the odd FP register gets the high word. + On O64, the first two floating point arguments are also + copied to general registers, because MIPS16 functions + don't use float registers for arguments. This duplication + of arguments in general registers can't hurt non-MIPS16 + functions because those registers are normally skipped. */ if (fp_register_arg_p (gdbarch, typecode, arg_type) && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch)) @@ -4611,28 +4687,54 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } static enum return_value_convention -mips_o64_return_value (struct gdbarch *gdbarch, struct type *func_type, +mips_o64_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { + CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0; struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int mips16 = mips_pc_is_mips16 (func_addr); + enum mips_fval_reg fval_reg; + fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both; if (TYPE_CODE (type) == TYPE_CODE_STRUCT || TYPE_CODE (type) == TYPE_CODE_UNION || TYPE_CODE (type) == TYPE_CODE_ARRAY) return RETURN_VALUE_STRUCT_CONVENTION; else if (fp_register_arg_p (gdbarch, TYPE_CODE (type), type)) { - /* A floating-point value. It fits in the least significant - part of FP0. */ + /* A floating-point value. If reading in or copying, then we get it + from/put it to FP0 for standard MIPS code or GPR2 for MIPS16 code. + If writing out only, then we put it to both FP0 and GPR2. We do + not support reading in with no function known, if this safety + check ever triggers, then we'll have to try harder. */ + gdb_assert (function || !readbuf); if (mips_debug) - fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n"); - mips_xfer_register (gdbarch, regcache, - (gdbarch_num_regs (gdbarch) - + mips_regnum (gdbarch)->fp0), - TYPE_LENGTH (type), - gdbarch_byte_order (gdbarch), - readbuf, writebuf, 0); + switch (fval_reg) + { + case mips_fval_fpr: + fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n"); + break; + case mips_fval_gpr: + fprintf_unfiltered (gdb_stderr, "Return float in $2\n"); + break; + case mips_fval_both: + fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n"); + break; + } + if (fval_reg != mips_fval_gpr) + mips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + mips_regnum (gdbarch)->fp0), + TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + if (fval_reg != mips_fval_fpr) + mips_xfer_register (gdbarch, regcache, + gdbarch_num_regs (gdbarch) + 2, + TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); return RETURN_VALUE_REGISTER_CONVENTION; } else |