/* Target-dependent code for the RISC-V architecture, for GDB.
- Copyright (C) 2018 Free Software Foundation, Inc.
+ Copyright (C) 2018-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "dwarf2-frame.h"
#include "user-regs.h"
#include "valprint.h"
-#include "common-defs.h"
+#include "common/common-defs.h"
#include "opcode/riscv-opc.h"
#include "cli/cli-decode.h"
#include "observable.h"
{ RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true },
{ RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true },
{ RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true },
- { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true },
+ { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8" }, true },
{ RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true },
{ RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true },
{ RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true },
int
riscv_isa_xlen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->features.xlen;
+ return gdbarch_tdep (gdbarch)->isa_features.xlen;
+}
+
+/* See riscv-tdep.h. */
+
+int
+riscv_abi_xlen (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->abi_features.xlen;
}
/* See riscv-tdep.h. */
int
riscv_isa_flen (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->features.flen;
+ return gdbarch_tdep (gdbarch)->isa_features.flen;
+}
+
+/* See riscv-tdep.h. */
+
+int
+riscv_abi_flen (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->abi_features.flen;
}
/* Return true if the target for GDBARCH has floating point hardware. */
static bool
riscv_has_fp_abi (struct gdbarch *gdbarch)
{
- return gdbarch_tdep (gdbarch)->features.hw_float_abi;
+ return gdbarch_tdep (gdbarch)->abi_features.flen > 0;
}
/* Return true if REGNO is a floating pointer register. */
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);
}
}
default:
error (_("Could not compute alignment of type"));
+ case TYPE_CODE_RANGE:
case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_PTR:
case TYPE_CODE_ENUM:
: int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7),
float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7)
{
- xlen = riscv_isa_xlen (gdbarch);
- flen = riscv_isa_flen (gdbarch);
+ xlen = riscv_abi_xlen (gdbarch);
+ flen = riscv_abi_flen (gdbarch);
/* Disable use of floating point registers if needed. */
if (!riscv_has_fp_abi (gdbarch))
struct riscv_arg_reg float_regs;
/* The XLEN and FLEN are copied in to this structure for convenience, and
- are just the results of calling RISCV_ISA_XLEN and RISCV_ISA_FLEN. */
+ are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. */
int xlen;
int flen;
};
{
int len0, len1, offset;
- gdb_assert (TYPE_LENGTH (ainfo->type)
- <= (cinfo->flen + cinfo->xlen));
-
len0 = TYPE_LENGTH (sinfo.field_type (0));
if (!riscv_assign_reg_location (&ainfo->argloc[0],
&cinfo->float_regs, len0, 0))
{
int len0, len1, offset;
- gdb_assert (TYPE_LENGTH (ainfo->type)
- <= (cinfo->flen + cinfo->xlen));
-
len0 = TYPE_LENGTH (sinfo.field_type (0));
len1 = TYPE_LENGTH (sinfo.field_type (1));
offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1)));
/* 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)
return align_down (addr, 16);
}
-/* Implement the unwind_pc gdbarch method. */
-
-static CORE_ADDR
-riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM);
-}
-
-/* Implement the unwind_sp gdbarch method. */
-
-static CORE_ADDR
-riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM);
-}
-
-/* Implement the dummy_id gdbarch method. */
-
-static struct frame_id
-riscv_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
- return frame_id_build (get_frame_register_signed (this_frame, RISCV_SP_REGNUM),
- get_frame_pc (this_frame));
-}
-
/* Generate, or return the cached frame cache for the RiscV frame
unwinder. */
_("unknown ELF header class %d"), eclass);
if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
- {
- features.flen = 8;
- features.hw_float_abi = true;
- }
+ features.flen = 8;
else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
- {
- features.flen = 4;
- features.hw_float_abi = true;
- }
+ features.flen = 4;
}
else
{
}
}
+/* 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.
/* 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
+ struct riscv_gdbarch_features abi_features
= riscv_features_from_gdbarch_info (info);
- if (info_features.xlen != 0 && info_features.xlen != features.xlen)
+ /* In theory a binary compiled for RV32 could run on an RV64 target,
+ however, this has not been tested in GDB yet, so for now we require
+ that the requested xlen match the targets xlen. */
+ if (abi_features.xlen != 0 && abi_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)
+ abi_features.xlen, features.xlen);
+ /* We do support running binaries compiled for 32-bit float on targets
+ with 64-bit float, so we only complain if the binary requires more
+ than the target has available. */
+ if (abi_features.flen > features.flen)
error (_("bfd requires flen %d, but target has flen %d"),
- info_features.flen, features.flen);
+ abi_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);
+ /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
+ features from the INFO object. In this case we assume that the xlen
+ abi matches the hardware. */
+ if (abi_features.xlen == 0)
+ abi_features.xlen = features.xlen;
/* Find a candidate among the list of pre-declared architectures. */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
gdbarch. */
struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
- if (other_tdep->features != features)
+ if (other_tdep->isa_features != features
+ || other_tdep->abi_features != abi_features)
continue;
break;
/* None found, so create a new architecture from the information provided. */
tdep = new (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
- tdep->features = features;
+ tdep->isa_features = features;
+ tdep->abi_features = abi_features;
/* Target data types. */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_frame_align (gdbarch, riscv_frame_align);
- /* Functions to access frame data. */
- set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc);
- set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp);
-
/* Functions handling dummy frames. */
set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
- set_gdbarch_dummy_id (gdbarch, riscv_dummy_id);
/* Frame unwinders. Use DWARF debug info if available, otherwise use our own
unwinder. */
/* 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