aboutsummaryrefslogtreecommitdiff
path: root/gdb/arch
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2022-08-11 18:38:53 +0100
committerAndrew Burgess <aburgess@redhat.com>2022-08-31 16:07:05 +0100
commit4749b84b51bcaa59acfb8bda5d9e134432528cf9 (patch)
tree8c25668a8b8fc03c8281646cbdf702cdfdfffe80 /gdb/arch
parentb49d7aa74466fb73529ebf0e6c907c2142505610 (diff)
downloadbinutils-4749b84b51bcaa59acfb8bda5d9e134432528cf9.zip
binutils-4749b84b51bcaa59acfb8bda5d9e134432528cf9.tar.gz
binutils-4749b84b51bcaa59acfb8bda5d9e134432528cf9.tar.bz2
gdb/riscv: better support for fflags and frm registers
First, some background on the RISC-V registers fflags, frm, and fcsr. These three registers all relate to the floating-point status and control mechanism on RISC-V. The fcsr is the floatint-point control status register, and consists of two parts, the flags (bits 0 to 4) and the rounding-mode (bits 5 to 7). The fcsr register is just one of many control/status registers (or CSRs) available on RISC-V. The fflags and frm registers are also CSRs. These CSRs are aliases for the relevant parts of the fcsr register. So fflags is an alias for bits 0 to 4 of fcsr, and frm is an alias for bits 5 to 7 of fcsr. This means that a user can change the floating-point rounding mode either, by writing a complete new value into fcsr, or by writing just the rounding mode into frm. How this impacts on GDB is like this: a target description could, legitimately include all three registers, fcsr, fflags, and frm. The QEMU target currently does this, and this makes sense. The target is emulating the complete system, and has all three CSRs available, so why not tell GDB about this. In contrast, the RISC-V native Linux target only has access to the fcsr. This is because the ptrace data structure that the kernel uses for reading and writing floating point state only contains a copy of the fcsr, after all, this one field really contains both the fflags and frm fields, so why carry around duplicate data. So, we might expect that the target description for the RISC-V native Linux GDB would only contain the fcsr register. Unfortunately, this is not the case. The RISC-V native Linux target uses GDB's builtin target descriptions by calling riscv_lookup_target_description, this will then add an fpu feature from gdb/features/riscv, either 32bit-fpu.xml or 64bit-fpu.xml. The problem, is that these features include an entry for fcsr, fflags, and frm. This means that GDB expects the target to handle reading and writing these registers. And the RISC-V native Linux target currently doesn't. In riscv_linux_nat_target::store_registers and riscv_linux_nat_target::fetch_registers only the fcsr register is handled, this means that, for RISC-V native Linux, the fflags and frm registers always show up as <unavailable> - they are present in the target description, but the target doesn't know how to access the registers. A final complication relating to these floating pointer CSRs is which target description feature the registers appear in. These registers are CSRs, so it would seem sensible that these registers should appear in the CSR target description feature. However, when I first added RISC-V target description support, I was using a RISC-V simulator that didn't support any CSRs other than the floating point related ones. This simulator bundled all the float related CSRs into the fpu target feature. This didn't feel completely unreasonable to me, and so I had GDB check for these registers in either target feature. In this commit I make some changes relating to how GDB handles the three floating point CSR: 1. Remove fflags and frm from 32bit-fpu.xml and 64bit-fpu.xml. This means that the default RISC-V target description (which RISC-V native FreeBSD), and the target descriptions created for RISC-V native Linux, will not include these registers. There's nothing stopping some other target (e.g. QEMU) from continuing to include all three of these CSRs, the code in riscv-tdep.c continues to check for all three of these registers, and will handle them correctly if they are present. 2. If a target supplied fcsr, but does not supply fflags and/or frm, then RISC-V GDB will now create two pseudo registers in order to emulate the two missing CSRs. These new pseudo-registers do the obvious thing of just reading and writing the fcsr register. 3. With the new pseudo-registers we can no longer make use of the GDB register numbers RISCV_CSR_FFLAGS_REGNUM and RISCV_CSR_FRM_REGNUM. These will be the numbers used if the target supplies the registers in its target description, but, if GDB falls back to using pseudo-registers, then new, unique numbers will be used. To handle this I've added riscv_gdbarch_tdep::fflags_regnum and riscv_gdbarch_tdep::frm_regnum, I've then updated the RISC-V code to compare against these fields. When adding the pseudo-register support, it is important that the pseudo-register numbers are calculated after the call to tdesc_use_registers. This is because we don't know the total number of physical registers until after this call, and the psuedo-register numbers must follow on from the real (target supplied) registers. I've updated some tests to include more testing of the fflags and frm registers, as well as adding a new test.
Diffstat (limited to 'gdb/arch')
-rw-r--r--gdb/arch/riscv.h19
1 files changed, 17 insertions, 2 deletions
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
index 0aef546..8e814d5 100644
--- a/gdb/arch/riscv.h
+++ b/gdb/arch/riscv.h
@@ -55,11 +55,23 @@ struct riscv_gdbarch_features
/* When true this target is RV32E. */
bool embedded = false;
+ /* Track if the target description has an fcsr, fflags, and frm
+ registers. Some targets provide all these in their target
+ descriptions, while some only offer fcsr, while others don't even
+ offer that register. If a target provides fcsr but not fflags and/or
+ frm, then we can emulate these registers as pseudo registers. */
+ bool has_fcsr_reg = false;
+ bool has_fflags_reg = false;
+ bool has_frm_reg = false;
+
/* Equality operator. */
bool operator== (const struct riscv_gdbarch_features &rhs) const
{
return (xlen == rhs.xlen && flen == rhs.flen
- && embedded == rhs.embedded && vlen == rhs.vlen);
+ && embedded == rhs.embedded && vlen == rhs.vlen
+ && has_fflags_reg == rhs.has_fflags_reg
+ && has_frm_reg == rhs.has_frm_reg
+ && has_fcsr_reg == rhs.has_fcsr_reg);
}
/* Inequality operator. */
@@ -72,9 +84,12 @@ struct riscv_gdbarch_features
std::size_t hash () const noexcept
{
std::size_t val = ((embedded ? 1 : 0) << 10
+ | (has_fflags_reg ? 1 : 0) << 11
+ | (has_frm_reg ? 1 : 0) << 12
+ | (has_fcsr_reg ? 1 : 0) << 13
| (xlen & 0x1f) << 5
| (flen & 0x1f) << 0
- | (vlen & 0xfff) << 11);
+ | (vlen & 0xfff) << 14);
return val;
}
};