+ 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;
+}
+
+/* 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.
+
+ Called e.g. at program startup, when reading a core file, and when
+ reading a binary file. */
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+ struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ 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");
+
+ for (auto &tdesc_reg : feature_cpu->registers)
+ valid_p &= (tdesc_reg->bitsize == xlen_bitsize);
+
+ if (riscv_debug_gdbarch)
+ fprintf_filtered
+ (gdb_stdlog,
+ "From target-description, xlen = %d\n", xlen_bitsize);
+
+ features.xlen = (xlen_bitsize / 8);
+ }
+
+ if (feature_fpu != NULL)
+ {
+ valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu,
+ &riscv_freg_feature);
+
+ int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
+ features.flen = (bitsize / 8);
+
+ if (riscv_debug_gdbarch)
+ fprintf_filtered
+ (gdb_stdlog,
+ "From target-description, flen = %d\n", bitsize);
+ }
+ else
+ {
+ features.flen = 0;
+
+ 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 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);
+