/* The stack must be 16-byte aligned. */
#define SP_ALIGNMENT 16
+/* The biggest alignment that the target supports. */
+#define BIGGEST_ALIGNMENT 16
+
/* Forward declarations. */
static bool riscv_has_feature (struct gdbarch *gdbarch, char feature);
CORE_ADDR frame_base;
};
-/* Architectural name for core registers. */
+/* 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_unwinder = 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). */
+/* 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
+ for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
{
- value = get_frame_register_unsigned (frame,
- RISCV_CSR_MISA_REGNUM);
- }
- CATCH (ex, RETURN_MASK_ERROR)
- {
- /* 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'))
+ bool unaligned_p = false;
+ gdb_byte buf[1];
+
+ /* Some targets don't support unaligned reads. The address can only
+ be unaligned if the C extension is supported. So it is safe to
+ use a compressed breakpoint in this case. */
+ if (*pcptr & 0x2)
+ unaligned_p = true;
+ else
+ {
+ /* Read the opcode byte to determine the instruction length. */
+ read_code (*pcptr, buf, 1);
+ }
+
+ if (riscv_debug_breakpoints)
+ {
+ const char *bp = (unaligned_p || riscv_insn_length (buf[0]) == 2
+ ? "C.EBREAK" : "EBREAK");
+
+ fprintf_unfiltered (gdb_stdlog, "Using %s for breakpoint at %s ",
+ bp, paddress (gdbarch, *pcptr));
+ if (unaligned_p)
+ fprintf_unfiltered (gdb_stdlog, "(unaligned address)\n");
+ else
+ fprintf_unfiltered (gdb_stdlog, "(instruction length %d)\n",
+ riscv_insn_length (buf[0]));
+ }
+ if (unaligned_p || 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)
return extract_unsigned_integer (buf, instlen, byte_order);
}
-/* Fetch from target memory an instruction at PC and decode it. */
+/* Fetch from target memory an instruction at PC and decode it. This can
+ throw an error if the memory access fails, callers are responsible for
+ handling this error if that is appropriate. */
void
riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
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))
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
{
end_prologue_addr = cur_pc;
return TYPE_LENGTH (t);
case TYPE_CODE_ARRAY:
+ if (TYPE_VECTOR (t))
+ return std::min (TYPE_LENGTH (t), (unsigned) BIGGEST_ALIGNMENT);
+ /* FALLTHROUGH */
+
case TYPE_CODE_COMPLEX:
return riscv_type_alignment (TYPE_TARGET_TYPE (t));
then this offset will be set to 0. */
int c_offset;
} argloc[2];
+
+ /* TRUE if this is an unnamed argument. */
+ bool is_unnamed;
};
/* Information about a set of registers being used for passing arguments as
}
else
{
- int len = (ainfo->length > cinfo->xlen) ? cinfo->xlen : ainfo->length;
+ int len = std::min (ainfo->length, cinfo->xlen);
+ int align = std::max (ainfo->align, cinfo->xlen);
+
+ /* Unnamed arguments in registers that require 2*XLEN alignment are
+ passed in an aligned register pair. */
+ if (ainfo->is_unnamed && (align == cinfo->xlen * 2)
+ && cinfo->int_regs.next_regnum & 1)
+ cinfo->int_regs.next_regnum++;
if (!riscv_assign_reg_location (&ainfo->argloc[0],
&cinfo->int_regs, len, 0))
riscv_assign_stack_location (&ainfo->argloc[0],
- &cinfo->memory, len, ainfo->align);
+ &cinfo->memory, len, align);
if (len < ainfo->length)
{
selected from CINFO which holds information about what call argument
locations are available for use next. The TYPE is the type of the
argument being passed, this information is recorded into AINFO (along
- with some additional information derived from the type).
+ with some additional information derived from the type). IS_UNNAMED
+ is true if this is an unnamed (stdarg) argument, this info is also
+ recorded into AINFO.
After assigning a location to AINFO, CINFO will have been updated. */
riscv_arg_location (struct gdbarch *gdbarch,
struct riscv_arg_info *ainfo,
struct riscv_call_info *cinfo,
- struct type *type)
+ struct type *type, bool is_unnamed)
{
ainfo->type = type;
ainfo->length = TYPE_LENGTH (ainfo->type);
ainfo->align = riscv_type_alignment (ainfo->type);
+ ainfo->is_unnamed = is_unnamed;
ainfo->contents = nullptr;
switch (TYPE_CODE (ainfo->type))
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);
CORE_ADDR osp = sp;
+ struct type *ftype = check_typedef (value_type (function));
+
+ if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+ ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+
/* We'll use register $a0 if we're returning a struct. */
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));
- riscv_arg_location (gdbarch, info, &call_info, arg_type);
+ riscv_arg_location (gdbarch, info, &call_info, arg_type,
+ TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype));
if (info->type != arg_type)
arg_value = value_cast (info->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);
}
struct type *arg_type;
arg_type = check_typedef (type);
- riscv_arg_location (gdbarch, &info, &call_info, arg_type);
+ riscv_arg_location (gdbarch, &info, &call_info, arg_type, false);
if (riscv_debug_infcall > 0)
{
/* 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);
+ = (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),
{
struct riscv_unwind_cache *cache;
- cache = riscv_frame_cache (this_frame, prologue_cache);
- *this_id = cache->this_id;
+ TRY
+ {
+ cache = riscv_frame_cache (this_frame, prologue_cache);
+ *this_id = cache->this_id;
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ /* Ignore errors, this leaves the frame id as the predefined outer
+ frame id which terminates the backtrace at this point. */
+ }
+ END_CATCH
}
/* Implement the prev_register callback for RiscV frame unwinder. */
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."), _("\
_("\
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,