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.
This commit is contained in:
parent
cf2611febc
commit
dd8953924b
|
@ -1,3 +1,11 @@
|
|||
2020-03-25 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
PR gdb/25534
|
||||
* 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.
|
||||
|
||||
2020-03-24 Simon Marchi <simon.marchi@polymtl.ca>
|
||||
|
||||
* fbsd-nat.c (fbsd_nat_target::follow_fork): Change bool to int.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue