summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>2020-02-21 13:02:32 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2022-10-13 11:25:32 -0700
commit2be1bc103fab216d2188f89628f84e688f5c9b14 (patch)
tree0d6934be91849b07315205053f6a3c014f5847e2
parentd6a05f2cbf60ea5645942030d69e93e76c6bcb08 (diff)
downloadbinutils-gdb-2be1bc103fab216d2188f89628f84e688f5c9b14.tar.gz
Add basic CHERI-RISC-V support including CHERI registers.
Co-authored-by: John Baldwin <jhb@FreeBSD.org>
-rw-r--r--gdb/arch/riscv.c10
-rw-r--r--gdb/arch/riscv.h11
-rw-r--r--gdb/riscv-tdep.c164
-rw-r--r--gdb/riscv-tdep.h24
4 files changed, 203 insertions, 6 deletions
diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
index 030c2cfdd98..6db31e4fa6d 100644
--- a/gdb/arch/riscv.c
+++ b/gdb/arch/riscv.c
@@ -25,6 +25,8 @@
#include "../features/riscv/32bit-fpu.c"
#include "../features/riscv/64bit-fpu.c"
#include "../features/riscv/rv32e-xregs.c"
+#include "../features/riscv/32bit-cheri64.c"
+#include "../features/riscv/64bit-cheri128.c"
#ifndef GDBSERVER
#define STATIC_IN_GDB static
@@ -62,6 +64,9 @@ riscv_create_target_description (const struct riscv_gdbarch_features features)
else if (features.flen == 16)
arch_name.append ("q");
+ if (features.clen != 0)
+ arch_name.append ("xcheri");
+
set_tdesc_architecture (tdesc.get (), arch_name.c_str ());
#endif
@@ -78,6 +83,11 @@ riscv_create_target_description (const struct riscv_gdbarch_features features)
else if (features.xlen == 8)
regnum = create_feature_riscv_64bit_cpu (tdesc.get (), regnum);
+ if (features.clen == 8)
+ regnum = create_feature_riscv_32bit_cheri64 (tdesc.get (), regnum);
+ else if (features.clen == 16)
+ regnum = create_feature_riscv_64bit_cheri128 (tdesc.get (), regnum);
+
/* For now we only support creating 32-bit or 64-bit f-registers. */
if (features.flen == 4)
regnum = create_feature_riscv_32bit_fpu (tdesc.get (), regnum);
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
index 0aef54638fe..2b58151f694 100644
--- a/gdb/arch/riscv.h
+++ b/gdb/arch/riscv.h
@@ -46,6 +46,12 @@ struct riscv_gdbarch_features
that there are no f-registers. No other value is valid. */
int flen = 0;
+ /* The size of the capability registers in bytes. This is either 8
+ (RV32) or 16 (RV64). This can also hold the value 0 to indicate
+ that there are no capability registers. No other value is
+ valid. */
+ int clen = 0;
+
/* The size of the v-registers in bytes. The value 0 indicates a target
with no vector registers. The minimum value for a standard compliant
target should be 16, but GDB doesn't currently mind, and will accept
@@ -58,7 +64,7 @@ struct riscv_gdbarch_features
/* Equality operator. */
bool operator== (const struct riscv_gdbarch_features &rhs) const
{
- return (xlen == rhs.xlen && flen == rhs.flen
+ return (xlen == rhs.xlen && flen == rhs.flen && clen == rhs.clen
&& embedded == rhs.embedded && vlen == rhs.vlen);
}
@@ -72,9 +78,10 @@ struct riscv_gdbarch_features
std::size_t hash () const noexcept
{
std::size_t val = ((embedded ? 1 : 0) << 10
+ | (clen != 0 ? 1 : 0) << 11
| (xlen & 0x1f) << 5
| (flen & 0x1f) << 0
- | (vlen & 0xfff) << 11);
+ | (vlen & 0xfff) << 12);
return val;
}
};
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index a3f302e0742..822e18b651f 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -97,6 +97,7 @@ static unsigned int riscv_debug_gdbarch = 0;
/* The names of the RISC-V target description features. */
const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr";
static const char *riscv_feature_name_cpu = "org.gnu.gdb.riscv.cpu";
+static const char *riscv_feature_name_cheri = "org.gnu.gdb.riscv.cheri";
static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
static const char *riscv_feature_name_vector = "org.gnu.gdb.riscv.vector";
@@ -359,6 +360,105 @@ struct riscv_xreg_feature : public riscv_register_feature
static const struct riscv_xreg_feature riscv_xreg_feature;
+/* Class representing the Xcheri-registers feature set. */
+
+struct riscv_creg_feature : public riscv_register_feature
+{
+ riscv_creg_feature ()
+ : riscv_register_feature (riscv_feature_name_cheri)
+ {
+ m_registers = {
+ { RISCV_CNULL_REGNUM + 0, { "cnull", "c0" } },
+ { RISCV_CNULL_REGNUM + 1, { "cra", "c1" } },
+ { RISCV_CNULL_REGNUM + 2, { "csp", "c2" } },
+ { RISCV_CNULL_REGNUM + 3, { "cgp", "c3" } },
+ { RISCV_CNULL_REGNUM + 4, { "ctp", "c4" } },
+ { RISCV_CNULL_REGNUM + 5, { "ct0", "c5" } },
+ { RISCV_CNULL_REGNUM + 6, { "ct1", "c6" } },
+ { RISCV_CNULL_REGNUM + 7, { "ct2", "c7" } },
+ { RISCV_CNULL_REGNUM + 8, { "cfp", "c8", "cs0" } },
+ { RISCV_CNULL_REGNUM + 9, { "cs1", "c9" } },
+ { RISCV_CNULL_REGNUM + 10, { "ca0", "c10" } },
+ { RISCV_CNULL_REGNUM + 11, { "ca1", "c11" } },
+ { RISCV_CNULL_REGNUM + 12, { "ca2", "c12" } },
+ { RISCV_CNULL_REGNUM + 13, { "ca3", "c13" } },
+ { RISCV_CNULL_REGNUM + 14, { "ca4", "c14" } },
+ { RISCV_CNULL_REGNUM + 15, { "ca5", "c15" } },
+ { RISCV_CNULL_REGNUM + 16, { "ca6", "c16" } },
+ { RISCV_CNULL_REGNUM + 17, { "ca7", "c17" } },
+ { RISCV_CNULL_REGNUM + 18, { "cs2", "c18" } },
+ { RISCV_CNULL_REGNUM + 19, { "cs3", "c19" } },
+ { RISCV_CNULL_REGNUM + 20, { "cs4", "c20" } },
+ { RISCV_CNULL_REGNUM + 21, { "cs5", "c21" } },
+ { RISCV_CNULL_REGNUM + 22, { "cs6", "c22" } },
+ { RISCV_CNULL_REGNUM + 23, { "cs7", "c23" } },
+ { RISCV_CNULL_REGNUM + 24, { "cs8", "c24" } },
+ { RISCV_CNULL_REGNUM + 25, { "cs9", "c25" } },
+ { RISCV_CNULL_REGNUM + 26, { "cs10", "c26" } },
+ { RISCV_CNULL_REGNUM + 27, { "cs11", "c27" } },
+ { RISCV_CNULL_REGNUM + 28, { "ct3", "c28" } },
+ { RISCV_CNULL_REGNUM + 29, { "ct4", "c29" } },
+ { RISCV_CNULL_REGNUM + 30, { "ct5", "c30" } },
+ { RISCV_CNULL_REGNUM + 31, { "ct6", "c31" } },
+ { RISCV_CNULL_REGNUM + 32, { "pcc" } },
+ { RISCV_CNULL_REGNUM + 33, { "ddc" } },
+ };
+ }
+
+ /* Return the preferred name for the register with gdb register number
+ REGNUM, which must be in the inclusive range RISCV_CNULL_REGNUM to
+ RISCV_LAST_CHERI_REGNUM. */
+ const char *register_name (int regnum) const
+ {
+ gdb_assert (regnum >= RISCV_CNULL_REGNUM
+ && regnum <= RISCV_LAST_CHERI_REGNUM);
+ regnum -= RISCV_CNULL_REGNUM;
+ return m_registers[regnum].names[0];
+ }
+
+ /* Check this feature within TDESC, record the registers from this
+ feature into TDESC_DATA and update ALIASES and FEATURES. */
+ bool check (const struct target_desc *tdesc,
+ struct tdesc_arch_data *tdesc_data,
+ std::vector<riscv_pending_register_alias> *aliases,
+ struct riscv_gdbarch_features *features) const
+ {
+ const struct tdesc_feature *feature_xcheri = tdesc_feature (tdesc);
+
+ /* It's fine if this feature is missing. Update the architecture
+ feature set and return. */
+ if (feature_xcheri == nullptr)
+ {
+ features->clen = 0;
+ return true;
+ }
+
+ for (const auto &reg : m_registers)
+ {
+ bool found = reg.check (tdesc_data, feature_xcheri, true, aliases);
+
+ if (!found)
+ return false;
+ }
+
+ /* Check that all of the CHERI capability registers have the same
+ bitsize. */
+ int clen_bitsize = tdesc_register_bitsize (feature_xcheri, "pcc");
+
+ bool valid_p = true;
+ for (auto &tdesc_reg : feature_xcheri->registers)
+ valid_p &= (tdesc_reg->bitsize == clen_bitsize);
+
+ features->clen = (clen_bitsize / 8);
+
+ return valid_p;
+ }
+};
+
+/* An instance of the Xcheri-register feature set. */
+
+static const struct riscv_creg_feature riscv_creg_feature;
+
/* Class representing the f-registers feature set. */
struct riscv_freg_feature : public riscv_register_feature
@@ -773,6 +873,24 @@ riscv_abi_embedded (struct gdbarch *gdbarch)
return tdep->abi_features.embedded;
}
+/* See riscv-tdep.h. */
+
+int
+riscv_isa_clen (struct gdbarch *gdbarch)
+{
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->isa_features.clen;
+}
+
+/* See riscv-tdep.h. */
+
+int
+riscv_abi_clen (struct gdbarch *gdbarch)
+{
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->abi_features.clen;
+}
+
/* Return true if the target for GDBARCH has floating point hardware. */
static bool
@@ -799,6 +917,22 @@ riscv_is_fp_regno_p (int regno)
&& regno <= RISCV_LAST_FP_REGNUM);
}
+/* Return true if the target for GDBARCH has capability registers. */
+
+static bool
+riscv_has_cheri (struct gdbarch *gdbarch)
+{
+ return (riscv_isa_clen (gdbarch) > 0);
+}
+
+/* Return true if the target for GDBARCH is using CheriABI. */
+
+static bool
+riscv_has_cheriabi (struct gdbarch *gdbarch)
+{
+ return (riscv_abi_clen (gdbarch) > 0);
+}
+
/* Implement the breakpoint_kind_from_pc gdbarch method. */
static int
@@ -997,6 +1131,10 @@ riscv_register_type (struct gdbarch *gdbarch, int regnum)
type = riscv_fpreg_d_type (gdbarch);
}
+ /* Force plain long types for GPRs when using CheriABI. */
+ if (riscv_has_cheriabi (gdbarch) && regnum <= RISCV_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_long;
+
if ((regnum == gdbarch_pc_regnum (gdbarch)
|| regnum == RISCV_RA_REGNUM
|| regnum == RISCV_FP_REGNUM
@@ -1323,7 +1461,9 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
|| regnum == RISCV_CSR_FFLAGS_REGNUM
|| regnum == RISCV_CSR_FRM_REGNUM);
else if (reggroup == general_reggroup)
- return regnum < RISCV_FIRST_FP_REGNUM;
+ return (regnum < RISCV_FIRST_FP_REGNUM
+ || (regnum >= RISCV_CNULL_REGNUM
+ && regnum <= RISCV_LAST_CHERI_REGNUM));
else if (reggroup == restore_reggroup || reggroup == save_reggroup)
{
if (riscv_has_fp_regs (gdbarch))
@@ -3462,6 +3602,9 @@ riscv_features_from_bfd (const bfd *abfd)
else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
features.flen = 4;
+ if (e_flags & EF_RISCV_CHERIABI)
+ features.clen = features.xlen * 2;
+
if (e_flags & EF_RISCV_RVE)
{
if (features.xlen == 8)
@@ -3522,7 +3665,12 @@ static int
riscv_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
if (reg < RISCV_DWARF_REGNUM_X31)
- return RISCV_ZERO_REGNUM + (reg - RISCV_DWARF_REGNUM_X0);
+ {
+ if (riscv_has_cheriabi (gdbarch))
+ return RISCV_CNULL_REGNUM + (reg - RISCV_DWARF_REGNUM_X0);
+ else
+ return RISCV_ZERO_REGNUM + (reg - RISCV_DWARF_REGNUM_X0);
+ }
else if (reg < RISCV_DWARF_REGNUM_F31)
return RISCV_FIRST_FP_REGNUM + (reg - RISCV_DWARF_REGNUM_F0);
@@ -3546,8 +3694,10 @@ riscv_gcc_target_options (struct gdbarch *gdbarch)
{
int isa_xlen = riscv_isa_xlen (gdbarch);
int isa_flen = riscv_isa_flen (gdbarch);
+ int isa_clen = riscv_isa_clen (gdbarch);
int abi_xlen = riscv_abi_xlen (gdbarch);
int abi_flen = riscv_abi_flen (gdbarch);
+ int abi_clen = riscv_abi_clen (gdbarch);
std::string target_options;
target_options = "-march=rv";
@@ -3561,9 +3711,15 @@ riscv_gcc_target_options (struct gdbarch *gdbarch)
target_options += "imafc";
else
target_options += "imac";
+ if (isa_clen != 0)
+ target_options += "xcheri";
target_options += " -mabi=";
- if (abi_xlen == 8)
+ if (abi_clen == 128)
+ target_options = "l64pc128";
+ else if (abi_clen == 64)
+ target_options = "l32pc64";
+ else if (abi_xlen == 8)
target_options += "lp64";
else
target_options += "ilp32";
@@ -3695,6 +3851,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
bool valid_p = (riscv_xreg_feature.check (tdesc, tdesc_data.get (),
&pending_aliases, &features)
+ && riscv_creg_feature.check (tdesc, tdesc_data.get (),
+ &pending_aliases, &features)
&& riscv_freg_feature.check (tdesc, tdesc_data.get (),
&pending_aliases, &features)
&& riscv_virtual_feature.check (tdesc, tdesc_data.get (),
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index ac4b4b7144d..5d4265e3cfd 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -59,7 +59,20 @@ enum
RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31,
- RISCV_LAST_REGNUM = RISCV_V31_REGNUM
+ RISCV_CNULL_REGNUM = RISCV_V31_REGNUM + 1,
+ RISCV_CRA_REGNUM = RISCV_CNULL_REGNUM + RISCV_RA_REGNUM,
+ RISCV_CSP_REGNUM = RISCV_CNULL_REGNUM + RISCV_SP_REGNUM,
+ RISCV_CGP_REGNUM = RISCV_CNULL_REGNUM + RISCV_GP_REGNUM,
+ RISCV_CTP_REGNUM = RISCV_CNULL_REGNUM + RISCV_TP_REGNUM,
+ RISCV_CFP_REGNUM = RISCV_CNULL_REGNUM + RISCV_FP_REGNUM,
+ RISCV_CA0_REGNUM = RISCV_CNULL_REGNUM + RISCV_A0_REGNUM,
+ RISCV_CA1_REGNUM = RISCV_CNULL_REGNUM + RISCV_A1_REGNUM,
+ RISCV_PCC_REGNUM = RISCV_CNULL_REGNUM + RISCV_PC_REGNUM,
+ RISCV_DDC_REGNUM = RISCV_PCC_REGNUM + 1,
+ RISCV_NUM_CHERI_REGS = 34, /* GPRs + DDC + PCC */
+ RISCV_LAST_CHERI_REGNUM = RISCV_CNULL_REGNUM + RISCV_NUM_CHERI_REGS - 1,
+
+ RISCV_LAST_REGNUM = RISCV_LAST_CHERI_REGNUM
};
/* RiscV DWARF register numbers. */
@@ -121,6 +134,11 @@ extern int riscv_isa_xlen (struct gdbarch *gdbarch);
single, double or quad floating point support is available. */
extern int riscv_isa_flen (struct gdbarch *gdbarch);
+/* Return the width in bytes of the capability registers for GDBARCH.
+ Possible return values are 0, 8, or 16 for no CHERI, CHERI-RV32, or
+ CHERI-RV64. */
+extern int riscv_isa_clen (struct gdbarch *gdbarch);
+
/* Return the width in bytes of the general purpose register abi for
GDBARCH. This can be equal to, or less than RISCV_ISA_XLEN and reflects
how the binary was compiled rather than the hardware that is available.
@@ -144,6 +162,10 @@ extern int riscv_abi_flen (struct gdbarch *gdbarch);
argument registers. */
extern bool riscv_abi_embedded (struct gdbarch *gdbarch);
+/* This exists for completeness, but the only valid values are 0 (plain
+ RISC-V binary) or the native clen. */
+extern int riscv_abi_clen (struct gdbarch *gdbarch);
+
/* Single step based on where the current instruction will take us. */
extern std::vector<CORE_ADDR> riscv_software_single_step
(struct regcache *regcache);