switch (regnum)
{
- #include "opcode/riscv-opc.h"
+#include "opcode/riscv-opc.h"
}
#undef DECLARE_CSR
}
int size = register_size (gdbarch, regnum);
unsigned xlen;
+ /* The SD field is always in the upper bit of MSTATUS, regardless
+ of the number of bits in MSTATUS. */
d = value_as_long (val);
- xlen = size * 4;
+ xlen = size * 8;
fprintf_filtered (file,
"\tSD:%X VM:%02X MXR:%X PUM:%X MPRV:%X XS:%X "
"FS:%X MPP:%x HPP:%X SPP:%X MPIE:%X HPIE:%X "
int base;
unsigned xlen, i;
LONGEST d;
+ int size = register_size (gdbarch, regnum);
+ /* The MXL field is always in the upper two bits of MISA,
+ regardless of the number of bits in MISA. Mask out other
+ bits to ensure we have a positive value. */
d = value_as_long (val);
- base = d >> 30;
+ base = (d >> ((size * 8) - 2)) & 0x3;
xlen = 16;
for (; base > 0; base--)
else if (reggroup == restore_reggroup || reggroup == save_reggroup)
{
if (riscv_has_fp_regs (gdbarch))
- return regnum <= RISCV_LAST_FP_REGNUM;
+ return (regnum <= RISCV_LAST_FP_REGNUM
+ || regnum == RISCV_CSR_FCSR_REGNUM
+ || regnum == RISCV_CSR_FFLAGS_REGNUM
+ || regnum == RISCV_CSR_FRM_REGNUM);
else
return regnum < RISCV_FIRST_FP_REGNUM;
}
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);
+ {
+ /* Display OFFSET as a signed value, the offsets are from
+ the frame base address to the registers location on
+ the stack, with a descending stack this means the
+ offsets are always negative. */
+ fprintf_unfiltered (gdb_stdlog,
+ "Register $%s at stack offset %s\n",
+ gdbarch_register_name (gdbarch, i),
+ plongest ((LONGEST) offset));
+ }
trad_frame_set_addr (cache->regs, i, offset);
}
}
riscv_call_arg_scalar_float (struct riscv_arg_info *ainfo,
struct riscv_call_info *cinfo)
{
- if (ainfo->length > cinfo->flen)
+ if (ainfo->length > cinfo->flen || ainfo->is_unnamed)
return riscv_call_arg_scalar_int (ainfo, cinfo);
else
{
struct riscv_call_info *cinfo)
{
if (ainfo->length <= (2 * cinfo->flen)
- && riscv_arg_regs_available (&cinfo->float_regs) >= 2)
+ && riscv_arg_regs_available (&cinfo->float_regs) >= 2
+ && !ainfo->is_unnamed)
{
bool result;
int len = ainfo->length / 2;
/* Non of the structure flattening cases apply, so we just pass using
the integer ABI. */
- ainfo->length = align_up (ainfo->length, cinfo->xlen);
riscv_call_arg_scalar_int (ainfo, cinfo);
}
if (readbuf != nullptr || writebuf != nullptr)
{
- int regnum;
+ unsigned int arg_len;
+ struct value *abi_val;
+ gdb_byte *old_readbuf = nullptr;
+ int regnum;
+
+ /* We only do one thing at a time. */
+ gdb_assert (readbuf == nullptr || writebuf == nullptr);
+
+ /* In some cases the argument is not returned as the declared type,
+ and we need to cast to or from the ABI type in order to
+ correctly access the argument. When writing to the machine we
+ do the cast here, when reading from the machine the cast occurs
+ later, after extracting the value. As the ABI type can be
+ larger than the declared type, then the read or write buffers
+ passed in might be too small. Here we ensure that we are using
+ 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);
+ }
+ else
+ {
+ abi_val = allocate_value (info.type);
+ old_readbuf = readbuf;
+ readbuf = value_contents_raw (abi_val);
+ }
+ arg_len = TYPE_LENGTH (info.type);
switch (info.argloc[0].loc_type)
{
case riscv_arg_info::location::in_reg:
{
regnum = info.argloc[0].loc_data.regno;
+ gdb_assert (info.argloc[0].c_length <= arg_len);
+ gdb_assert (info.argloc[0].c_length
+ <= register_size (gdbarch, regnum));
if (readbuf)
- regcache->cooked_read (regnum, readbuf);
+ regcache->cooked_read_part (regnum, 0,
+ info.argloc[0].c_length,
+ readbuf);
if (writebuf)
- regcache->cooked_write (regnum, writebuf);
+ regcache->cooked_write_part (regnum, 0,
+ info.argloc[0].c_length,
+ writebuf);
/* A return value in register can have a second part in a
second register. */
case riscv_arg_info::location::in_reg:
regnum = info.argloc[1].loc_data.regno;
+ gdb_assert ((info.argloc[0].c_length
+ + info.argloc[1].c_length) <= arg_len);
+ gdb_assert (info.argloc[1].c_length
+ <= register_size (gdbarch, regnum));
+
if (readbuf)
{
readbuf += info.argloc[1].c_offset;
- regcache->cooked_read (regnum, readbuf);
+ regcache->cooked_read_part (regnum, 0,
+ info.argloc[1].c_length,
+ readbuf);
}
if (writebuf)
{
writebuf += info.argloc[1].c_offset;
- regcache->cooked_write (regnum, writebuf);
+ regcache->cooked_write_part (regnum, 0,
+ info.argloc[1].c_length,
+ writebuf);
}
break;
error (_("invalid argument location"));
break;
}
+
+ /* This completes the cast from abi type back to the declared type
+ in the case that we are reading from the machine. See the
+ 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),
+ TYPE_LENGTH (arg_type));
+ }
}
switch (info.argloc[0].loc_type)
/*.prev_arch =*/ NULL,
};
-/* Find a suitable default target description. Use the contents of INFO,
- specifically the bfd object being executed, to guide the selection of a
- suitable default target description. */
+/* 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. */
-static const struct target_desc *
-riscv_find_default_target_description (const struct gdbarch_info info)
+static struct riscv_gdbarch_features
+riscv_features_from_gdbarch_info (const struct gdbarch_info info)
{
struct riscv_gdbarch_features features;
- /* Setup some arbitrary defaults. */
- features.xlen = 8;
- features.flen = 0;
- features.hw_float_abi = false;
-
/* Now try to improve on the defaults by looking at the binary we are
going to execute. We assume the user knows what they are doing and
that the target will match the binary. Remember, this code path is
binfo->bits_per_word);
}
+ return features;
+}
+
+/* Find a suitable default target description. Use the contents of INFO,
+ specifically the bfd object being executed, to guide the selection of a
+ suitable default target description. */
+
+static const struct target_desc *
+riscv_find_default_target_description (const struct gdbarch_info info)
+{
+ /* Extract desired feature set from INFO. */
+ struct riscv_gdbarch_features features
+ = riscv_features_from_gdbarch_info (info);
+
+ /* 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 (features.xlen == 0)
+ features.xlen = 8;
+
/* Now build a target description based on the feature set. */
return riscv_create_target_description (features);
}
}
}
+/* Implement the "dwarf2_reg_to_regnum" gdbarch method. */
+
+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);
+
+ else if (reg < RISCV_DWARF_REGNUM_F31)
+ return RISCV_FIRST_FP_REGNUM + (reg - RISCV_DWARF_REGNUM_F0);
+
+ return -1;
+}
+
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
features.flen = (bitsize / 8);
- features.hw_float_abi = true;
if (riscv_debug_gdbarch)
fprintf_filtered
else
{
features.flen = 0;
- features.hw_float_abi = false;
if (riscv_debug_gdbarch)
fprintf_filtered
return NULL;
}
+ /* Have a look at what the supplied (if any) bfd object requires of the
+ target, then check that this matches with what the target is
+ providing. */
+ struct riscv_gdbarch_features info_features
+ = riscv_features_from_gdbarch_info (info);
+ if (info_features.xlen != 0 && info_features.xlen != features.xlen)
+ error (_("bfd requires xlen %d, but target has xlen %d"),
+ info_features.xlen, features.xlen);
+ if (info_features.flen != 0 && info_features.flen != features.flen)
+ error (_("bfd requires flen %d, but target has flen %d"),
+ info_features.flen, features.flen);
+
+ /* If the xlen from INFO_FEATURES is 0 then this indicates either there
+ is no bfd object, or nothing useful could be extracted from it, in
+ this case we enable hardware float abi if the target has floating
+ point registers.
+
+ If the xlen from INFO_FEATURES is not 0, and the flen in
+ INFO_FEATURES is also not 0, then this indicates that the supplied
+ bfd does require hardware floating point abi. */
+ if (info_features.xlen == 0 || info_features.flen != 0)
+ features.hw_float_abi = (features.flen > 0);
+
/* Find a candidate among the list of pre-declared architectures. */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
gdbarch. */
struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
- if (other_tdep->features.hw_float_abi != features.hw_float_abi
- || other_tdep->features.xlen != features.xlen
- || other_tdep->features.flen != features.flen)
+ if (other_tdep->features != features)
continue;
break;
/* Register architecture. */
riscv_add_reggroups (gdbarch);
+ /* Internal <-> external register number maps. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, riscv_dwarf_reg_to_regnum);
+
/* We reserve all possible register numbers for the known registers.
This means the target description mechanism will add any target
specific registers after this number. This helps make debugging GDB