/* Target-dependent code for the RISC-V architecture, for GDB.
- Copyright (C) 2018-2021 Free Software Foundation, Inc.
+ Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is part of GDB.
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_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";
+
+/* The current set of options to be passed to the disassembler. */
+static char *riscv_disassembler_options;
+
/* Cached information about a frame. */
struct riscv_unwind_cache
struct riscv_xreg_feature : public riscv_register_feature
{
riscv_xreg_feature ()
- : riscv_register_feature ("org.gnu.gdb.riscv.cpu")
+ : riscv_register_feature (riscv_feature_name_cpu)
{
m_registers = {
{ RISCV_ZERO_REGNUM + 0, { "zero", "x0" } },
struct riscv_freg_feature : public riscv_register_feature
{
riscv_freg_feature ()
- : riscv_register_feature ("org.gnu.gdb.riscv.fpu")
+ : riscv_register_feature (riscv_feature_name_fpu)
{
m_registers = {
{ RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" } },
struct riscv_virtual_feature : public riscv_register_feature
{
riscv_virtual_feature ()
- : riscv_register_feature ("org.gnu.gdb.riscv.virtual")
+ : riscv_register_feature (riscv_feature_name_virtual)
{
m_registers = {
{ RISCV_PRIV_REGNUM, { "priv" } }
struct riscv_csr_feature : public riscv_register_feature
{
riscv_csr_feature ()
- : riscv_register_feature ("org.gnu.gdb.riscv.csr")
+ : riscv_register_feature (riscv_feature_name_csr)
{
m_registers = {
#define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER) \
for (auto ® : m_registers)
{
int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
- const char *alias = xstrprintf ("csr%d", csr_num);
- reg.names.push_back (alias);
+ gdb::unique_xmalloc_ptr<char> alias = xstrprintf ("csr%d", csr_num);
+ reg.names.push_back (alias.release ());
}
}
};
static const struct riscv_csr_feature riscv_csr_feature;
+/* Class representing the v-registers feature set. */
+
+struct riscv_vector_feature : public riscv_register_feature
+{
+ riscv_vector_feature ()
+ : riscv_register_feature (riscv_feature_name_vector)
+ {
+ m_registers = {
+ { RISCV_V0_REGNUM + 0, { "v0" } },
+ { RISCV_V0_REGNUM + 1, { "v1" } },
+ { RISCV_V0_REGNUM + 2, { "v2" } },
+ { RISCV_V0_REGNUM + 3, { "v3" } },
+ { RISCV_V0_REGNUM + 4, { "v4" } },
+ { RISCV_V0_REGNUM + 5, { "v5" } },
+ { RISCV_V0_REGNUM + 6, { "v6" } },
+ { RISCV_V0_REGNUM + 7, { "v7" } },
+ { RISCV_V0_REGNUM + 8, { "v8" } },
+ { RISCV_V0_REGNUM + 9, { "v9" } },
+ { RISCV_V0_REGNUM + 10, { "v10" } },
+ { RISCV_V0_REGNUM + 11, { "v11" } },
+ { RISCV_V0_REGNUM + 12, { "v12" } },
+ { RISCV_V0_REGNUM + 13, { "v13" } },
+ { RISCV_V0_REGNUM + 14, { "v14" } },
+ { RISCV_V0_REGNUM + 15, { "v15" } },
+ { RISCV_V0_REGNUM + 16, { "v16" } },
+ { RISCV_V0_REGNUM + 17, { "v17" } },
+ { RISCV_V0_REGNUM + 18, { "v18" } },
+ { RISCV_V0_REGNUM + 19, { "v19" } },
+ { RISCV_V0_REGNUM + 20, { "v20" } },
+ { RISCV_V0_REGNUM + 21, { "v21" } },
+ { RISCV_V0_REGNUM + 22, { "v22" } },
+ { RISCV_V0_REGNUM + 23, { "v23" } },
+ { RISCV_V0_REGNUM + 24, { "v24" } },
+ { RISCV_V0_REGNUM + 25, { "v25" } },
+ { RISCV_V0_REGNUM + 26, { "v26" } },
+ { RISCV_V0_REGNUM + 27, { "v27" } },
+ { RISCV_V0_REGNUM + 28, { "v28" } },
+ { RISCV_V0_REGNUM + 29, { "v29" } },
+ { RISCV_V0_REGNUM + 30, { "v30" } },
+ { RISCV_V0_REGNUM + 31, { "v31" } },
+ };
+ }
+
+ /* Return the preferred name for the register with gdb register number
+ REGNUM, which must be in the inclusive range RISCV_V0_REGNUM to
+ RISCV_V0_REGNUM + 31. */
+ const char *register_name (int regnum) const
+ {
+ gdb_assert (regnum >= RISCV_V0_REGNUM
+ && regnum <= RISCV_V0_REGNUM + 31);
+ regnum -= RISCV_V0_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_vector = tdesc_feature (tdesc);
+
+ /* It's fine if this feature is missing. Update the architecture
+ feature set and return. */
+ if (feature_vector == nullptr)
+ {
+ features->vlen = 0;
+ return true;
+ }
+
+ /* Check all of the vector registers are present. */
+ for (const auto ® : m_registers)
+ {
+ if (!reg.check (tdesc_data, feature_vector, true, aliases))
+ return false;
+ }
+
+ /* Look through all of the vector registers and check they all have the
+ same bitsize. Use this bitsize to update the feature set for this
+ gdbarch. */
+ int vector_bitsize = -1;
+ for (const auto ® : m_registers)
+ {
+ int reg_bitsize = -1;
+ for (const char *name : reg.names)
+ {
+ if (tdesc_unnumbered_register (feature_vector, name))
+ {
+ reg_bitsize = tdesc_register_bitsize (feature_vector, name);
+ break;
+ }
+ }
+ gdb_assert (reg_bitsize != -1);
+ if (vector_bitsize == -1)
+ vector_bitsize = reg_bitsize;
+ else if (vector_bitsize != reg_bitsize)
+ return false;
+ }
+
+ features->vlen = (vector_bitsize / 8);
+ return true;
+ }
+};
+
+/* An instance of the v-register feature set. */
+
+static const struct riscv_vector_feature riscv_vector_feature;
+
/* Controls whether we place compressed breakpoints or not. When in auto
mode GDB tries to determine if the target supports compressed
breakpoints, and uses them if it does. */
int
riscv_isa_xlen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->isa_features.xlen;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->isa_features.xlen;
}
/* See riscv-tdep.h. */
int
riscv_abi_xlen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->abi_features.xlen;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->abi_features.xlen;
}
/* See riscv-tdep.h. */
int
riscv_isa_flen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->isa_features.flen;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->isa_features.flen;
}
/* See riscv-tdep.h. */
int
riscv_abi_flen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->abi_features.flen;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->abi_features.flen;
}
/* See riscv-tdep.h. */
bool
riscv_abi_embedded (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->abi_features.embedded;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->abi_features.embedded;
}
/* Return true if the target for GDBARCH has floating point hardware. */
static bool
riscv_has_fp_abi (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->abi_features.flen > 0;
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+ return tdep->abi_features.flen > 0;
}
/* Return true if REGNO is a floating pointer register. */
user. */
if (target_read_code (*pcptr, buf, 1) == -1)
buf[0] = 0;
- read_code (*pcptr, buf, 1);
}
if (riscv_debug_breakpoints)
case 4:
return ebreak;
default:
- gdb_assert_not_reached (_("unhandled breakpoint kind"));
+ gdb_assert_not_reached ("unhandled breakpoint kind");
}
}
will show up in 'info register all'. Unless, we identify the
duplicate copies of these registers (in riscv_tdesc_unknown_reg) and
then hide the registers here by giving them no name. */
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
if (tdep->duplicate_fflags_regnum == regnum)
return NULL;
if (tdep->duplicate_frm_regnum == regnum)
static struct type *
riscv_fpreg_d_type (struct gdbarch *gdbarch)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
if (tdep->riscv_fpreg_d_type == nullptr)
{
&& regtype->field (2).type ()->code () == TYPE_CODE_FLT))
{
struct value_print_options opts;
- const gdb_byte *valaddr = value_contents_for_printing (val);
+ const gdb_byte *valaddr = value_contents_for_printing (val).data ();
enum bfd_endian byte_order = type_byte_order (regtype);
get_user_print_options (&opts);
static bool
riscv_is_unknown_csr (struct gdbarch *gdbarch, int regnum)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
return (regnum >= tdep->unknown_csrs_first_regnum
&& regnum < (tdep->unknown_csrs_first_regnum
+ tdep->unknown_csrs_count));
if (reggroup == all_reggroup)
{
- if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
+ if (regnum < RISCV_FIRST_CSR_REGNUM || regnum >= RISCV_PRIV_REGNUM)
return 1;
if (riscv_is_regnum_a_named_csr (regnum))
return 1;
return 0;
}
else if (reggroup == vector_reggroup)
- return 0;
+ return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM);
else
return 0;
}
LUI,
SD,
SW,
+ LD,
+ LW,
+ MV,
/* These are needed for software breakpoint support. */
JAL,
JALR,
/* These are needed for stepping over atomic sequences. */
LR,
SC,
+ /* This instruction is used to do a syscall. */
+ ECALL,
/* Other instructions are not interesting during the prologue scan, and
are ignored. */
{
m_opcode = opcode;
m_rd = m_rs1 = decode_register_index (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_RVC_IMM (ival);
+ m_imm.s = EXTRACT_CITYPE_IMM (ival);
+ }
+
+ /* Helper for DECODE, decode 16-bit compressed CL-type instruction. */
+ void decode_cl_type_insn (enum opcode opcode, ULONGEST ival)
+ {
+ m_opcode = opcode;
+ m_rd = decode_register_index_short (ival, OP_SH_CRS2S);
+ m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
+ m_imm.s = EXTRACT_CLTYPE_IMM (ival);
}
/* Helper for DECODE, decode 32-bit S-type instruction. */
{
m_opcode = opcode;
m_rd = decode_register_index (ival, OP_SH_RD);
- m_imm.s = EXTRACT_UJTYPE_IMM (ival);
+ m_imm.s = EXTRACT_JTYPE_IMM (ival);
}
/* Helper for DECODE, decode 32-bit J-type instruction. */
void decode_cj_type_insn (enum opcode opcode, ULONGEST ival)
{
m_opcode = opcode;
- m_imm.s = EXTRACT_RVC_J_IMM (ival);
+ m_imm.s = EXTRACT_CJTYPE_IMM (ival);
}
void decode_b_type_insn (enum opcode opcode, ULONGEST ival)
m_opcode = opcode;
m_rs1 = decode_register_index (ival, OP_SH_RS1);
m_rs2 = decode_register_index (ival, OP_SH_RS2);
- m_imm.s = EXTRACT_SBTYPE_IMM (ival);
+ m_imm.s = EXTRACT_BTYPE_IMM (ival);
}
void decode_cb_type_insn (enum opcode opcode, ULONGEST ival)
{
m_opcode = opcode;
m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_RVC_B_IMM (ival);
+ m_imm.s = EXTRACT_CBTYPE_IMM (ival);
}
/* Fetch instruction from target memory at ADDR, return the content of
decode_r_type_insn (SC, ival);
else if (is_sc_d_insn (ival))
decode_r_type_insn (SC, ival);
+ else if (is_ecall_insn (ival))
+ decode_i_type_insn (ECALL, ival);
+ else if (is_ld_insn (ival))
+ decode_i_type_insn (LD, ival);
+ else if (is_lw_insn (ival))
+ decode_i_type_insn (LW, ival);
else
/* None of the other fields are valid in this case. */
m_opcode = OTHER;
{
m_opcode = ADDI;
m_rd = m_rs1 = decode_register_index (ival, OP_SH_RD);
- m_imm.s = EXTRACT_RVC_ADDI16SP_IMM (ival);
+ m_imm.s = EXTRACT_CITYPE_ADDI16SP_IMM (ival);
}
else if (is_c_addi4spn_insn (ival))
{
m_opcode = ADDI;
m_rd = decode_register_index_short (ival, OP_SH_CRS2S);
m_rs1 = RISCV_SP_REGNUM;
- m_imm.s = EXTRACT_RVC_ADDI4SPN_IMM (ival);
+ m_imm.s = EXTRACT_CIWTYPE_ADDI4SPN_IMM (ival);
}
else if (is_c_lui_insn (ival))
{
m_opcode = LUI;
m_rd = decode_register_index (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_RVC_LUI_IMM (ival);
+ m_imm.s = EXTRACT_CITYPE_LUI_IMM (ival);
}
/* C_SD and C_FSW have the same opcode. C_SD is RV64 and RV128 only,
and C_FSW is RV32 only. */
else if (xlen != 4 && is_c_sd_insn (ival))
- decode_cs_type_insn (SD, ival, EXTRACT_RVC_LD_IMM (ival));
+ decode_cs_type_insn (SD, ival, EXTRACT_CLTYPE_LD_IMM (ival));
else if (is_c_sw_insn (ival))
- decode_cs_type_insn (SW, ival, EXTRACT_RVC_LW_IMM (ival));
+ decode_cs_type_insn (SW, ival, EXTRACT_CLTYPE_LW_IMM (ival));
else if (is_c_swsp_insn (ival))
- decode_css_type_insn (SW, ival, EXTRACT_RVC_SWSP_IMM (ival));
+ decode_css_type_insn (SW, ival, EXTRACT_CSSTYPE_SWSP_IMM (ival));
else if (xlen != 4 && is_c_sdsp_insn (ival))
- decode_css_type_insn (SD, ival, EXTRACT_RVC_SDSP_IMM (ival));
+ decode_css_type_insn (SD, ival, EXTRACT_CSSTYPE_SDSP_IMM (ival));
/* C_JR and C_MV have the same opcode. If RS2 is 0, then this is a C_JR.
- So must try to match C_JR first as it ahs more bits in mask. */
+ So must try to match C_JR first as it has more bits in mask. */
else if (is_c_jr_insn (ival))
decode_cr_type_insn (JALR, ival);
+ else if (is_c_mv_insn (ival))
+ decode_cr_type_insn (MV, ival);
else if (is_c_j_insn (ival))
decode_cj_type_insn (JAL, ival);
else if (is_c_beqz_insn (ival))
decode_cb_type_insn (BEQ, ival);
else if (is_c_bnez_insn (ival))
decode_cb_type_insn (BNE, ival);
+ else if (is_c_ld_insn (ival))
+ decode_cl_type_insn (LD, ival);
+ else if (is_c_lw_insn (ival))
+ decode_cl_type_insn (LW, ival);
else
/* None of the other fields of INSN are valid in this case. */
m_opcode = OTHER;
}
else if (insn.opcode () == riscv_insn::ADD)
{
- /* Handle: addi REG1, REG2, IMM */
+ /* Handle: add REG1, REG2, REG3 */
gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
regs[insn.rd ()] = pv_add (regs[insn.rs1 ()], regs[insn.rs2 ()]);
}
+ else if (insn.opcode () == riscv_insn::LD
+ || insn.opcode () == riscv_insn::LW)
+ {
+ /* Handle: ld reg, offset(rs1)
+ or: c.ld reg, offset(rs1)
+ or: lw reg, offset(rs1)
+ or: c.lw reg, offset(rs1) */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()]
+ = stack.fetch (pv_add_constant (regs[insn.rs1 ()],
+ insn.imm_signed ()),
+ (insn.opcode () == riscv_insn::LW ? 4 : 8));
+ }
+ else if (insn.opcode () == riscv_insn::MV)
+ {
+ /* Handle: c.mv RD, RS2 */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs2 () > 0);
+ regs[insn.rd ()] = regs[insn.rs2 ()];
+ }
else
{
end_prologue_addr = cur_pc;
gdbarch_register_name (gdbarch, i),
plongest ((LONGEST) offset));
}
- trad_frame_set_addr (cache->regs, i, offset);
+ cache->regs[i].set_addr (offset);
}
}
}
for (i = 0; i < count; ++i)
{
- if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_BITPOS)
+ if (type->field (i).loc_kind () != FIELD_LOC_KIND_BITPOS)
continue;
struct type *field_type = type->field (i).type ();
field_type = check_typedef (field_type);
int field_offset
- = offset + TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT;
+ = offset + type->field (i).loc_bitpos () / TARGET_CHAR_BIT;
switch (field_type->code ())
{
case TYPE_CODE_RANGE:
case TYPE_CODE_ENUM:
case TYPE_CODE_PTR:
+ case TYPE_CODE_FIXED_POINT:
if (ainfo->length <= cinfo->xlen)
{
ainfo->type = builtin_type (gdbarch)->builtin_long;
break;
default:
- gdb_assert_not_reached (_("unknown argument location type"));
+ gdb_assert_not_reached ("unknown argument location type");
}
}
if (info->type != arg_type)
arg_value = value_cast (info->type, arg_value);
- info->contents = value_contents (arg_value);
+ info->contents = value_contents (arg_value).data ();
}
/* Adjust the stack pointer and align it. */
break;
default:
- gdb_assert_not_reached (_("unknown argument location type"));
+ gdb_assert_not_reached ("unknown argument location type");
}
if (second_arg_length > 0)
buffers of sufficient size. */
if (writebuf != nullptr)
{
- struct value *arg_val = value_from_contents (arg_type, writebuf);
- abi_val = value_cast (info.type, arg_val);
- writebuf = value_contents_raw (abi_val);
+ struct value *arg_val;
+
+ if (is_fixed_point_type (arg_type))
+ {
+ /* Convert the argument to the type used to pass
+ the return value, but being careful to preserve
+ the fact that the value needs to be returned
+ unscaled. */
+ gdb_mpz unscaled;
+
+ unscaled.read (gdb::make_array_view (writebuf,
+ TYPE_LENGTH (arg_type)),
+ type_byte_order (arg_type),
+ arg_type->is_unsigned ());
+ abi_val = allocate_value (info.type);
+ unscaled.write (value_contents_raw (abi_val),
+ type_byte_order (info.type),
+ info.type->is_unsigned ());
+ }
+ else
+ {
+ arg_val = value_from_contents (arg_type, writebuf);
+ abi_val = value_cast (info.type, arg_val);
+ }
+ writebuf = value_contents_raw (abi_val).data ();
}
else
{
abi_val = allocate_value (info.type);
old_readbuf = readbuf;
- readbuf = value_contents_raw (abi_val);
+ readbuf = value_contents_raw (abi_val).data ();
}
arg_len = TYPE_LENGTH (info.type);
comment at the head of this block for more details. */
if (readbuf != nullptr)
{
- struct value *arg_val = value_cast (arg_type, abi_val);
- memcpy (old_readbuf, value_contents_raw (arg_val),
+ struct value *arg_val;
+
+ if (is_fixed_point_type (arg_type))
+ {
+ /* Convert abi_val to the actual return type, but
+ being careful to preserve the fact that abi_val
+ is unscaled. */
+ gdb_mpz unscaled;
+
+ unscaled.read (value_contents (abi_val),
+ type_byte_order (info.type),
+ info.type->is_unsigned ());
+ arg_val = allocate_value (arg_type);
+ unscaled.write (value_contents_raw (arg_val),
+ type_byte_order (arg_type),
+ arg_type->is_unsigned ());
+ }
+ else
+ arg_val = value_cast (arg_type, abi_val);
+ memcpy (old_readbuf, value_contents_raw (arg_val).data (),
TYPE_LENGTH (arg_type));
}
}
numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
for (regno = 0; regno < numregs; ++regno)
{
- if (trad_frame_addr_p (cache->regs, regno))
+ if (cache->regs[regno].is_addr ())
cache->regs[regno].set_addr (cache->regs[regno].addr ()
+ cache->frame_base);
}
The previous $ra value is gone, this would have been stored be the
previous frame if required. */
cache->regs[gdbarch_pc_regnum (gdbarch)] = cache->regs[RISCV_RA_REGNUM];
- trad_frame_set_unknown (cache->regs, RISCV_RA_REGNUM);
+ cache->regs[RISCV_RA_REGNUM].set_unknown ();
/* Build the frame id. */
cache->this_id = frame_id_build (cache->frame_base, start_addr);
/* The previous $sp value is the frame base value. */
- trad_frame_set_value (cache->regs, gdbarch_sp_regnum (gdbarch),
- cache->frame_base);
+ cache->regs[gdbarch_sp_regnum (gdbarch)].set_value (cache->frame_base);
return cache;
}
static const struct frame_unwind riscv_frame_unwind =
{
+ /*.name =*/ "riscv prologue",
/*.type =*/ NORMAL_FRAME,
/*.stop_reason =*/ default_frame_unwind_stop_reason,
/*.this_id =*/ riscv_frame_this_id,
/*.prev_arch =*/ NULL,
};
-/* Extract a set of required target features out of INFO, specifically the
- bfd being executed is examined to see what target features it requires.
- IF there is no current bfd, or the bfd doesn't indicate any useful
- features then a RISCV_GDBARCH_FEATURES is returned in its default state. */
+/* Extract a set of required target features out of ABFD. If ABFD is
+ nullptr then a RISCV_GDBARCH_FEATURES is returned in its default state. */
static struct riscv_gdbarch_features
-riscv_features_from_gdbarch_info (const struct gdbarch_info info)
+riscv_features_from_bfd (const bfd *abfd)
{
struct riscv_gdbarch_features features;
only used at all if the target hasn't given us a description, so this
is really a last ditched effort to do something sane before giving
up. */
- if (info.abfd != NULL
- && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+ if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
{
- unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
- int e_flags = elf_elfheader (info.abfd)->e_flags;
+ unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
+ int e_flags = elf_elfheader (abfd)->e_flags;
if (eclass == ELFCLASS32)
features.xlen = 4;
{
/* Extract desired feature set from INFO. */
struct riscv_gdbarch_features features
- = riscv_features_from_gdbarch_info (info);
+ = riscv_features_from_bfd (info.abfd);
- /* If the XLEN field is still 0 then we got nothing useful from INFO. In
- this case we fall back to a minimal useful target, 8-byte x-registers,
- with no floating point. */
+ /* If the XLEN field is still 0 then we got nothing useful from INFO.BFD,
+ maybe there was no bfd object. In this case we fall back to a minimal
+ useful target with no floating point, the x-register size is selected
+ based on the architecture from INFO. */
if (features.xlen == 0)
- features.xlen = 8;
+ features.xlen = info.bfd_arch_info->bits_per_word == 32 ? 4 : 8;
/* Now build a target description based on the feature set. */
return riscv_lookup_target_description (features);
else if (reg >= RISCV_DWARF_FIRST_CSR && reg <= RISCV_DWARF_LAST_CSR)
return RISCV_FIRST_CSR_REGNUM + (reg - RISCV_DWARF_FIRST_CSR);
+ else if (reg >= RISCV_DWARF_REGNUM_V0 && reg <= RISCV_DWARF_REGNUM_V31)
+ return RISCV_V0_REGNUM + (reg - RISCV_DWARF_REGNUM_V0);
+
return -1;
}
record their register numbers here. */
if (strcmp (tdesc_feature_name (feature), riscv_freg_feature.name ()) == 0)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
int *regnum_ptr = nullptr;
if (strcmp (reg_name, "fflags") == 0)
about register groups in riscv_register_reggroup_p. */
if (strcmp (tdesc_feature_name (feature), riscv_csr_feature.name ()) == 0)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
if (tdep->unknown_csrs_first_regnum == -1)
tdep->unknown_csrs_first_regnum = possible_regnum;
gdb_assert (tdep->unknown_csrs_first_regnum
struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
- struct gdbarch_tdep *tdep;
struct riscv_gdbarch_features features;
const struct target_desc *tdesc = info.target_desc;
&& riscv_virtual_feature.check (tdesc, tdesc_data.get (),
&pending_aliases, &features)
&& riscv_csr_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features));
+ &pending_aliases, &features)
+ && riscv_vector_feature.check (tdesc, tdesc_data.get (),
+ &pending_aliases, &features));
if (!valid_p)
{
if (riscv_debug_gdbarch)
target, then check that this matches with what the target is
providing. */
struct riscv_gdbarch_features abi_features
- = riscv_features_from_gdbarch_info (info);
+ = riscv_features_from_bfd (info.abfd);
/* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
features from the INFO object. In this case we just treat the
/* Check that the feature set of the ARCHES matches the feature set
we are looking for. If it doesn't then we can't reuse this
gdbarch. */
- struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+ riscv_gdbarch_tdep *other_tdep
+ = (riscv_gdbarch_tdep *) gdbarch_tdep (arches->gdbarch);
if (other_tdep->isa_features != features
|| other_tdep->abi_features != abi_features)
return arches->gdbarch;
/* None found, so create a new architecture from the information provided. */
- tdep = new (struct gdbarch_tdep);
+ riscv_gdbarch_tdep *tdep = new riscv_gdbarch_tdep;
gdbarch = gdbarch_alloc (&info, tdep);
tdep->isa_features = features;
tdep->abi_features = abi_features;
set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options);
set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp);
+ /* Disassembler options support. */
+ set_gdbarch_valid_disassembler_options (gdbarch,
+ disassembler_options_riscv ());
+ set_gdbarch_disassembler_options (gdbarch, &riscv_disassembler_options);
+
/* Hook in OS ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
riscv_next_pc (struct regcache *regcache, CORE_ADDR pc)
{
struct gdbarch *gdbarch = regcache->arch ();
+ const riscv_gdbarch_tdep *tdep
+ = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
struct riscv_insn insn;
CORE_ADDR next_pc;
if (src1 >= src2)
next_pc = pc + insn.imm_signed ();
}
+ else if (insn.opcode () == riscv_insn::ECALL)
+ {
+ if (tdep->syscall_next_pc != nullptr)
+ next_pc = tdep->syscall_next_pc (get_current_frame ());
+ }
return next_pc;
}
csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
}
+/* See riscv-tdep.h. */
+
+void
+riscv_supply_regset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *regs, size_t len)
+{
+ regcache->supply_regset (regset, regnum, regs, len);
+
+ if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
+ regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
+
+ if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM
+ || regnum == RISCV_CSR_FRM_REGNUM)
+ {
+ int fcsr_regnum = RISCV_CSR_FCSR_REGNUM;
+
+ /* Ensure that FCSR has been read into REGCACHE. */
+ if (regnum != -1)
+ regcache->supply_regset (regset, fcsr_regnum, regs, len);
+
+ /* Grab the FCSR value if it is now in the regcache. We must check
+ the status first as, if the register was not supplied by REGSET,
+ this call will trigger a recursive attempt to fetch the
+ registers. */
+ if (regcache->get_register_status (fcsr_regnum) == REG_VALID)
+ {
+ ULONGEST fcsr_val;
+ regcache->raw_read (fcsr_regnum, &fcsr_val);
+
+ /* Extract the fflags and frm values. */
+ ULONGEST fflags_val = fcsr_val & 0x1f;
+ ULONGEST frm_val = (fcsr_val >> 5) & 0x7;
+
+ /* And supply these if needed. */
+ if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM)
+ regcache->raw_supply_integer (RISCV_CSR_FFLAGS_REGNUM,
+ (gdb_byte *) &fflags_val,
+ sizeof (fflags_val),
+ /* is_signed */ false);
+
+ if (regnum == -1 || regnum == RISCV_CSR_FRM_REGNUM)
+ regcache->raw_supply_integer (RISCV_CSR_FRM_REGNUM,
+ (gdb_byte *)&frm_val,
+ sizeof (fflags_val),
+ /* is_signed */ false);
+ }
+ }
+}
+
void _initialize_riscv_tdep ();
void
_initialize_riscv_tdep ()
/* Add root prefix command for all "set debug riscv" and "show debug
riscv" commands. */
- add_basic_prefix_cmd ("riscv", no_class,
- _("RISC-V specific debug commands."),
- &setdebugriscvcmdlist, "set debug riscv ", 0,
- &setdebuglist);
-
- add_show_prefix_cmd ("riscv", no_class,
- _("RISC-V specific debug commands."),
- &showdebugriscvcmdlist, "show debug riscv ", 0,
- &showdebuglist);
+ add_setshow_prefix_cmd ("riscv", no_class,
+ _("RISC-V specific debug commands."),
+ _("RISC-V specific debug commands."),
+ &setdebugriscvcmdlist, &showdebugriscvcmdlist,
+ &setdebuglist, &showdebuglist);
add_setshow_zuinteger_cmd ("breakpoints", class_maintenance,
&riscv_debug_breakpoints, _("\
&setdebugriscvcmdlist, &showdebugriscvcmdlist);
/* Add root prefix command for all "set riscv" and "show riscv" commands. */
- add_basic_prefix_cmd ("riscv", no_class,
- _("RISC-V specific commands."),
- &setriscvcmdlist, "set riscv ", 0, &setlist);
-
- add_show_prefix_cmd ("riscv", no_class,
- _("RISC-V specific commands."),
- &showriscvcmdlist, "show riscv ", 0, &showlist);
+ add_setshow_prefix_cmd ("riscv", no_class,
+ _("RISC-V specific commands."),
+ _("RISC-V specific commands."),
+ &setriscvcmdlist, &showriscvcmdlist,
+ &setlist, &showlist);
use_compressed_breakpoints = AUTO_BOOLEAN_AUTO;