diff options
author | Andrew Burgess <andrew.burgess@embecosm.com> | 2020-03-13 15:50:28 +0000 |
---|---|---|
committer | Andrew Burgess <andrew.burgess@embecosm.com> | 2020-03-25 11:29:00 +0000 |
commit | dd8953924b0966e363c27ee38a0663c08f742fa0 (patch) | |
tree | 4c6e18d299e8d9dee3f0f0a4e964ea0a94e08436 /gdb/riscv-tdep.c | |
parent | cf2611febcfa6b7c680de31071c5658e7463eee4 (diff) | |
download | gdb-dd8953924b0966e363c27ee38a0663c08f742fa0.zip gdb-dd8953924b0966e363c27ee38a0663c08f742fa0.tar.gz gdb-dd8953924b0966e363c27ee38a0663c08f742fa0.tar.bz2 |
gdb/riscv: Apply NaN boxing when writing return values into registers
When setting up function parameters we already perform NaN boxing, as
required by the RISC-V ABI, however, we don't do this when writing
values into registers as part of setting up a return value.
This commit moves the NaN boxing code into a small helper function,
and then makes use of this function when setting up function
parameters, and also when setting up return values.
This should resolve this failure:
FAIL: gdb.base/return-nodebug.exp: float: full width of the returned result
gdb/ChangeLog:
PR gdb/25489
* riscv-tdep.c (riscv_arg_info::c_offset): Update comment.
(riscv_regcache_cooked_write): New function.
(riscv_push_dummy_call): Use new function.
(riscv_return_value): Likewise.
Diffstat (limited to 'gdb/riscv-tdep.c')
-rw-r--r-- | gdb/riscv-tdep.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 2978b9e..0423e6a 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1727,8 +1727,9 @@ struct riscv_arg_info will go. */ int c_length; - /* The offset within CONTENTS for this part of the argument. Will - always be 0 for the first part. For the second part of the + /* The offset within CONTENTS for this part of the argument. This can + be non-zero even for the first part (the first field of a struct can + have a non-zero offset due to padding). For the second part of the argument, this might be the C_LENGTH value of the first part, however, if we are passing a structure in two registers, and there's is padding between the first and second field, then this offset @@ -2417,6 +2418,26 @@ riscv_print_arg_location (ui_file *stream, struct gdbarch *gdbarch, } } +/* Wrapper around REGCACHE->cooked_write. Places the LEN bytes of DATA + into a buffer that is at least as big as the register REGNUM, padding + out the DATA with either 0x00, or 0xff. For floating point registers + 0xff is used, for everyone else 0x00 is used. */ + +static void +riscv_regcache_cooked_write (int regnum, const gdb_byte *data, int len, + struct regcache *regcache, int flen) +{ + gdb_byte tmp [sizeof (ULONGEST)]; + + /* FP values in FP registers must be NaN-boxed. */ + if (riscv_is_fp_regno_p (regnum) && len < flen) + memset (tmp, -1, sizeof (tmp)); + else + memset (tmp, 0, sizeof (tmp)); + memcpy (tmp, data, len); + regcache->cooked_write (regnum, tmp); +} + /* Implement the push dummy call gdbarch callback. */ static CORE_ADDR @@ -2526,18 +2547,13 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, { case riscv_arg_info::location::in_reg: { - gdb_byte tmp [sizeof (ULONGEST)]; - gdb_assert (info->argloc[0].c_length <= info->length); - /* FP values in FP registers must be NaN-boxed. */ - if (riscv_is_fp_regno_p (info->argloc[0].loc_data.regno) - && info->argloc[0].c_length < call_info.flen) - memset (tmp, -1, sizeof (tmp)); - else - memset (tmp, 0, sizeof (tmp)); - memcpy (tmp, (info->contents + info->argloc[0].c_offset), - info->argloc[0].c_length); - regcache->cooked_write (info->argloc[0].loc_data.regno, tmp); + + riscv_regcache_cooked_write (info->argloc[0].loc_data.regno, + (info->contents + + info->argloc[0].c_offset), + info->argloc[0].c_length, + regcache, call_info.flen); second_arg_length = (((info->argloc[0].c_length + info->argloc[0].c_offset) < info->length) ? info->argloc[1].c_length : 0); @@ -2569,19 +2585,13 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, { case riscv_arg_info::location::in_reg: { - gdb_byte tmp [sizeof (ULONGEST)]; - gdb_assert ((riscv_is_fp_regno_p (info->argloc[1].loc_data.regno) && second_arg_length <= call_info.flen) || second_arg_length <= call_info.xlen); - /* FP values in FP registers must be NaN-boxed. */ - if (riscv_is_fp_regno_p (info->argloc[1].loc_data.regno) - && second_arg_length < call_info.flen) - memset (tmp, -1, sizeof (tmp)); - else - memset (tmp, 0, sizeof (tmp)); - memcpy (tmp, second_arg_data, second_arg_length); - regcache->cooked_write (info->argloc[1].loc_data.regno, tmp); + riscv_regcache_cooked_write (info->argloc[1].loc_data.regno, + second_arg_data, + second_arg_length, + regcache, call_info.flen); } break; @@ -2701,9 +2711,9 @@ riscv_return_value (struct gdbarch *gdbarch, if (writebuf) { const gdb_byte *ptr = writebuf + info.argloc[0].c_offset; - regcache->cooked_write_part (regnum, 0, + riscv_regcache_cooked_write (regnum, ptr, info.argloc[0].c_length, - ptr); + regcache, call_info.flen); } /* A return value in register can have a second part in a @@ -2730,10 +2740,11 @@ riscv_return_value (struct gdbarch *gdbarch, if (writebuf) { - writebuf += info.argloc[1].c_offset; - regcache->cooked_write_part (regnum, 0, - info.argloc[1].c_length, - writebuf); + const gdb_byte *ptr + = writebuf + info.argloc[1].c_offset; + riscv_regcache_cooked_write + (regnum, ptr, info.argloc[1].c_length, + regcache, call_info.flen); } break; |