X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Friscv-tdep.c;h=a8b057f622befe1c39c00dcd8858580e48aa792c;hb=3cb5a3a16af2cae1a5059b7571c514b3fa575df9;hp=408ab0af24b73a3ca9c1470b722be371b08b6bcf;hpb=cf84fa6bcf514157df8343d32885050bafc396f7;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 408ab0af24..a8b057f622 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1,6 +1,6 @@ /* 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. @@ -50,11 +50,13 @@ #include "dwarf2-frame.h" #include "user-regs.h" #include "valprint.h" -#include "common-defs.h" +#include "gdbsupport/common-defs.h" #include "opcode/riscv-opc.h" #include "cli/cli-decode.h" #include "observable.h" #include "prologue-value.h" +#include "arch/riscv.h" +#include "riscv-ravenscar-thread.h" /* The stack must be 16-byte aligned. */ #define SP_ALIGNMENT 16 @@ -62,9 +64,6 @@ /* The biggest alignment that the target supports. */ #define BIGGEST_ALIGNMENT 16 -/* Forward declarations. */ -static bool riscv_has_feature (struct gdbarch *gdbarch, char feature); - /* Define a series of is_XXX_insn functions to check if the value INSN is an instance of instruction XXX. */ #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \ @@ -98,110 +97,170 @@ struct riscv_unwind_cache 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. */ +/* RISC-V specific register group for CSRs. */ -static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] = -{ - "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", -}; +static reggroup *csr_reggroup = NULL; -/* Map alternative register names onto their GDB register number. */ +/* A set of registers that we expect to find in a tdesc_feature. These + are use in RISCV_GDBARCH_INIT when processing the target description. */ -struct riscv_register_alias +struct riscv_register_feature { - /* The register alias. Usually more descriptive than the - architectural name of the register. */ + /* Information for a single register. */ + struct register_info + { + /* The GDB register number for this register. */ + int regnum; + + /* List of names for this register. The first name in this list is the + preferred name, the name GDB should use when describing this + register. */ + std::vector names; + + /* When true this register is required in this feature set. */ + bool required_p; + }; + + /* The name for this feature. This is the name used to find this feature + within the target description. */ const char *name; - /* The GDB register number. */ - int regnum; + /* List of all the registers that we expect that we might find in this + register set. */ + std::vector registers; +}; + +/* The general x-registers feature set. */ + +static const struct riscv_register_feature riscv_xreg_feature = +{ + "org.gnu.gdb.riscv.cpu", + { + { RISCV_ZERO_REGNUM + 0, { "zero", "x0" }, true }, + { RISCV_ZERO_REGNUM + 1, { "ra", "x1" }, true }, + { RISCV_ZERO_REGNUM + 2, { "sp", "x2" }, true }, + { RISCV_ZERO_REGNUM + 3, { "gp", "x3" }, true }, + { RISCV_ZERO_REGNUM + 4, { "tp", "x4" }, true }, + { RISCV_ZERO_REGNUM + 5, { "t0", "x5" }, true }, + { RISCV_ZERO_REGNUM + 6, { "t1", "x6" }, true }, + { RISCV_ZERO_REGNUM + 7, { "t2", "x7" }, true }, + { RISCV_ZERO_REGNUM + 8, { "fp", "x8", "s0" }, true }, + { RISCV_ZERO_REGNUM + 9, { "s1", "x9" }, true }, + { RISCV_ZERO_REGNUM + 10, { "a0", "x10" }, true }, + { RISCV_ZERO_REGNUM + 11, { "a1", "x11" }, true }, + { RISCV_ZERO_REGNUM + 12, { "a2", "x12" }, true }, + { RISCV_ZERO_REGNUM + 13, { "a3", "x13" }, true }, + { RISCV_ZERO_REGNUM + 14, { "a4", "x14" }, true }, + { RISCV_ZERO_REGNUM + 15, { "a5", "x15" }, true }, + { RISCV_ZERO_REGNUM + 16, { "a6", "x16" }, true }, + { RISCV_ZERO_REGNUM + 17, { "a7", "x17" }, true }, + { RISCV_ZERO_REGNUM + 18, { "s2", "x18" }, true }, + { RISCV_ZERO_REGNUM + 19, { "s3", "x19" }, true }, + { RISCV_ZERO_REGNUM + 20, { "s4", "x20" }, true }, + { RISCV_ZERO_REGNUM + 21, { "s5", "x21" }, true }, + { RISCV_ZERO_REGNUM + 22, { "s6", "x22" }, true }, + { RISCV_ZERO_REGNUM + 23, { "s7", "x23" }, true }, + { RISCV_ZERO_REGNUM + 24, { "s8", "x24" }, true }, + { RISCV_ZERO_REGNUM + 25, { "s9", "x25" }, true }, + { RISCV_ZERO_REGNUM + 26, { "s10", "x26" }, true }, + { RISCV_ZERO_REGNUM + 27, { "s11", "x27" }, true }, + { RISCV_ZERO_REGNUM + 28, { "t3", "x28" }, true }, + { RISCV_ZERO_REGNUM + 29, { "t4", "x29" }, true }, + { RISCV_ZERO_REGNUM + 30, { "t5", "x30" }, true }, + { RISCV_ZERO_REGNUM + 31, { "t6", "x31" }, true }, + { RISCV_ZERO_REGNUM + 32, { "pc" }, true } + } }; -/* Table of register aliases. */ - -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) }, +/* The f-registers feature set. */ + +static const struct riscv_register_feature riscv_freg_feature = +{ + "org.gnu.gdb.riscv.fpu", + { + { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" }, true }, + { RISCV_FIRST_FP_REGNUM + 1, { "ft1", "f1" }, true }, + { RISCV_FIRST_FP_REGNUM + 2, { "ft2", "f2" }, true }, + { RISCV_FIRST_FP_REGNUM + 3, { "ft3", "f3" }, true }, + { RISCV_FIRST_FP_REGNUM + 4, { "ft4", "f4" }, true }, + { 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" }, 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 }, + { RISCV_FIRST_FP_REGNUM + 12, { "fa2", "f12" }, true }, + { RISCV_FIRST_FP_REGNUM + 13, { "fa3", "f13" }, true }, + { RISCV_FIRST_FP_REGNUM + 14, { "fa4", "f14" }, true }, + { RISCV_FIRST_FP_REGNUM + 15, { "fa5", "f15" }, true }, + { RISCV_FIRST_FP_REGNUM + 16, { "fa6", "f16" }, true }, + { RISCV_FIRST_FP_REGNUM + 17, { "fa7", "f17" }, true }, + { RISCV_FIRST_FP_REGNUM + 18, { "fs2", "f18" }, true }, + { RISCV_FIRST_FP_REGNUM + 19, { "fs3", "f19" }, true }, + { RISCV_FIRST_FP_REGNUM + 20, { "fs4", "f20" }, true }, + { RISCV_FIRST_FP_REGNUM + 21, { "fs5", "f21" }, true }, + { RISCV_FIRST_FP_REGNUM + 22, { "fs6", "f22" }, true }, + { RISCV_FIRST_FP_REGNUM + 23, { "fs7", "f23" }, true }, + { RISCV_FIRST_FP_REGNUM + 24, { "fs8", "f24" }, true }, + { RISCV_FIRST_FP_REGNUM + 25, { "fs9", "f25" }, true }, + { RISCV_FIRST_FP_REGNUM + 26, { "fs10", "f26" }, true }, + { RISCV_FIRST_FP_REGNUM + 27, { "fs11", "f27" }, true }, + { RISCV_FIRST_FP_REGNUM + 28, { "ft8", "f28" }, true }, + { RISCV_FIRST_FP_REGNUM + 29, { "ft9", "f29" }, true }, + { RISCV_FIRST_FP_REGNUM + 30, { "ft10", "f30" }, true }, + { RISCV_FIRST_FP_REGNUM + 31, { "ft11", "f31" }, true }, + + { RISCV_CSR_FFLAGS_REGNUM, { "fflags" }, true }, + { RISCV_CSR_FRM_REGNUM, { "frm" }, true }, + { RISCV_CSR_FCSR_REGNUM, { "fcsr" }, true }, + + } }; +/* Set of virtual registers. These are not physical registers on the + hardware, but might be available from the target. These are not pseudo + registers, reading these really does result in a register read from the + target, it is just that there might not be a physical register backing + the result. */ + +static const struct riscv_register_feature riscv_virtual_feature = +{ + "org.gnu.gdb.riscv.virtual", + { + { RISCV_PRIV_REGNUM, { "priv" }, false } + } +}; + +/* Feature set for CSRs. This set is NOT constant as the register names + list for each register is not complete. The aliases are computed + during RISCV_CREATE_CSR_ALIASES. */ + +static struct riscv_register_feature riscv_csr_feature = +{ + "org.gnu.gdb.riscv.csr", + { +#define DECLARE_CSR(NAME,VALUE) \ + { RISCV_ ## VALUE ## _REGNUM, { # NAME }, false }, +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + } +}; + +/* Complete RISCV_CSR_FEATURE, building the CSR alias names and adding them + to the name list for each register. */ + +static void +riscv_create_csr_aliases () +{ + for (auto ® : riscv_csr_feature.registers) + { + int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM; + const char *alias = xstrprintf ("csr%d", csr_num); + reg.names.push_back (alias); + } +} + /* 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. */ @@ -293,97 +352,41 @@ static unsigned int riscv_debug_infcall = 0; 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 () -{ - 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 (); - - for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i) - { - bool success = false; +/* When this is set to non-zero debugging information about gdbarch + initialisation will be printed. */ - 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 +static unsigned int riscv_debug_gdbarch = 0; - if (success) - break; - } - } +/* See riscv-tdep.h. */ - return value; +int +riscv_isa_xlen (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->isa_features.xlen; } -/* Return true if FEATURE is available for the architecture GDBARCH. The - FEATURE should be one of the single character feature codes described in - the RiscV ISA manual, these are between 'A' and 'Z'. */ +/* See riscv-tdep.h. */ -static bool -riscv_has_feature (struct gdbarch *gdbarch, char feature) +int +riscv_abi_xlen (struct gdbarch *gdbarch) { - gdb_assert (feature >= 'A' && feature <= 'Z'); - - uint32_t misa = riscv_read_misa_reg (); - if (misa == 0) - misa = gdbarch_tdep (gdbarch)->core_features; - - return (misa & (1 << (feature - 'A'))) != 0; + return gdbarch_tdep (gdbarch)->abi_features.xlen; } /* See riscv-tdep.h. */ int -riscv_isa_xlen (struct gdbarch *gdbarch) +riscv_isa_flen (struct gdbarch *gdbarch) { - switch (gdbarch_tdep (gdbarch)->abi.fields.base_len) - { - default: - warning (_("unknown xlen size, assuming 4 bytes")); - /* Fall through. */ - case 1: - return 4; - case 2: - return 8; - case 3: - return 16; - } + return gdbarch_tdep (gdbarch)->isa_features.flen; } /* See riscv-tdep.h. */ int -riscv_isa_flen (struct gdbarch *gdbarch) +riscv_abi_flen (struct gdbarch *gdbarch) { - if (riscv_has_feature (gdbarch, 'Q')) - return 16; - else if (riscv_has_feature (gdbarch, 'D')) - return 8; - else if (riscv_has_feature (gdbarch, 'F')) - return 4; - - return 0; + return gdbarch_tdep (gdbarch)->abi_features.flen; } /* Return true if the target for GDBARCH has floating point hardware. */ @@ -399,7 +402,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch) static bool riscv_has_fp_abi (struct gdbarch *gdbarch) { - return (gdbarch_tdep (gdbarch)->abi.fields.float_abi != 0); + return gdbarch_tdep (gdbarch)->abi_features.flen > 0; } /* Return true if REGNO is a floating pointer register. */ @@ -428,7 +431,15 @@ riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) unaligned_p = true; else { - /* Read the opcode byte to determine the instruction length. */ + /* Read the opcode byte to determine the instruction length. If + the read fails this may be because we tried to set the + breakpoint at an invalid address, in this case we provide a + fake result which will give a breakpoint length of 4. + Hopefully when we try to actually insert the breakpoint we + will see a failure then too which will be reported to the + user. */ + if (target_read_code (*pcptr, buf, 1) == -1) + buf[0] = 0; read_code (*pcptr, buf, 1); } @@ -485,16 +496,36 @@ value_of_riscv_user_reg (struct frame_info *frame, const void *baton) return value_of_register (*reg_p, frame); } -/* Implement the register_name gdbarch method. */ +/* Implement the register_name gdbarch method. This is used instead of + the function supplied by calling TDESC_USE_REGISTERS so that we can + ensure the preferred names are offered. */ static const char * riscv_register_name (struct gdbarch *gdbarch, int regnum) { - /* Prefer to use the alias. */ - if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) + /* Lookup the name through the target description. If we get back NULL + then this is an unknown register. If we do get a name back then we + look up the registers preferred name below. */ + const char *name = tdesc_register_name (gdbarch, regnum); + if (name == NULL || name[0] == '\0') + return NULL; + + if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM) { - gdb_assert (regnum < ARRAY_SIZE (riscv_gdb_reg_names)); - return riscv_gdb_reg_names[regnum]; + gdb_assert (regnum < riscv_xreg_feature.registers.size ()); + return riscv_xreg_feature.registers[regnum].names[0]; + } + + if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) + { + if (riscv_has_fp_regs (gdbarch)) + { + regnum -= RISCV_FIRST_FP_REGNUM; + gdb_assert (regnum < riscv_freg_feature.registers.size ()); + return riscv_freg_feature.registers[regnum].names[0]; + } + else + return NULL; } /* Check that there's no gap between the set of registers handled above, @@ -508,15 +539,7 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum) 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; - } +#include "opcode/riscv-opc.h" } #undef DECLARE_CSR } @@ -524,7 +547,10 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum) if (regnum == RISCV_PRIV_REGNUM) return "priv"; - return NULL; + /* It is possible that that the target provides some registers that GDB + is unaware of, in that case just return the NAME from the target + description. */ + return name; } /* Construct a type for 64-bit FP registers. */ @@ -561,115 +587,59 @@ riscv_fpreg_d_type (struct gdbarch *gdbarch) return tdep->riscv_fpreg_d_type; } -/* Construct a type for 128-bit FP registers. */ +/* Implement the register_type gdbarch method. This is installed as an + for the override setup by TDESC_USE_REGISTERS, for most registers we + delegate the type choice to the target description, but for a few + registers we try to improve the types if the target description has + taken a simplistic approach. */ static struct type * -riscv_fpreg_q_type (struct gdbarch *gdbarch) +riscv_register_type (struct gdbarch *gdbarch, int regnum) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct type *type = tdesc_register_type (gdbarch, regnum); + int xlen = riscv_isa_xlen (gdbarch); - if (tdep->riscv_fpreg_q_type == nullptr) + /* We want to perform some specific type "fixes" in cases where we feel + that we really can do better than the target description. For all + other cases we just return what the target description says. */ + if (riscv_is_fp_regno_p (regnum)) { - 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; + /* This spots the case for RV64 where the double is defined as + either 'ieee_double' or 'float' (which is the generic name that + converts to 'double' on 64-bit). In these cases its better to + present the registers using a union type. */ + int flen = riscv_isa_flen (gdbarch); + if (flen == 8 + && TYPE_CODE (type) == TYPE_CODE_FLT + && TYPE_LENGTH (type) == flen + && (strcmp (TYPE_NAME (type), "builtin_type_ieee_double") == 0 + || strcmp (TYPE_NAME (type), "double") == 0)) + type = riscv_fpreg_d_type (gdbarch); } - return tdep->riscv_fpreg_q_type; -} - -/* Implement the register_type gdbarch method. */ - -static struct type * -riscv_register_type (struct gdbarch *gdbarch, int regnum) -{ - int regsize; - - if (regnum < RISCV_FIRST_FP_REGNUM) + if ((regnum == gdbarch_pc_regnum (gdbarch) + || regnum == RISCV_RA_REGNUM + || regnum == RISCV_FP_REGNUM + || regnum == RISCV_SP_REGNUM + || regnum == RISCV_GP_REGNUM + || regnum == RISCV_TP_REGNUM) + && TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_LENGTH (type) == xlen) { + /* This spots the case where some interesting registers are defined + as simple integers of the expected size, we force these registers + to be pointers as we believe that is more useful. */ if (regnum == gdbarch_pc_regnum (gdbarch) - || regnum == RISCV_RA_REGNUM) - return builtin_type (gdbarch)->builtin_func_ptr; - - if (regnum == RISCV_FP_REGNUM - || regnum == RISCV_SP_REGNUM - || regnum == RISCV_GP_REGNUM - || regnum == RISCV_TP_REGNUM) - return builtin_type (gdbarch)->builtin_data_ptr; - - /* Remaining GPRs vary in size based on the current ISA. */ - regsize = riscv_isa_xlen (gdbarch); - switch (regsize) - { - case 4: - return builtin_type (gdbarch)->builtin_uint32; - case 8: - return builtin_type (gdbarch)->builtin_uint64; - case 16: - return builtin_type (gdbarch)->builtin_uint128; - default: - internal_error (__FILE__, __LINE__, - _("unknown isa regsize %i"), regsize); - } + || regnum == RISCV_RA_REGNUM) + type = builtin_type (gdbarch)->builtin_func_ptr; + else if (regnum == RISCV_FP_REGNUM + || regnum == RISCV_SP_REGNUM + || regnum == RISCV_GP_REGNUM + || regnum == RISCV_TP_REGNUM) + type = builtin_type (gdbarch)->builtin_data_ptr; } - else if (regnum <= RISCV_LAST_FP_REGNUM) - { - regsize = riscv_isa_xlen (gdbarch); - switch (regsize) - { - case 4: - return builtin_type (gdbarch)->builtin_float; - case 8: - return riscv_fpreg_d_type (gdbarch); - case 16: - return riscv_fpreg_q_type (gdbarch); - default: - internal_error (__FILE__, __LINE__, - _("unknown isa regsize %i"), regsize); - } - } - else if (regnum == RISCV_PRIV_REGNUM) - return builtin_type (gdbarch)->builtin_int8; - else - { - if (regnum == RISCV_CSR_FFLAGS_REGNUM - || regnum == RISCV_CSR_FRM_REGNUM - || regnum == RISCV_CSR_FCSR_REGNUM) - return builtin_type (gdbarch)->builtin_int32; - regsize = riscv_isa_xlen (gdbarch); - switch (regsize) - { - case 4: - return builtin_type (gdbarch)->builtin_int32; - case 8: - return builtin_type (gdbarch)->builtin_int64; - case 16: - return builtin_type (gdbarch)->builtin_int128; - default: - internal_error (__FILE__, __LINE__, - _("unknown isa regsize %i"), regsize); - } - } + return type; } /* Helper for riscv_print_registers_info, prints info for a single register @@ -682,14 +652,27 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, int regnum) { const char *name = gdbarch_register_name (gdbarch, regnum); - struct value *val = value_of_register (regnum, frame); - struct type *regtype = value_type (val); + struct value *val; + struct type *regtype; int print_raw_format; enum tab_stops { value_column_1 = 15 }; fputs_filtered (name, file); print_spaces_filtered (value_column_1 - strlen (name), file); + try + { + val = value_of_register (regnum, frame); + regtype = value_type (val); + } + catch (const gdb_exception_error &ex) + { + /* Handle failure to read a register without interrupting the entire + 'info registers' flow. */ + fprintf_filtered (file, "%s\n", ex.what ()); + return; + } + print_raw_format = (value_entirely_available (val) && !value_optimized_out (val)); @@ -706,7 +689,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, { struct value_print_options opts; const gdb_byte *valaddr = value_contents_for_printing (val); - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype)); + enum bfd_endian byte_order = type_byte_order (regtype); get_user_print_options (&opts); opts.deref_ref = 1; @@ -742,8 +725,10 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, 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 " @@ -772,9 +757,13 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, 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--) @@ -904,6 +893,15 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum, || gdbarch_register_name (gdbarch, regnum)[0] == '\0') return 0; + if (regnum > RISCV_LAST_REGNUM) + { + int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup); + if (ret != -1) + return ret; + + return default_register_reggroup_p (gdbarch, regnum, reggroup); + } + if (reggroup == all_reggroup) { if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM) @@ -922,11 +920,14 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum, 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; } - else if (reggroup == system_reggroup) + else if (reggroup == system_reggroup || reggroup == csr_reggroup) { if (regnum == RISCV_PRIV_REGNUM) return 1; @@ -954,7 +955,6 @@ riscv_print_registers_info (struct gdbarch *gdbarch, if (regnum != -1) { /* Print one specified register. */ - gdb_assert (regnum <= RISCV_LAST_REGNUM); if (gdbarch_register_name (gdbarch, regnum) == NULL || *(gdbarch_register_name (gdbarch, regnum)) == '\0') error (_("Not a valid register for the current processor type")); @@ -981,7 +981,7 @@ riscv_print_registers_info (struct gdbarch *gdbarch, continue; /* Is the register in the group we're interested in? */ - if (!riscv_register_reggroup_p (gdbarch, regnum, reggroup)) + if (!gdbarch_register_reggroup_p (gdbarch, regnum, reggroup)) continue; riscv_print_one_register_info (gdbarch, file, frame, regnum); @@ -1011,7 +1011,7 @@ public: LUI, SD, SW, - /* These are needed for software breakopint support. */ + /* These are needed for software breakpoint support. */ JAL, JALR, BEQ, @@ -1386,10 +1386,12 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) m_opcode = OTHER; } else - internal_error (__FILE__, __LINE__, - _("unable to decode %d byte instructions in " - "prologue at %s"), m_length, - core_addr_to_string (pc)); + { + /* This must be a 6 or 8 byte instruction, we don't currently decode + any of these, so just ignore it. */ + gdb_assert (m_length == 6 || m_length == 8); + m_opcode = OTHER; + } } /* The prologue scanner. This is currently only used for skipping the @@ -1569,10 +1571,16 @@ riscv_scan_prologue (struct gdbarch *gdbarch, 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); } } @@ -1614,62 +1622,59 @@ riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache) { + /* A nop instruction is 'add x0, x0, 0'. */ + static const gdb_byte nop_insn[] = { 0x13, 0x00, 0x00, 0x00 }; + /* Allocate space for a breakpoint, and keep the stack correctly - aligned. */ + aligned. The space allocated here must be at least big enough to + accommodate the NOP_INSN defined above. */ sp -= 16; *bp_addr = sp; *real_pc = funaddr; + + /* When we insert a breakpoint we select whether to use a compressed + breakpoint or not based on the existing contents of the memory. + + If the breakpoint is being placed onto the stack as part of setting up + for an inferior call from GDB, then the existing stack contents may + randomly appear to be a compressed instruction, causing GDB to insert + a compressed breakpoint. If this happens on a target that does not + support compressed instructions then this could cause problems. + + To prevent this issue we write an uncompressed nop onto the stack at + the location where the breakpoint will be inserted. In this way we + ensure that we always use an uncompressed breakpoint, which should + work on all targets. + + We call TARGET_WRITE_MEMORY here so that if the write fails we don't + throw an exception. Instead we ignore the error and move on. The + assumption is that either GDB will error later when actually trying to + insert a software breakpoint, or GDB will use hardware breakpoints and + there will be no need to write to memory later. */ + int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn)); + + if (riscv_debug_breakpoints || riscv_debug_infcall) + fprintf_unfiltered (gdb_stdlog, + "Writing %s-byte nop instruction to %s: %s\n", + plongest (sizeof (nop_insn)), + paddress (gdbarch, *bp_addr), + (status == 0 ? "success" : "failed")); + return sp; } -/* Compute the alignment of the type T. Used while setting up the - arguments for a dummy call. */ +/* Implement the gdbarch type alignment method, overrides the generic + alignment algorithm for anything that is RISC-V specific. */ -static int -riscv_type_alignment (struct type *t) +static ULONGEST +riscv_type_align (gdbarch *gdbarch, type *type) { - t = check_typedef (t); - switch (TYPE_CODE (t)) - { - default: - error (_("Could not compute alignment of type")); + type = check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)) + return std::min (TYPE_LENGTH (type), (ULONGEST) BIGGEST_ALIGNMENT); - case TYPE_CODE_RVALUE_REF: - case TYPE_CODE_PTR: - case TYPE_CODE_ENUM: - case TYPE_CODE_INT: - case TYPE_CODE_FLT: - case TYPE_CODE_REF: - case TYPE_CODE_CHAR: - case TYPE_CODE_BOOL: - 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)); - - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - { - int i; - int align = 1; - - for (i = 0; i < TYPE_NFIELDS (t); ++i) - { - if (TYPE_FIELD_LOC_KIND (t, i) == FIELD_LOC_KIND_BITPOS) - { - int a = riscv_type_alignment (TYPE_FIELD_TYPE (t, i)); - if (a > align) - align = a; - } - } - return align; - } - } + /* Anything else will be aligned by the generic code. */ + return 0; } /* Holds information about a single argument either being passed to an @@ -1804,8 +1809,8 @@ struct riscv_call_info : 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)) @@ -1825,7 +1830,7 @@ struct riscv_call_info 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; }; @@ -1968,7 +1973,7 @@ static void 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 { @@ -1988,13 +1993,14 @@ riscv_call_arg_complex_float (struct riscv_arg_info *ainfo, 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; result = riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len, len); + &cinfo->float_regs, len, 0); gdb_assert (result); result = riscv_assign_reg_location (&ainfo->argloc[1], @@ -2015,14 +2021,18 @@ class riscv_struct_info public: riscv_struct_info () : m_number_of_fields (0), - m_types { nullptr, nullptr } + m_types { nullptr, nullptr }, + m_offsets { 0, 0 } { /* Nothing. */ } /* Analyse TYPE descending into nested structures, count the number of scalar fields and record the types of the first two fields found. */ - void analyse (struct type *type); + void analyse (struct type *type) + { + analyse_inner (type, 0); + } /* The number of scalar fields found in the analysed type. This is currently only accurate if the value returned is 0, 1, or 2 as the @@ -2042,6 +2052,16 @@ public: return m_types[index]; } + /* Return the offset of scalar field INDEX within the analysed type. Will + return 0 if there is no field at that index. Only INDEX values 0 and + 1 can be requested as the RiscV ABI only has special cases for + structures with 1 or 2 fields. */ + int field_offset (int index) const + { + gdb_assert (index < (sizeof (m_offsets) / sizeof (m_offsets[0]))); + return m_offsets[index]; + } + private: /* The number of scalar fields found within the structure after recursing into nested structures. */ @@ -2050,13 +2070,20 @@ private: /* The types of the first two scalar fields found within the structure after recursing into nested structures. */ struct type *m_types[2]; + + /* The offsets of the first two scalar fields found within the structure + after recursing into nested structures. */ + int m_offsets[2]; + + /* Recursive core for ANALYSE, the OFFSET parameter tracks the byte + offset from the start of the top level structure being analysed. */ + void analyse_inner (struct type *type, int offset); }; -/* Analyse TYPE descending into nested structures, count the number of - scalar fields and record the types of the first two fields found. */ +/* See description in class declaration. */ void -riscv_struct_info::analyse (struct type *type) +riscv_struct_info::analyse_inner (struct type *type, int offset) { unsigned int count = TYPE_NFIELDS (type); unsigned int i; @@ -2068,11 +2095,13 @@ riscv_struct_info::analyse (struct type *type) struct type *field_type = TYPE_FIELD_TYPE (type, i); field_type = check_typedef (field_type); + int field_offset + = offset + TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT; switch (TYPE_CODE (field_type)) { case TYPE_CODE_STRUCT: - analyse (field_type); + analyse_inner (field_type, field_offset); break; default: @@ -2082,7 +2111,10 @@ riscv_struct_info::analyse (struct type *type) structure we can special case, and pass the structure in memory. */ if (m_number_of_fields < 2) - m_types[m_number_of_fields] = field_type; + { + m_types[m_number_of_fields] = field_type; + m_offsets[m_number_of_fields] = field_offset; + } m_number_of_fields++; break; } @@ -2115,17 +2147,54 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, if (sinfo.number_of_fields () == 1 && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_COMPLEX) { - gdb_assert (TYPE_LENGTH (ainfo->type) - == TYPE_LENGTH (sinfo.field_type (0))); - return riscv_call_arg_complex_float (ainfo, cinfo); + /* The following is similar to RISCV_CALL_ARG_COMPLEX_FLOAT, + except we use the type of the complex field instead of the + type from AINFO, and the first location might be at a non-zero + offset. */ + if (TYPE_LENGTH (sinfo.field_type (0)) <= (2 * cinfo->flen) + && riscv_arg_regs_available (&cinfo->float_regs) >= 2 + && !ainfo->is_unnamed) + { + bool result; + int len = TYPE_LENGTH (sinfo.field_type (0)) / 2; + int offset = sinfo.field_offset (0); + + result = riscv_assign_reg_location (&ainfo->argloc[0], + &cinfo->float_regs, len, + offset); + gdb_assert (result); + + result = riscv_assign_reg_location (&ainfo->argloc[1], + &cinfo->float_regs, len, + (offset + len)); + gdb_assert (result); + } + else + riscv_call_arg_scalar_int (ainfo, cinfo); + return; } if (sinfo.number_of_fields () == 1 && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_FLT) { - gdb_assert (TYPE_LENGTH (ainfo->type) - == TYPE_LENGTH (sinfo.field_type (0))); - return riscv_call_arg_scalar_float (ainfo, cinfo); + /* The following is similar to RISCV_CALL_ARG_SCALAR_FLOAT, + except we use the type of the first scalar field instead of + the type from AINFO. Also the location might be at a non-zero + offset. */ + if (TYPE_LENGTH (sinfo.field_type (0)) > cinfo->flen + || ainfo->is_unnamed) + riscv_call_arg_scalar_int (ainfo, cinfo); + else + { + int offset = sinfo.field_offset (0); + int len = TYPE_LENGTH (sinfo.field_type (0)); + + if (!riscv_assign_reg_location (&ainfo->argloc[0], + &cinfo->float_regs, + len, offset)) + riscv_call_arg_scalar_int (ainfo, cinfo); + } + return; } if (sinfo.number_of_fields () == 2 @@ -2135,17 +2204,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen && riscv_arg_regs_available (&cinfo->float_regs) >= 2) { - int len0, len1, offset; - - gdb_assert (TYPE_LENGTH (ainfo->type) <= (2 * cinfo->flen)); - - len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len0, 0)) + &cinfo->float_regs, len0, offset)) error (_("failed during argument setup")); - len1 = TYPE_LENGTH (sinfo.field_type (1)); - offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1))); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); + offset = sinfo.field_offset (1); gdb_assert (len1 <= (TYPE_LENGTH (ainfo->type) - TYPE_LENGTH (sinfo.field_type (0)))); @@ -2163,18 +2229,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && is_integral_type (sinfo.field_type (1)) && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->xlen)) { - int len0, len1, offset; - - gdb_assert (TYPE_LENGTH (ainfo->type) - <= (cinfo->flen + cinfo->xlen)); - - len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len0, 0)) + &cinfo->float_regs, len0, offset)) error (_("failed during argument setup")); - len1 = TYPE_LENGTH (sinfo.field_type (1)); - offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1))); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); + offset = sinfo.field_offset (1); gdb_assert (len1 <= cinfo->xlen); if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->int_regs, len1, offset)) @@ -2189,22 +2251,18 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && TYPE_CODE (sinfo.field_type (1)) == TYPE_CODE_FLT && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen)) { - 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))); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); gdb_assert (len0 <= cinfo->xlen); gdb_assert (len1 <= cinfo->flen); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->int_regs, len0, 0)) + &cinfo->int_regs, len0, offset)) error (_("failed during argument setup")); + offset = sinfo.field_offset (1); if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->float_regs, len1, offset)) @@ -2216,7 +2274,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, /* 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); } @@ -2238,9 +2295,11 @@ riscv_arg_location (struct gdbarch *gdbarch, { ainfo->type = type; ainfo->length = TYPE_LENGTH (ainfo->type); - ainfo->align = riscv_type_alignment (ainfo->type); + ainfo->align = type_align (ainfo->type); ainfo->is_unnamed = is_unnamed; ainfo->contents = nullptr; + ainfo->argloc[0].c_length = 0; + ainfo->argloc[1].c_length = 0; switch (TYPE_CODE (ainfo->type)) { @@ -2262,7 +2321,7 @@ riscv_arg_location (struct gdbarch *gdbarch, } /* Recalculate the alignment requirement. */ - ainfo->align = riscv_type_alignment (ainfo->type); + ainfo->align = type_align (ainfo->type); riscv_call_arg_scalar_int (ainfo, cinfo); break; @@ -2482,10 +2541,11 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, memset (tmp, -1, sizeof (tmp)); else memset (tmp, 0, sizeof (tmp)); - memcpy (tmp, info->contents, info->argloc[0].c_length); + memcpy (tmp, (info->contents + info->argloc[0].c_offset), + info->argloc[0].c_length); regcache->cooked_write (info->argloc[0].loc_data.regno, tmp); second_arg_length = - ((info->argloc[0].c_length < info->length) + (((info->argloc[0].c_length + info->argloc[0].c_offset) < info->length) ? info->argloc[1].c_length : 0); second_arg_data = info->contents + info->argloc[1].c_offset; } @@ -2596,7 +2656,35 @@ riscv_return_value (struct gdbarch *gdbarch, 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) { @@ -2604,32 +2692,54 @@ riscv_return_value (struct gdbarch *gdbarch, 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); + { + gdb_byte *ptr = readbuf + info.argloc[0].c_offset; + regcache->cooked_read_part (regnum, 0, + info.argloc[0].c_length, + ptr); + } if (writebuf) - regcache->cooked_write (regnum, writebuf); + { + const gdb_byte *ptr = writebuf + info.argloc[0].c_offset; + regcache->cooked_write_part (regnum, 0, + info.argloc[0].c_length, + ptr); + } /* A return value in register can have a second part in a second register. */ - if (info.argloc[0].c_length < info.length) + if (info.argloc[1].c_length > 0) { switch (info.argloc[1].loc_type) { 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; @@ -2662,6 +2772,16 @@ riscv_return_value (struct gdbarch *gdbarch, 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) @@ -2684,31 +2804,6 @@ riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) 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. */ @@ -2780,17 +2875,16 @@ riscv_frame_this_id (struct frame_info *this_frame, { struct riscv_unwind_cache *cache; - TRY + try { cache = riscv_frame_cache (this_frame, prologue_cache); *this_id = cache->this_id; } - CATCH (ex, RETURN_MASK_ERROR) + catch (const gdb_exception_error &ex) { /* 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. */ @@ -2822,6 +2916,198 @@ static const struct frame_unwind riscv_frame_unwind = /*.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. */ + +static struct riscv_gdbarch_features +riscv_features_from_gdbarch_info (const struct gdbarch_info info) +{ + struct riscv_gdbarch_features features; + + /* 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 + 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) + { + unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS]; + int e_flags = elf_elfheader (info.abfd)->e_flags; + + if (eclass == ELFCLASS32) + features.xlen = 4; + else if (eclass == ELFCLASS64) + features.xlen = 8; + else + internal_error (__FILE__, __LINE__, + _("unknown ELF header class %d"), eclass); + + if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE) + features.flen = 8; + else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE) + features.flen = 4; + } + + 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); +} + +/* All of the registers in REG_SET are checked for in FEATURE, TDESC_DATA + is updated with the register numbers for each register as listed in + REG_SET. If any register marked as required in REG_SET is not found in + FEATURE then this function returns false, otherwise, it returns true. */ + +static bool +riscv_check_tdesc_feature (struct tdesc_arch_data *tdesc_data, + const struct tdesc_feature *feature, + const struct riscv_register_feature *reg_set) +{ + for (const auto ® : reg_set->registers) + { + bool found = false; + + for (const char *name : reg.names) + { + found = + tdesc_numbered_register (feature, tdesc_data, reg.regnum, name); + + if (found) + break; + } + + if (!found && reg.required_p) + return false; + } + + return true; +} + +/* Add all the expected register sets into GDBARCH. */ + +static void +riscv_add_reggroups (struct gdbarch *gdbarch) +{ + /* Add predefined register groups. */ + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, save_reggroup); + reggroup_add (gdbarch, restore_reggroup); + reggroup_add (gdbarch, system_reggroup); + reggroup_add (gdbarch, vector_reggroup); + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, float_reggroup); + + /* Add RISC-V specific register groups. */ + reggroup_add (gdbarch, csr_reggroup); +} + +/* Create register aliases for all the alternative names that exist for + registers in REG_SET. */ + +static void +riscv_setup_register_aliases (struct gdbarch *gdbarch, + const struct riscv_register_feature *reg_set) +{ + for (auto ® : reg_set->registers) + { + /* The first item in the names list is the preferred name for the + register, this is what RISCV_REGISTER_NAME returns, and so we + don't need to create an alias with that name here. */ + for (int i = 1; i < reg.names.size (); ++i) + user_reg_add (gdbarch, reg.names[i], value_of_riscv_user_reg, + ®.regnum); + } +} + +/* 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; +} + +/* Implement the gcc_target_options method. We have to select the arch and abi + from the feature info. We have enough feature info to select the abi, but + not enough info for the arch given all of the possible architecture + extensions. So choose reasonable defaults for now. */ + +static std::string +riscv_gcc_target_options (struct gdbarch *gdbarch) +{ + int isa_xlen = riscv_isa_xlen (gdbarch); + int isa_flen = riscv_isa_flen (gdbarch); + int abi_xlen = riscv_abi_xlen (gdbarch); + int abi_flen = riscv_abi_flen (gdbarch); + std::string target_options; + + target_options = "-march=rv"; + if (isa_xlen == 8) + target_options += "64"; + else + target_options += "32"; + if (isa_flen == 8) + target_options += "gc"; + else if (isa_flen == 4) + target_options += "imafc"; + else + target_options += "imac"; + + target_options += " -mabi="; + if (abi_xlen == 8) + target_options += "lp64"; + else + target_options += "ilp32"; + if (abi_flen == 8) + target_options += "d"; + else if (abi_flen == 4) + target_options += "f"; + + /* The gdb loader doesn't handle link-time relaxation relocations. */ + target_options += " -mno-relax"; + + return target_options; +} + +/* Implement the gnu_triplet_regexp method. A single compiler supports both + 32-bit and 64-bit code, and may be named riscv32 or riscv64 or (not + recommended) riscv. */ + +static const char * +riscv_gnu_triplet_regexp (struct gdbarch *gdbarch) +{ + return "riscv(32|64)?"; +} + /* 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. @@ -2835,76 +3121,155 @@ riscv_gdbarch_init (struct gdbarch_info info, { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; - struct gdbarch_tdep tmp_tdep; - int i; + struct riscv_gdbarch_features features; + const struct target_desc *tdesc = info.target_desc; + + /* Ensure we always have a target description. */ + if (!tdesc_has_registers (tdesc)) + tdesc = riscv_find_default_target_description (info); + gdb_assert (tdesc); + + if (riscv_debug_gdbarch) + fprintf_unfiltered (gdb_stdlog, "Have got a target description\n"); + + const struct tdesc_feature *feature_cpu + = tdesc_find_feature (tdesc, riscv_xreg_feature.name); + const struct tdesc_feature *feature_fpu + = tdesc_find_feature (tdesc, riscv_freg_feature.name); + const struct tdesc_feature *feature_virtual + = tdesc_find_feature (tdesc, riscv_virtual_feature.name); + const struct tdesc_feature *feature_csr + = tdesc_find_feature (tdesc, riscv_csr_feature.name); + + if (feature_cpu == NULL) + return NULL; + + struct tdesc_arch_data *tdesc_data = tdesc_data_alloc (); + + bool valid_p = riscv_check_tdesc_feature (tdesc_data, + feature_cpu, + &riscv_xreg_feature); + if (valid_p) + { + /* Check that all of the core cpu registers have the same bitsize. */ + int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc"); - /* Ideally, we'd like to get as much information from the target for - things like register size, and whether the target has floating point - hardware. However, there are some things that the target can't tell - us, like, what ABI is being used. + for (auto &tdesc_reg : feature_cpu->registers) + valid_p &= (tdesc_reg->bitsize == xlen_bitsize); - So, for now, we take as much information as possible from the ELF, - including things like register size, and FP hardware support, along - with information about the ABI. + if (riscv_debug_gdbarch) + fprintf_filtered + (gdb_stdlog, + "From target-description, xlen = %d\n", xlen_bitsize); - Information about this target is built up in TMP_TDEP, and then we - look for an existing gdbarch in ARCHES that matches TMP_TDEP. If no - match is found we'll create a new gdbarch and copy TMP_TDEP over. */ - memset (&tmp_tdep, 0, sizeof (tmp_tdep)); + features.xlen = (xlen_bitsize / 8); + } - if (info.abfd != NULL - && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + if (feature_fpu != NULL) { - unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS]; - int e_flags = elf_elfheader (info.abfd)->e_flags; - - if (eclass == ELFCLASS32) - tmp_tdep.abi.fields.base_len = 1; - else if (eclass == ELFCLASS64) - tmp_tdep.abi.fields.base_len = 2; - else - internal_error (__FILE__, __LINE__, - _("unknown ELF header class %d"), eclass); + valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu, + &riscv_freg_feature); - if (e_flags & EF_RISCV_RVC) - tmp_tdep.core_features |= (1 << ('C' - 'A')); + /* Search for the first floating point register (by any alias), to + determine the bitsize. */ + int bitsize = -1; + const auto &fp0 = riscv_freg_feature.registers[0]; - if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE) - { - tmp_tdep.abi.fields.float_abi = 2; - tmp_tdep.core_features |= (1 << ('D' - 'A')); - tmp_tdep.core_features |= (1 << ('F' - 'A')); - } - else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE) + for (const char *name : fp0.names) { - tmp_tdep.abi.fields.float_abi = 1; - tmp_tdep.core_features |= (1 << ('F' - 'A')); + if (tdesc_unnumbered_register (feature_fpu, name)) + { + bitsize = tdesc_register_bitsize (feature_fpu, name); + break; + } } + + gdb_assert (bitsize != -1); + features.flen = (bitsize / 8); + + if (riscv_debug_gdbarch) + fprintf_filtered + (gdb_stdlog, + "From target-description, flen = %d\n", bitsize); } else { - const struct bfd_arch_info *binfo = info.bfd_arch_info; + features.flen = 0; - if (binfo->bits_per_word == 32) - tmp_tdep.abi.fields.base_len = 1; - else if (binfo->bits_per_word == 64) - tmp_tdep.abi.fields.base_len = 2; - else - internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"), - binfo->bits_per_word); + if (riscv_debug_gdbarch) + fprintf_filtered + (gdb_stdlog, + "No FPU in target-description, assume soft-float ABI\n"); } + if (feature_virtual) + riscv_check_tdesc_feature (tdesc_data, feature_virtual, + &riscv_virtual_feature); + + if (feature_csr) + riscv_check_tdesc_feature (tdesc_data, feature_csr, + &riscv_csr_feature); + + if (!valid_p) + { + if (riscv_debug_gdbarch) + fprintf_unfiltered (gdb_stdlog, "Target description is not valid\n"); + tdesc_data_cleanup (tdesc_data); + 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 abi_features + = riscv_features_from_gdbarch_info (info); + /* 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"), + 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"), + abi_features.flen, features.flen); + + /* 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); arches != NULL; arches = gdbarch_list_lookup_by_info (arches->next, &info)) - if (gdbarch_tdep (arches->gdbarch)->abi.value == tmp_tdep.abi.value) + { + /* 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); + + if (other_tdep->isa_features != features + || other_tdep->abi_features != abi_features) + continue; + + break; + } + + if (arches != NULL) + { + tdesc_data_cleanup (tdesc_data); return arches->gdbarch; + } /* None found, so create a new architecture from the information provided. */ - tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep); + tdep = new (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); - memcpy (tdep, &tmp_tdep, sizeof (tmp_tdep)); + tdep->isa_features = features; + tdep->abi_features = abi_features; /* Target data types. */ set_gdbarch_short_bit (gdbarch, 16); @@ -2917,6 +3282,7 @@ riscv_gdbarch_init (struct gdbarch_info info, set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); set_gdbarch_ptr_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8); set_gdbarch_char_signed (gdbarch, 0); + set_gdbarch_type_align (gdbarch, riscv_type_align); /* Information about the target architecture. */ set_gdbarch_return_value (gdbarch, riscv_return_value); @@ -2924,46 +3290,77 @@ riscv_gdbarch_init (struct gdbarch_info info, 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); - set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM); - set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM); - set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM); - set_gdbarch_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM); - - /* Functions to supply register information. */ - set_gdbarch_register_name (gdbarch, riscv_register_name); - set_gdbarch_register_type (gdbarch, riscv_register_type); - set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info); - set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p); - /* Functions to analyze frames. */ set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue); 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. */ dwarf2_append_unwinders (gdbarch); frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind); - for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) - user_reg_add (gdbarch, riscv_register_aliases[i].name, - value_of_riscv_user_reg, &riscv_register_aliases[i].regnum); + /* 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 + just a little easier. */ + set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1); + + /* We don't have to provide the count of 0 here (its the default) but + include this line to make it explicit that, right now, we don't have + any pseudo registers on RISC-V. */ + set_gdbarch_num_pseudo_regs (gdbarch, 0); + + /* Some specific register numbers GDB likes to know about. */ + set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM); + set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM); + + set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info); + + /* Finalise the target description registers. */ + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + + /* Override the register type callback setup by the target description + mechanism. This allows us to provide special type for floating point + registers. */ + set_gdbarch_register_type (gdbarch, riscv_register_type); + + /* Override the register name callback setup by the target description + mechanism. This allows us to force our preferred names for the + registers, no matter what the target description called them. */ + set_gdbarch_register_name (gdbarch, riscv_register_name); + + /* Override the register group callback setup by the target description + mechanism. This allows us to force registers into the groups we + want, ignoring what the target tells us. */ + set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p); + + /* Create register aliases for alternative register names. */ + riscv_setup_register_aliases (gdbarch, &riscv_xreg_feature); + if (riscv_has_fp_regs (gdbarch)) + riscv_setup_register_aliases (gdbarch, &riscv_freg_feature); + riscv_setup_register_aliases (gdbarch, &riscv_csr_feature); + + /* Compile command hooks. */ + set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options); + set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp); /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); + register_riscv_ravenscar_ops (gdbarch); + return gdbarch; } @@ -3106,9 +3503,20 @@ riscv_software_single_step (struct regcache *regcache) return {next_pc}; } +/* Create RISC-V specific reggroups. */ + +static void +riscv_init_reggroups () +{ + csr_reggroup = reggroup_new ("csr", USER_REGGROUP); +} + void _initialize_riscv_tdep (void) { + riscv_create_csr_aliases (); + riscv_init_reggroups (); + gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL); /* Add root prefix command for all "set debug riscv" and "show debug @@ -3153,6 +3561,16 @@ of the stack unwinding mechanism."), show_riscv_debug_variable, &setdebugriscvcmdlist, &showdebugriscvcmdlist); + add_setshow_zuinteger_cmd ("gdbarch", class_maintenance, + &riscv_debug_gdbarch, _("\ +Set riscv gdbarch initialisation debugging."), _("\ +Show riscv gdbarch initialisation debugging."), _("\ +When non-zero, print debugging information for the riscv gdbarch\n\ +initialisation process."), + 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."),