#include "opcode/riscv-opc.h"
#include "cli/cli-decode.h"
#include "observable.h"
+#include "prologue-value.h"
/* The stack must be 16-byte aligned. */
#define SP_ALIGNMENT 16
#include "opcode/riscv-opc.h"
#undef DECLARE_INSN
-/* Architectural name for core registers. */
+/* Cached information about a frame. */
+
+struct riscv_unwind_cache
+{
+ /* The register from which we can calculate the frame base. This is
+ usually $sp or $fp. */
+ int frame_base_reg;
+
+ /* The offset from the current value in register FRAME_BASE_REG to the
+ actual frame base address. */
+ int frame_base_offset;
+
+ /* Information about previous register values. */
+ struct trad_frame_saved_reg *regs;
+
+ /* The id for this frame. */
+ struct frame_id this_id;
+
+ /* The base (stack) address for this frame. This is the stack pointer
+ value on entry to this frame before any adjustments are made. */
+ CORE_ADDR frame_base;
+};
+
+/* The preferred register names for all the general purpose and floating
+ point registers. These are what GDB will use when referencing a
+ register. */
static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
{
- "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
- "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
- "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
- "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
- "pc",
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
+ "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
+ "pc",
+ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
+ "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "fs2", "fs3",
+ "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9",
+ "ft10", "ft11",
};
-/* Maps "pretty" register names onto their GDB register number. */
+/* Map alternative register names onto their GDB register number. */
-struct register_alias
+struct riscv_register_alias
{
/* The register alias. Usually more descriptive than the
architectural name of the register. */
/* Table of register aliases. */
-static const struct register_alias riscv_register_aliases[] =
-{
- { "zero", 0 },
- { "ra", 1 },
- { "sp", 2 },
- { "gp", 3 },
- { "tp", 4 },
- { "t0", 5 },
- { "t1", 6 },
- { "t2", 7 },
- { "s0", 8 },
- { "fp", 8 },
- { "s1", 9 },
- { "a0", 10 },
- { "a1", 11 },
- { "a2", 12 },
- { "a3", 13 },
- { "a4", 14 },
- { "a5", 15 },
- { "a6", 16 },
- { "a7", 17 },
- { "s2", 18 },
- { "s3", 19 },
- { "s4", 20 },
- { "s5", 21 },
- { "s6", 22 },
- { "s7", 23 },
- { "s8", 24 },
- { "s9", 25 },
- { "s10", 26 },
- { "s11", 27 },
- { "t3", 28 },
- { "t4", 29 },
- { "t5", 30 },
- { "t6", 31 },
- /* pc is 32. */
- { "ft0", 33 },
- { "ft1", 34 },
- { "ft2", 35 },
- { "ft3", 36 },
- { "ft4", 37 },
- { "ft5", 38 },
- { "ft6", 39 },
- { "ft7", 40 },
- { "fs0", 41 },
- { "fs1", 42 },
- { "fa0", 43 },
- { "fa1", 44 },
- { "fa2", 45 },
- { "fa3", 46 },
- { "fa4", 47 },
- { "fa5", 48 },
- { "fa6", 49 },
- { "fa7", 50 },
- { "fs2", 51 },
- { "fs3", 52 },
- { "fs4", 53 },
- { "fs5", 54 },
- { "fs6", 55 },
- { "fs7", 56 },
- { "fs8", 57 },
- { "fs9", 58 },
- { "fs10", 59 },
- { "fs11", 60 },
- { "ft8", 61 },
- { "ft9", 62 },
- { "ft10", 63 },
- { "ft11", 64 },
-#define DECLARE_CSR(name, num) { #name, (num) + 65 },
-#include "opcode/riscv-opc.h"
-#undef DECLARE_CSR
+static const struct riscv_register_alias riscv_register_aliases[] =
+{
+ /* Aliases for general purpose registers. These are the architectural
+ names, as GDB uses the more user friendly names by default. */
+ { "x0", (RISCV_ZERO_REGNUM + 0) },
+ { "x1", (RISCV_ZERO_REGNUM + 1) },
+ { "x2", (RISCV_ZERO_REGNUM + 2) },
+ { "x3", (RISCV_ZERO_REGNUM + 3) },
+ { "x4", (RISCV_ZERO_REGNUM + 4) },
+ { "x5", (RISCV_ZERO_REGNUM + 5) },
+ { "x6", (RISCV_ZERO_REGNUM + 6) },
+ { "x7", (RISCV_ZERO_REGNUM + 7) },
+ { "x8", (RISCV_ZERO_REGNUM + 8) },
+ { "s0", (RISCV_ZERO_REGNUM + 8) }, /* fp, s0, and x8 are all aliases. */
+ { "x9", (RISCV_ZERO_REGNUM + 9) },
+ { "x10", (RISCV_ZERO_REGNUM + 10) },
+ { "x11", (RISCV_ZERO_REGNUM + 11) },
+ { "x12", (RISCV_ZERO_REGNUM + 12) },
+ { "x13", (RISCV_ZERO_REGNUM + 13) },
+ { "x14", (RISCV_ZERO_REGNUM + 14) },
+ { "x15", (RISCV_ZERO_REGNUM + 15) },
+ { "x16", (RISCV_ZERO_REGNUM + 16) },
+ { "x17", (RISCV_ZERO_REGNUM + 17) },
+ { "x18", (RISCV_ZERO_REGNUM + 18) },
+ { "x19", (RISCV_ZERO_REGNUM + 19) },
+ { "x20", (RISCV_ZERO_REGNUM + 20) },
+ { "x21", (RISCV_ZERO_REGNUM + 21) },
+ { "x22", (RISCV_ZERO_REGNUM + 22) },
+ { "x23", (RISCV_ZERO_REGNUM + 23) },
+ { "x24", (RISCV_ZERO_REGNUM + 24) },
+ { "x25", (RISCV_ZERO_REGNUM + 25) },
+ { "x26", (RISCV_ZERO_REGNUM + 26) },
+ { "x27", (RISCV_ZERO_REGNUM + 27) },
+ { "x28", (RISCV_ZERO_REGNUM + 28) },
+ { "x29", (RISCV_ZERO_REGNUM + 29) },
+ { "x30", (RISCV_ZERO_REGNUM + 30) },
+ { "x31", (RISCV_ZERO_REGNUM + 31) },
+
+ /* Aliases for the floating-point registers. These are the architectural
+ names as GDB uses the more user friendly names by default. */
+ { "f0", (RISCV_FIRST_FP_REGNUM + 0) },
+ { "f1", (RISCV_FIRST_FP_REGNUM + 1) },
+ { "f2", (RISCV_FIRST_FP_REGNUM + 2) },
+ { "f3", (RISCV_FIRST_FP_REGNUM + 3) },
+ { "f4", (RISCV_FIRST_FP_REGNUM + 4) },
+ { "f5", (RISCV_FIRST_FP_REGNUM + 5) },
+ { "f6", (RISCV_FIRST_FP_REGNUM + 6) },
+ { "f7", (RISCV_FIRST_FP_REGNUM + 7) },
+ { "f8", (RISCV_FIRST_FP_REGNUM + 8) },
+ { "f9", (RISCV_FIRST_FP_REGNUM + 9) },
+ { "f10", (RISCV_FIRST_FP_REGNUM + 10) },
+ { "f11", (RISCV_FIRST_FP_REGNUM + 11) },
+ { "f12", (RISCV_FIRST_FP_REGNUM + 12) },
+ { "f13", (RISCV_FIRST_FP_REGNUM + 13) },
+ { "f14", (RISCV_FIRST_FP_REGNUM + 14) },
+ { "f15", (RISCV_FIRST_FP_REGNUM + 15) },
+ { "f16", (RISCV_FIRST_FP_REGNUM + 16) },
+ { "f17", (RISCV_FIRST_FP_REGNUM + 17) },
+ { "f18", (RISCV_FIRST_FP_REGNUM + 18) },
+ { "f19", (RISCV_FIRST_FP_REGNUM + 19) },
+ { "f20", (RISCV_FIRST_FP_REGNUM + 20) },
+ { "f21", (RISCV_FIRST_FP_REGNUM + 21) },
+ { "f22", (RISCV_FIRST_FP_REGNUM + 22) },
+ { "f23", (RISCV_FIRST_FP_REGNUM + 23) },
+ { "f24", (RISCV_FIRST_FP_REGNUM + 24) },
+ { "f25", (RISCV_FIRST_FP_REGNUM + 25) },
+ { "f26", (RISCV_FIRST_FP_REGNUM + 26) },
+ { "f27", (RISCV_FIRST_FP_REGNUM + 27) },
+ { "f28", (RISCV_FIRST_FP_REGNUM + 28) },
+ { "f29", (RISCV_FIRST_FP_REGNUM + 29) },
+ { "f30", (RISCV_FIRST_FP_REGNUM + 30) },
+ { "f31", (RISCV_FIRST_FP_REGNUM + 31) },
};
/* Controls whether we place compressed breakpoints or not. When in auto
struct cmd_list_element *c,
const char *value)
{
- const char *additional_info;
- struct gdbarch *gdbarch = target_gdbarch ();
-
- if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO)
- if (riscv_has_feature (gdbarch, 'C'))
- additional_info = _(" (currently on)");
- else
- additional_info = _(" (currently off)");
- else
- additional_info = "";
-
fprintf_filtered (file,
_("Debugger's use of compressed breakpoints is set "
- "to %s%s.\n"), value, additional_info);
+ "to %s.\n"), value);
}
/* The set and show lists for 'set riscv' and 'show riscv' prefixes. */
c->name, value);
}
+/* When this is set to non-zero debugging information about breakpoint
+ kinds will be printed. */
+
+static unsigned int riscv_debug_breakpoints = 0;
+
/* When this is set to non-zero debugging information about inferior calls
will be printed. */
static unsigned int riscv_debug_infcall = 0;
-/* Read the MISA register from the target. The register will only be read
- once, and the value read will be cached. If the register can't be read
- from the target then a default value (0) will be returned. If the
- pointer READ_P is not null, then the bool pointed to is updated to
- indicate if the value returned was read from the target (true) or is the
- default (false). */
+/* When this is set to non-zero debugging information about stack unwinding
+ will be printed. */
+
+static unsigned int riscv_debug_unwinder = 0;
+
+/* Read the MISA register from the target. There are a couple of locations
+ that the register might be found, these are all tried. If the MISA
+ register can't be found at all then the default value of 0 is returned,
+ this is inline with the RISC-V specification. */
static uint32_t
-riscv_read_misa_reg (bool *read_p)
+riscv_read_misa_reg ()
{
uint32_t value = 0;
if (target_has_registers)
{
+ /* Old cores might have MISA located at a different offset. */
+ static int misa_regs[] =
+ { RISCV_CSR_MISA_REGNUM, RISCV_CSR_LEGACY_MISA_REGNUM };
+
struct frame_info *frame = get_current_frame ();
- TRY
- {
- value = get_frame_register_unsigned (frame,
- RISCV_CSR_MISA_REGNUM);
- }
- CATCH (ex, RETURN_MASK_ERROR)
+ for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
{
- /* Old cores might have MISA located at a different offset. */
- value = get_frame_register_unsigned (frame,
- RISCV_CSR_LEGACY_MISA_REGNUM);
+ bool success = false;
+
+ TRY
+ {
+ value = get_frame_register_unsigned (frame, misa_regs[i]);
+ success = true;
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ /* Ignore errors, it is acceptable for a target to not
+ provide a MISA register, in which case the default value
+ of 0 should be used. */
+ }
+ END_CATCH
+
+ if (success)
+ break;
}
- END_CATCH
}
return value;
static bool
riscv_has_feature (struct gdbarch *gdbarch, char feature)
{
- bool have_read_misa = false;
- uint32_t misa;
-
gdb_assert (feature >= 'A' && feature <= 'Z');
- misa = riscv_read_misa_reg (&have_read_misa);
- if (!have_read_misa || misa == 0)
+ uint32_t misa = riscv_read_misa_reg ();
+ if (misa == 0)
misa = gdbarch_tdep (gdbarch)->core_features;
return (misa & (1 << (feature - 'A'))) != 0;
}
-/* Return the width in bytes of the general purpose registers for GDBARCH.
- Possible return values are 4, 8, or 16 for RiscV variants RV32, RV64, or
- RV128. */
+/* See riscv-tdep.h. */
int
riscv_isa_xlen (struct gdbarch *gdbarch)
}
}
-/* Return the width in bytes of the floating point registers for GDBARCH.
- If this architecture has no floating point registers, then return 0.
- Possible values are 4, 8, or 16 for depending on which of single, double
- or quad floating point support is available. */
+/* See riscv-tdep.h. */
-static int
+int
riscv_isa_flen (struct gdbarch *gdbarch)
{
if (riscv_has_feature (gdbarch, 'Q'))
{
if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO)
{
- if (riscv_has_feature (gdbarch, 'C'))
+ gdb_byte buf[1];
+
+ /* Read the opcode byte to determine the instruction length. */
+ read_code (*pcptr, buf, 1);
+
+ if (riscv_debug_breakpoints)
+ fprintf_unfiltered
+ (gdb_stdlog,
+ "Using %s for breakpoint at %s (instruction length %d)\n",
+ riscv_insn_length (buf[0]) == 2 ? "C.EBREAK" : "EBREAK",
+ paddress (gdbarch, *pcptr), riscv_insn_length (buf[0]));
+ if (riscv_insn_length (buf[0]) == 2)
return 2;
else
return 4;
riscv_register_name (struct gdbarch *gdbarch, int regnum)
{
/* Prefer to use the alias. */
- if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
+ if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
- if (regnum == riscv_register_aliases[i].regnum)
- return riscv_register_aliases[i].name;
+ gdb_assert (regnum < ARRAY_SIZE (riscv_gdb_reg_names));
+ return riscv_gdb_reg_names[regnum];
}
- if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
- return riscv_gdb_reg_names[regnum];
+ /* Check that there's no gap between the set of registers handled above,
+ and the set of registers handled next. */
+ gdb_assert ((RISCV_LAST_FP_REGNUM + 1) == RISCV_FIRST_CSR_REGNUM);
if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
{
- static char buf[20];
+#define DECLARE_CSR(NAME,VALUE) \
+ case RISCV_ ## VALUE ## _REGNUM: return # NAME;
- xsnprintf (buf, sizeof (buf), "csr%d",
- regnum - RISCV_FIRST_CSR_REGNUM);
- return buf;
+ switch (regnum)
+ {
+ #include "opcode/riscv-opc.h"
+ default:
+ {
+ static char buf[20];
+
+ xsnprintf (buf, sizeof (buf), "csr%d",
+ regnum - RISCV_FIRST_CSR_REGNUM);
+ return buf;
+ }
+ }
+#undef DECLARE_CSR
}
if (regnum == RISCV_PRIV_REGNUM)
return NULL;
}
+/* Construct a type for 64-bit FP registers. */
+
+static struct type *
+riscv_fpreg_d_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->riscv_fpreg_d_type == nullptr)
+ {
+ const struct builtin_type *bt = builtin_type (gdbarch);
+
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_fpreg_d
+ {
+ float f;
+ double d;
+ };
+#endif
+
+ struct type *t;
+
+ t = arch_composite_type (gdbarch,
+ "__gdb_builtin_type_fpreg_d", TYPE_CODE_UNION);
+ append_composite_type_field (t, "float", bt->builtin_float);
+ append_composite_type_field (t, "double", bt->builtin_double);
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_fpreg_d";
+ tdep->riscv_fpreg_d_type = t;
+ }
+
+ return tdep->riscv_fpreg_d_type;
+}
+
+/* Construct a type for 128-bit FP registers. */
+
+static struct type *
+riscv_fpreg_q_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->riscv_fpreg_q_type == nullptr)
+ {
+ const struct builtin_type *bt = builtin_type (gdbarch);
+
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_fpreg_d
+ {
+ float f;
+ double d;
+ long double ld;
+ };
+#endif
+
+ struct type *t;
+
+ t = arch_composite_type (gdbarch,
+ "__gdb_builtin_type_fpreg_q", TYPE_CODE_UNION);
+ append_composite_type_field (t, "float", bt->builtin_float);
+ append_composite_type_field (t, "double", bt->builtin_double);
+ append_composite_type_field (t, "long double", bt->builtin_long_double);
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_fpreg_q";
+ tdep->riscv_fpreg_q_type = t;
+ }
+
+ return tdep->riscv_fpreg_q_type;
+}
+
/* Implement the register_type gdbarch method. */
static struct type *
case 4:
return builtin_type (gdbarch)->builtin_float;
case 8:
- return builtin_type (gdbarch)->builtin_double;
+ return riscv_fpreg_d_type (gdbarch);
case 16:
- return builtin_type (gdbarch)->builtin_long_double;
+ return riscv_fpreg_q_type (gdbarch);
default:
internal_error (__FILE__, __LINE__,
_("unknown isa regsize %i"), regsize);
print_raw_format = (value_entirely_available (val)
&& !value_optimized_out (val));
- if (TYPE_CODE (regtype) == TYPE_CODE_FLT)
+ if (TYPE_CODE (regtype) == TYPE_CODE_FLT
+ || (TYPE_CODE (regtype) == TYPE_CODE_UNION
+ && TYPE_NFIELDS (regtype) == 2
+ && TYPE_CODE (TYPE_FIELD_TYPE (regtype, 0)) == TYPE_CODE_FLT
+ && TYPE_CODE (TYPE_FIELD_TYPE (regtype, 1)) == TYPE_CODE_FLT)
+ || (TYPE_CODE (regtype) == TYPE_CODE_UNION
+ && TYPE_NFIELDS (regtype) == 3
+ && TYPE_CODE (TYPE_FIELD_TYPE (regtype, 0)) == TYPE_CODE_FLT
+ && TYPE_CODE (TYPE_FIELD_TYPE (regtype, 1)) == TYPE_CODE_FLT
+ && TYPE_CODE (TYPE_FIELD_TYPE (regtype, 2)) == TYPE_CODE_FLT))
{
struct value_print_options opts;
const gdb_byte *valaddr = value_contents_for_printing (val);
fprintf_filtered (file, "\n");
}
+/* Return true if REGNUM is a valid CSR register. The CSR register space
+ is sparsely populated, so not every number is a named CSR. */
+
+static bool
+riscv_is_regnum_a_named_csr (int regnum)
+{
+ gdb_assert (regnum >= RISCV_FIRST_CSR_REGNUM
+ && regnum <= RISCV_LAST_CSR_REGNUM);
+
+ switch (regnum)
+ {
+#define DECLARE_CSR(name, num) case RISCV_ ## num ## _REGNUM:
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/* Implement the register_reggroup_p gdbarch method. Is REGNUM a member
of REGGROUP? */
riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *reggroup)
{
- unsigned int i;
-
/* Used by 'info registers' and 'info registers <groupname>'. */
if (gdbarch_register_name (gdbarch, regnum) == NULL
{
if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
return 1;
- /* Only include CSRs that have aliases. */
- for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
- {
- if (regnum == riscv_register_aliases[i].regnum)
- return 1;
- }
+ if (riscv_is_regnum_a_named_csr (regnum))
+ return 1;
return 0;
}
else if (reggroup == float_reggroup)
return 1;
if (regnum < RISCV_FIRST_CSR_REGNUM || regnum > RISCV_LAST_CSR_REGNUM)
return 0;
- /* Only include CSRs that have aliases. */
- for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
- {
- if (regnum == riscv_register_aliases[i].regnum)
- return 1;
- }
+ if (riscv_is_regnum_a_named_csr (regnum))
+ return 1;
return 0;
}
else if (reggroup == vector_reggroup)
m_imm.s = EXTRACT_STYPE_IMM (ival);
}
+ /* Helper for DECODE, decode 16-bit CS-type instruction. The immediate
+ encoding is different for each CS format instruction, so extracting
+ the immediate is left up to the caller, who should pass the extracted
+ immediate value through in IMM. */
+ void decode_cs_type_insn (enum opcode opcode, ULONGEST ival, int imm)
+ {
+ m_opcode = opcode;
+ m_imm.s = imm;
+ m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
+ m_rs2 = decode_register_index_short (ival, OP_SH_CRS2S);
+ }
+
+ /* Helper for DECODE, decode 16-bit CSS-type instruction. The immediate
+ encoding is different for each CSS format instruction, so extracting
+ the immediate is left up to the caller, who should pass the extracted
+ immediate value through in IMM. */
+ void decode_css_type_insn (enum opcode opcode, ULONGEST ival, int imm)
+ {
+ m_opcode = opcode;
+ m_imm.s = imm;
+ m_rs1 = RISCV_SP_REGNUM;
+ /* Not a compressed register number in this case. */
+ m_rs2 = decode_register_index (ival, OP_SH_CRS2);
+ }
+
/* Helper for DECODE, decode 32-bit U-type instruction. */
void decode_u_type_insn (enum opcode opcode, ULONGEST ival)
{
m_rd = m_rs1 = decode_register_index (ival, OP_SH_RD);
m_imm.s = EXTRACT_RVC_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);
+ }
else if (is_c_lui_insn (ival))
- m_opcode = OTHER;
+ {
+ m_opcode = LUI;
+ m_rd = decode_register_index (ival, OP_SH_CRS1S);
+ m_imm.s = EXTRACT_RVC_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))
- m_opcode = OTHER;
+ decode_cs_type_insn (SD, ival, EXTRACT_RVC_LD_IMM (ival));
else if (is_c_sw_insn (ival))
- m_opcode = OTHER;
+ decode_cs_type_insn (SW, ival, EXTRACT_RVC_LW_IMM (ival));
+ else if (is_c_swsp_insn (ival))
+ decode_css_type_insn (SW, ival, EXTRACT_RVC_SWSP_IMM (ival));
+ else if (xlen != 4 && is_c_sdsp_insn (ival))
+ decode_css_type_insn (SW, ival, EXTRACT_RVC_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. */
else if (is_c_jr_insn (ival))
static CORE_ADDR
riscv_scan_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start_pc, CORE_ADDR limit_pc)
+ CORE_ADDR start_pc, CORE_ADDR end_pc,
+ struct riscv_unwind_cache *cache)
{
- CORE_ADDR cur_pc, next_pc;
- long frame_offset = 0;
+ CORE_ADDR cur_pc, next_pc, after_prologue_pc;
CORE_ADDR end_prologue_addr = 0;
- if (limit_pc > start_pc + 200)
- limit_pc = start_pc + 200;
-
- for (next_pc = cur_pc = start_pc; cur_pc < limit_pc; cur_pc = next_pc)
+ /* Find an upper limit on the function prologue using the debug
+ information. If the debug information could not be used to provide
+ that bound, then use an arbitrary large number as the upper bound. */
+ after_prologue_pc = skip_prologue_using_sal (gdbarch, start_pc);
+ if (after_prologue_pc == 0)
+ after_prologue_pc = start_pc + 100; /* Arbitrary large number. */
+ if (after_prologue_pc < end_pc)
+ end_pc = after_prologue_pc;
+
+ pv_t regs[RISCV_NUM_INTEGER_REGS]; /* Number of GPR. */
+ for (int regno = 0; regno < RISCV_NUM_INTEGER_REGS; regno++)
+ regs[regno] = pv_register (regno, 0);
+ pv_area stack (RISCV_SP_REGNUM, gdbarch_addr_bit (gdbarch));
+
+ if (riscv_debug_unwinder)
+ fprintf_unfiltered
+ (gdb_stdlog,
+ "Prologue scan for function starting at %s (limit %s)\n",
+ core_addr_to_string (start_pc),
+ core_addr_to_string (end_pc));
+
+ for (next_pc = cur_pc = start_pc; cur_pc < end_pc; cur_pc = next_pc)
{
struct riscv_insn insn;
{
/* Handle: addi sp, sp, -i
or: addiw sp, sp, -i */
- if (insn.imm_signed () < 0)
- frame_offset += insn.imm_signed ();
- else
- break;
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()]
+ = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
}
else if ((insn.opcode () == riscv_insn::SW
|| insn.opcode () == riscv_insn::SD)
or: sw reg, offset(s0)
or: sd reg, offset(s0) */
/* Instruction storing a register onto the stack. */
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
+ stack.store (pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ()),
+ (insn.opcode () == riscv_insn::SW ? 4 : 8),
+ regs[insn.rs2 ()]);
}
else if (insn.opcode () == riscv_insn::ADDI
&& insn.rd () == RISCV_FP_REGNUM
{
/* Handle: addi s0, sp, size */
/* Instructions setting up the frame pointer. */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()]
+ = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
}
else if ((insn.opcode () == riscv_insn::ADD
|| insn.opcode () == riscv_insn::ADDW)
/* Handle: add s0, sp, 0
or: addw s0, sp, 0 */
/* Instructions setting up the frame pointer. */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()] = pv_add_constant (regs[insn.rs1 ()], 0);
}
- else if ((insn.rd () == RISCV_GP_REGNUM
- && (insn.opcode () == riscv_insn::AUIPC
- || insn.opcode () == riscv_insn::LUI
- || (insn.opcode () == riscv_insn::ADDI
- && insn.rs1 () == RISCV_GP_REGNUM)
- || (insn.opcode () == riscv_insn::ADD
- && (insn.rs1 () == RISCV_GP_REGNUM
- || insn.rs2 () == RISCV_GP_REGNUM))))
- || (insn.opcode () == riscv_insn::ADDI
- && insn.rd () == RISCV_ZERO_REGNUM
- && insn.rs1 () == RISCV_ZERO_REGNUM
- && insn.imm_signed () == 0))
+ else if ((insn.opcode () == riscv_insn::ADDI
+ && insn.rd () == RISCV_ZERO_REGNUM
+ && insn.rs1 () == RISCV_ZERO_REGNUM
+ && insn.imm_signed () == 0))
{
- /* Handle: auipc gp, n
- or: addi gp, gp, n
- or: add gp, gp, reg
- or: add gp, reg, gp
- or: lui gp, n
- or: add x0, x0, 0 (NOP) */
- /* These instructions are part of the prologue, but we don't need
- to do anything special to handle them. */
+ /* Handle: add x0, x0, 0 (NOP) */
}
+ else if (insn.opcode () == riscv_insn::AUIPC)
+ {
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()] = pv_constant (cur_pc + insn.imm_signed ());
+ }
+ else if (insn.opcode () == riscv_insn::LUI)
+ {
+ /* Handle: lui REG, n
+ Where REG is not gp register. */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()] = pv_constant (insn.imm_signed ());
+ }
+ else if (insn.opcode () == riscv_insn::ADDI)
+ {
+ /* Handle: addi REG1, REG2, IMM */
+ gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+ gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
+ regs[insn.rd ()]
+ = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
+ }
+ else if (insn.opcode () == riscv_insn::ADD)
+ {
+ /* Handle: addi REG1, REG2, IMM */
+ 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 (end_prologue_addr == 0)
- end_prologue_addr = cur_pc;
+ end_prologue_addr = cur_pc;
+ break;
}
}
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
+ if (riscv_debug_unwinder)
+ fprintf_unfiltered (gdb_stdlog, "End of prologue at %s\n",
+ core_addr_to_string (end_prologue_addr));
+
+ if (cache != NULL)
+ {
+ /* Figure out if it is a frame pointer or just a stack pointer. Also
+ the offset held in the pv_t is from the original register value to
+ the current value, which for a grows down stack means a negative
+ value. The FRAME_BASE_OFFSET is the negation of this, how to get
+ from the current value to the original value. */
+ if (pv_is_register (regs[RISCV_FP_REGNUM], RISCV_SP_REGNUM))
+ {
+ cache->frame_base_reg = RISCV_FP_REGNUM;
+ cache->frame_base_offset = -regs[RISCV_FP_REGNUM].k;
+ }
+ else
+ {
+ cache->frame_base_reg = RISCV_SP_REGNUM;
+ cache->frame_base_offset = -regs[RISCV_SP_REGNUM].k;
+ }
+
+ /* Assign offset from old SP to all saved registers. As we don't
+ have the previous value for the frame base register at this
+ point, we store the offset as the address in the trad_frame, and
+ then convert this to an actual address later. */
+ for (int i = 0; i <= RISCV_NUM_INTEGER_REGS; i++)
+ {
+ CORE_ADDR offset;
+ if (stack.find_reg (gdbarch, i, &offset))
+ {
+ if (riscv_debug_unwinder)
+ fprintf_unfiltered (gdb_stdlog,
+ "Register $%s at stack offset %ld\n",
+ gdbarch_register_name (gdbarch, i),
+ offset);
+ trad_frame_set_addr (cache->regs, i, offset);
+ }
+ }
+ }
+
return end_prologue_addr;
}
/* Implement the riscv_skip_prologue gdbarch method. */
static CORE_ADDR
-riscv_skip_prologue (struct gdbarch *gdbarch,
- CORE_ADDR pc)
+riscv_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- CORE_ADDR limit_pc;
CORE_ADDR func_addr;
/* See if we can determine the end of the prologue via the symbol
}
/* Can't determine prologue from the symbol table, need to examine
- instructions. */
-
- /* Find an upper limit on the function prologue using the debug
- information. If the debug information could not be used to provide
- that bound, then use an arbitrary large number as the upper bound. */
- limit_pc = skip_prologue_using_sal (gdbarch, pc);
- if (limit_pc == 0)
- limit_pc = pc + 100; /* MAGIC! */
-
- return riscv_scan_prologue (gdbarch, pc, limit_pc);
+ instructions. Pass -1 for the end address to indicate the prologue
+ scanner can scan as far as it needs to find the end of the prologue. */
+ return riscv_scan_prologue (gdbarch, pc, ((CORE_ADDR) -1), NULL);
}
/* Implement the gdbarch push dummy code callback. */
struct riscv_arg_info *arg_info =
(struct riscv_arg_info *) alloca (nargs * sizeof (struct riscv_arg_info));
- struct riscv_arg_info *info;
struct riscv_call_info call_info (gdbarch);
if (struct_return)
++call_info.int_regs.next_regnum;
- for (i = 0, info = &arg_info[0];
- i < nargs;
- ++i, ++info)
+ for (i = 0; i < nargs; ++i)
{
struct value *arg_value;
struct type *arg_type;
+ struct riscv_arg_info *info = &arg_info[i];
arg_value = args[i];
arg_type = check_typedef (value_type (arg_value));
gdb_byte tmp [sizeof (ULONGEST)];
gdb_assert (info->argloc[0].c_length <= info->length);
- memset (tmp, 0, sizeof (tmp));
+ /* 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_length);
regcache->cooked_write (info->argloc[0].loc_data.regno, tmp);
second_arg_length =
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);
- memset (tmp, 0, sizeof (tmp));
+ /* 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);
}
/* Generate, or return the cached frame cache for the RiscV frame
unwinder. */
-static struct trad_frame_cache *
+static struct riscv_unwind_cache *
riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
{
- CORE_ADDR pc;
- CORE_ADDR start_addr;
- CORE_ADDR stack_addr;
- struct trad_frame_cache *this_trad_cache;
+ CORE_ADDR pc, start_addr;
+ struct riscv_unwind_cache *cache;
struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ int numregs, regno;
if ((*this_cache) != NULL)
- return (struct trad_frame_cache *) *this_cache;
- this_trad_cache = trad_frame_cache_zalloc (this_frame);
- (*this_cache) = this_trad_cache;
+ return (struct riscv_unwind_cache *) *this_cache;
- trad_frame_set_reg_realreg (this_trad_cache, gdbarch_pc_regnum (gdbarch),
- RISCV_RA_REGNUM);
+ cache = FRAME_OBSTACK_ZALLOC (struct riscv_unwind_cache);
+ cache->regs = trad_frame_alloc_saved_regs (this_frame);
+ (*this_cache) = cache;
+ /* Scan the prologue, filling in the cache. */
+ start_addr = get_frame_func (this_frame);
pc = get_frame_pc (this_frame);
- find_pc_partial_function (pc, NULL, &start_addr, NULL);
- stack_addr = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
- trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
+ riscv_scan_prologue (gdbarch, start_addr, pc, cache);
+
+ /* We can now calculate the frame base address. */
+ cache->frame_base
+ = (get_frame_register_signed (this_frame, cache->frame_base_reg)
+ + cache->frame_base_offset);
+ if (riscv_debug_unwinder)
+ fprintf_unfiltered (gdb_stdlog, "Frame base is %s ($%s + 0x%x)\n",
+ core_addr_to_string (cache->frame_base),
+ gdbarch_register_name (gdbarch,
+ cache->frame_base_reg),
+ cache->frame_base_offset);
+
+ /* The prologue scanner sets the address of registers stored to the stack
+ as the offset of that register from the frame base. The prologue
+ scanner doesn't know the actual frame base value, and so is unable to
+ compute the exact address. We do now know the frame base value, so
+ update the address of registers stored to the stack. */
+ numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+ for (regno = 0; regno < numregs; ++regno)
+ {
+ if (trad_frame_addr_p (cache->regs, regno))
+ cache->regs[regno].addr += cache->frame_base;
+ }
- trad_frame_set_this_base (this_trad_cache, stack_addr);
+ /* The previous $pc can be found wherever the $ra value can be found.
+ 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);
- return this_trad_cache;
+ /* 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);
+
+ return cache;
}
/* Implement the this_id callback for RiscV frame unwinder. */
void **prologue_cache,
struct frame_id *this_id)
{
- struct trad_frame_cache *info;
+ struct riscv_unwind_cache *cache;
- info = riscv_frame_cache (this_frame, prologue_cache);
- trad_frame_get_id (info, this_id);
+ cache = riscv_frame_cache (this_frame, prologue_cache);
+ *this_id = cache->this_id;
}
/* Implement the prev_register callback for RiscV frame unwinder. */
void **prologue_cache,
int regnum)
{
- struct trad_frame_cache *info;
+ struct riscv_unwind_cache *cache;
- info = riscv_frame_cache (this_frame, prologue_cache);
- return trad_frame_get_register (info, this_frame, regnum);
+ cache = riscv_frame_cache (this_frame, prologue_cache);
+ return trad_frame_get_prev_register (this_frame, cache->regs, regnum);
}
/* Structure defining the RiscV normal frame unwind functions. Since we
set_gdbarch_return_value (gdbarch, riscv_return_value);
set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
/* Register architecture. */
set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
&showdebugriscvcmdlist, "show debug riscv ", 0,
&showdebuglist);
+ add_setshow_zuinteger_cmd ("breakpoints", class_maintenance,
+ &riscv_debug_breakpoints, _("\
+Set riscv breakpoint debugging."), _("\
+Show riscv breakpoint debugging."), _("\
+When non-zero, print debugging information for the riscv specific parts\n\
+of the breakpoint mechanism."),
+ NULL,
+ show_riscv_debug_variable,
+ &setdebugriscvcmdlist, &showdebugriscvcmdlist);
+
add_setshow_zuinteger_cmd ("infcall", class_maintenance,
&riscv_debug_infcall, _("\
Set riscv inferior call debugging."), _("\
show_riscv_debug_variable,
&setdebugriscvcmdlist, &showdebugriscvcmdlist);
+ add_setshow_zuinteger_cmd ("unwinder", class_maintenance,
+ &riscv_debug_unwinder, _("\
+Set riscv stack unwinding debugging."), _("\
+Show riscv stack unwinding debugging."), _("\
+When non-zero, print debugging information for the riscv specific parts\n\
+of the stack unwinding mechanism."),
+ NULL,
+ show_riscv_debug_variable,
+ &setdebugriscvcmdlist, &showdebugriscvcmdlist);
+
/* Add root prefix command for all "set riscv" and "show riscv" commands. */
add_prefix_cmd ("riscv", no_class, set_riscv_command,
_("RISC-V specific commands."),
_("\
Set debugger's use of compressed breakpoints."), _(" \
Show debugger's use of compressed breakpoints."), _("\
-Debugging compressed code requires compressed breakpoints to be used. If\n \
-left to 'auto' then gdb will use them if $misa indicates the C extension\n \
-is supported. If that doesn't give the correct behavior, then this option\n\
-can be used."),
+Debugging compressed code requires compressed breakpoints to be used. If\n\
+left to 'auto' then gdb will use them if the existing instruction is a\n\
+compressed instruction. If that doesn't give the correct behavior, then\n\
+this option can be used."),
NULL,
show_use_compressed_breakpoints,
&setriscvcmdlist,