From 611d8a342f474a342f12d60a7828b77dce1f6e78 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 20 Jul 2022 14:14:18 +0900 Subject: [PATCH] RISC-V: Make ELF `priv-spec' overridable `priv-spec' disassembler option only allowed a privileged specification matching the one that is specified on the ELF attributes. This commit removes this restriction (making privileged specification for the disassembler overridable) for programs which uses future privileged specification than the toolchain (e.g. OpenSBI). opcodes/ChangeLog: * riscv-dis.c (init_riscv_dis_state_for_arch_and_options): Use `priv_spec' instead of `default_priv_spec'. (print_insn_args): Likewise. Also don't update `priv_spec' here. (set_default_riscv_dis_options): Add initialization. (riscv_get_disassembler): Likewise. Move fallback from `print_insn_args'. (parse_riscv_dis_option): Make ELF `priv-spec' overridable. (parse_riscv_dis_options): Track custom `priv-spec' option. --- opcodes/riscv-dis.c | 58 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index e50cb00b98e..395441fce78 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -47,7 +47,7 @@ static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1; /* Default privileged specification (as specified by the ELF attributes or the `priv-spec' option). */ -static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE; +static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; static riscv_subset_list_t riscv_subsets; static riscv_parse_subset_t riscv_rps_dis = @@ -84,6 +84,12 @@ static bool is_numeric = false; /* Reset when either arch or option is changed. */ static bool is_init_csr = false; +/* Current privileged specification version. */ +static enum riscv_spec_class priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; + +/* If set, a custom privileged specification is specified. */ +static bool is_custom_priv_spec = false; + /* Initialization (for arch and options). */ @@ -102,14 +108,14 @@ static void init_riscv_dis_state_for_arch_and_options (void) { static bool init = false; - static enum riscv_spec_class prev_default_priv_spec; + static enum riscv_spec_class prev_priv_spec; if (!init) { set_default_riscv_dis_options (); build_riscv_opcodes_hash_table (); init = true; /* Save initial options. */ - prev_default_priv_spec = default_priv_spec; + prev_priv_spec = priv_spec; } riscv_gpr_names = is_numeric ? riscv_gpr_names_numeric : riscv_gpr_names_abi; riscv_fpr_names = is_numeric ? riscv_fpr_names_numeric : riscv_fpr_names_abi; @@ -117,10 +123,10 @@ init_riscv_dis_state_for_arch_and_options (void) if (riscv_subset_supports (&riscv_rps_dis, "zfinx")) riscv_fpr_names = riscv_gpr_names; /* Reset CSR hashtable if either `arch' or `priv-spec' option changes. */ - if (is_arch_changed || prev_default_priv_spec != default_priv_spec) + if (is_arch_changed || prev_priv_spec != priv_spec) is_init_csr = false; /* Save previous options and mark them "unchanged". */ - prev_default_priv_spec = default_priv_spec; + prev_priv_spec = priv_spec; is_arch_changed = false; } @@ -129,6 +135,7 @@ set_default_riscv_dis_options (void) { no_aliases = false; is_numeric = false; + is_custom_priv_spec = false; } /* Update current architecture string @@ -206,21 +213,18 @@ parse_riscv_dis_option (const char *option) value = equal + 1; if (strcmp (option, "priv-spec") == 0) { - enum riscv_spec_class priv_spec = PRIV_SPEC_CLASS_NONE; - const char *name = NULL; - - RISCV_GET_PRIV_SPEC_CLASS (value, priv_spec); - if (priv_spec == PRIV_SPEC_CLASS_NONE) - opcodes_error_handler (_("unknown privileged spec set by %s=%s"), - option, value); - else if (default_priv_spec == PRIV_SPEC_CLASS_NONE) - default_priv_spec = priv_spec; - else if (default_priv_spec != priv_spec) + enum riscv_spec_class priv_spec_new = PRIV_SPEC_CLASS_NONE; + RISCV_GET_PRIV_SPEC_CLASS (value, priv_spec_new); + if (priv_spec_new == PRIV_SPEC_CLASS_NONE) { - RISCV_GET_PRIV_SPEC_NAME (name, default_priv_spec); - opcodes_error_handler (_("mis-matched privilege spec set by %s=%s, " - "the elf privilege attribute is %s"), - option, value, name); + opcodes_error_handler (_ ("unknown privileged spec set by %s=%s." + "not overriding"), + option, value); + } + else + { + is_custom_priv_spec = true; + priv_spec = priv_spec_new; } } else @@ -234,6 +238,7 @@ static void parse_riscv_dis_options (const char *opts_in) { char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts; + bool prev_is_custom_priv_spec = is_custom_priv_spec; set_default_riscv_dis_options (); @@ -245,6 +250,8 @@ parse_riscv_dis_options (const char *opts_in) } free (opts); + if (prev_is_custom_priv_spec && !is_custom_priv_spec) + priv_spec = default_priv_spec; } /* Print one argument from an array. */ @@ -609,16 +616,12 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info for (i = 0; i < 4096; i++) riscv_csr_hash[i] = NULL; - /* Set to the newest privileged version. */ - if (default_priv_spec == PRIV_SPEC_CLASS_NONE) - default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; - #define DECLARE_CSR(name, num, class, define_version, abort_version) \ if (riscv_csr_hash[num] == NULL \ && ((define_version == PRIV_SPEC_CLASS_NONE \ && abort_version == PRIV_SPEC_CLASS_NONE) \ - || (default_priv_spec >= define_version \ - && default_priv_spec < abort_version))) \ + || (priv_spec >= define_version \ + && priv_spec < abort_version))) \ riscv_csr_hash[num] = #name; #define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \ DECLARE_CSR (name, num, class, define_version, abort_version) @@ -1154,11 +1157,16 @@ riscv_get_disassembler (bfd *abfd) /* For ELF files with (somehow) empty attributes, we use the default. */ if (!default_arch_next || !*default_arch_next) default_arch_next = initial_default_arch; + /* By default, set to the newest privileged version. */ + if (default_priv_spec == PRIV_SPEC_CLASS_NONE) + default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; } } if (update_riscv_dis_default_arch (default_arch_next)) update_riscv_dis_current_arch (default_arch_next); + if (!is_custom_priv_spec) + priv_spec = default_priv_spec; init_riscv_dis_state_for_arch_and_options (); return print_insn_riscv; }