diff options
author | Daniel Jacobowitz <drow@false.org> | 2007-08-22 15:13:04 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2007-08-22 15:13:04 +0000 |
commit | 8d26208a1e22d9720c1423625c7e15f1bc7d237c (patch) | |
tree | 865c53dc061875f491071df2a55cd1fafcf97391 /gdb/mips-tdep.c | |
parent | 65728c26984bf8b45c0f473d96443186b5c4ebab (diff) | |
download | gdb-8d26208a1e22d9720c1423625c7e15f1bc7d237c.zip gdb-8d26208a1e22d9720c1423625c7e15f1bc7d237c.tar.gz gdb-8d26208a1e22d9720c1423625c7e15f1bc7d237c.tar.bz2 |
gdb/testsuite/
* gdb.base/callfuncs.exp (do_function_calls): Use t_double_int
and t_int_double.
* gdb.base/callfuncs.c (t_double_int, t_int_double): New.
gdb/
* mips-tdep.c (mips_n32n64_fp_arg_chunk_p): New.
(mips_n32n64_push_dummy_call): Always increment float_argreg along
with argreg. Use mips_n32n64_fp_arg_chunk_p.
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 87 |
1 files changed, 76 insertions, 11 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 531d936..68621e1 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -2781,6 +2781,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch, /* N32/N64 ABI stuff. */ +/* Search for a naturally aligned double at OFFSET inside a struct + ARG_TYPE. The N32 / N64 ABIs pass these in floating point + registers. */ + +static int +mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset) +{ + int i; + + if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT) + return 0; + + if (MIPS_FPU_TYPE != MIPS_FPU_DOUBLE) + return 0; + + if (TYPE_LENGTH (arg_type) < offset + MIPS64_REGSIZE) + return 0; + + for (i = 0; i < TYPE_NFIELDS (arg_type); i++) + { + int pos; + struct type *field_type; + + /* We're only looking at normal fields. */ + if (TYPE_FIELD_STATIC (arg_type, i) + || (TYPE_FIELD_BITPOS (arg_type, i) % 8) != 0) + continue; + + /* If we have gone past the offset, there is no double to pass. */ + pos = TYPE_FIELD_BITPOS (arg_type, i) / 8; + if (pos > offset) + return 0; + + field_type = check_typedef (TYPE_FIELD_TYPE (arg_type, i)); + + /* If this field is entirely before the requested offset, go + on to the next one. */ + if (pos + TYPE_LENGTH (field_type) <= offset) + continue; + + /* If this is our special aligned double, we can stop. */ + if (TYPE_CODE (field_type) == TYPE_CODE_FLT + && TYPE_LENGTH (field_type) == MIPS64_REGSIZE) + return 1; + + /* This field starts at or before the requested offset, and + overlaps it. If it is a structure, recurse inwards. */ + return mips_n32n64_fp_arg_chunk_p (field_type, offset - pos); + } + + return 0; +} + static CORE_ADDR mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, @@ -2855,23 +2908,22 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, val = value_contents (arg); if (fp_register_arg_p (typecode, arg_type) - && float_argreg <= MIPS_LAST_FP_ARG_REGNUM) + && argreg <= MIPS_LAST_ARG_REGNUM) { /* This is a floating point value that fits entirely in a single register. */ - /* On 32 bit ABI's the float_argreg is further adjusted - above to ensure that it is even register aligned. */ LONGEST regval = extract_unsigned_integer (val, len); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s", float_argreg, phex (regval, len)); - regcache_cooked_write_unsigned (regcache, float_argreg++, regval); + regcache_cooked_write_unsigned (regcache, float_argreg, regval); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s", argreg, phex (regval, len)); regcache_cooked_write_unsigned (regcache, argreg, regval); - argreg += 1; + float_argreg++; + argreg++; } else { @@ -2896,10 +2948,12 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, fprintf_unfiltered (gdb_stdlog, " -- partial=%d", partial_len); + if (fp_register_arg_p (typecode, arg_type)) + gdb_assert (argreg > MIPS_LAST_ARG_REGNUM); + /* Write this portion of the argument to the stack. */ if (argreg > MIPS_LAST_ARG_REGNUM - || odd_sized_struct - || fp_register_arg_p (typecode, arg_type)) + || odd_sized_struct) { /* Should shorter than int integer values be promoted to int before being stored? */ @@ -2940,12 +2994,10 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } /* Note!!! This is NOT an else clause. Odd sized - structs may go thru BOTH paths. Floating point - arguments will not. */ + structs may go thru BOTH paths. */ /* Write this portion of the argument to a general purpose register. */ - if (argreg <= MIPS_LAST_ARG_REGNUM - && !fp_register_arg_p (typecode, arg_type)) + if (argreg <= MIPS_LAST_ARG_REGNUM) { LONGEST regval = extract_unsigned_integer (val, partial_len); @@ -2971,6 +3023,19 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, argreg, phex (regval, MIPS64_REGSIZE)); regcache_cooked_write_unsigned (regcache, argreg, regval); + + if (mips_n32n64_fp_arg_chunk_p (arg_type, + TYPE_LENGTH (arg_type) - len)) + { + if (mips_debug) + fprintf_filtered (gdb_stdlog, " - fpreg=%d val=%s", + float_argreg, + phex (regval, MIPS64_REGSIZE)); + regcache_cooked_write_unsigned (regcache, float_argreg, + regval); + } + + float_argreg++; argreg++; } |