From: Tsukasa OI <research_trasio@irq.a4lg.com>
This commit makes existing disassembler option "priv-spec" overridable on
ELF files with attributes.
Existing implementation is helpful on debugging binary files but on ELF
files, the value specified by "priv-spec" option must match the attributes.
However, there's a case where privileged specification ELF attributes and
actual CSRs as used in the program differs. For instance, OpenSBI is the
prime example.
This commit enables objdump and GDB to ignore ELF attributes but instead
use custom specification (e.g. even if OpenSBI is compiled with priv-spec
1.11 toolchain, we can correctly disassemble with priv-spec=1.12 option).
gas/ChangeLog:
* testsuite/gas/riscv/dis-priv-spec-override.s: New privileged
specification override tests.
* testsuite/gas/riscv/dis-priv-spec-override-1.d: Likewise.
* testsuite/gas/riscv/dis-priv-spec-override-2.d: Likewise.
opcodes/ChangeLog:
* riscv-dis.c (default_priv_spec) Set to initial default version.
(priv_spec, is_custom_priv_spec) New.
(is_init_csr): Define as a file-scope variable instead a local
variable of print_insn_args.
(init_riscv_dis_state_for_arch_and_options): Keep track of
"priv-spec" changes.
(set_default_riscv_dis_options): Initialize "priv-spec".
(parse_riscv_dis_option): Make "priv-spec" overridable.
(print_insn_args): Use file-scope is_init_csr variable.
(riscv_get_disassembler): Move fallback of default_priv_spec
from print_insn_args. Initialize "priv-spec".
---
.../gas/riscv/dis-priv-spec-override-1.d | 10 +++
.../gas/riscv/dis-priv-spec-override-2.d | 10 +++
.../gas/riscv/dis-priv-spec-override.s | 2 +
opcodes/riscv-dis.c | 70 ++++++++++++-------
4 files changed, 68 insertions(+), 24 deletions(-)
create mode 100644 gas/testsuite/gas/riscv/dis-priv-spec-override-1.d
create mode 100644 gas/testsuite/gas/riscv/dis-priv-spec-override-2.d
create mode 100644 gas/testsuite/gas/riscv/dis-priv-spec-override.s
new file mode 100644
@@ -0,0 +1,10 @@
+#as: -march=rv64i_zicsr -mpriv-spec=1.11
+#source: dis-priv-spec-override.s
+#objdump: -d -M priv-spec=1.12
+
+.*:[ ]+file format .*
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ ]+[0-9a-f]+:[ ]+3d002573[ ]+csrr[ ]+a0,pmpaddr32
new file mode 100644
@@ -0,0 +1,10 @@
+#as: -march=rv64i_zicsr -mpriv-spec=1.12
+#source: dis-priv-spec-override.s
+#objdump: -d -M priv-spec=1.11
+
+.*:[ ]+file format .*
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ ]+[0-9a-f]+:[ ]+3d002573[ ]+csrr[ ]+a0,0x3d0
new file mode 100644
@@ -0,0 +1,2 @@
+target:
+ csrr a0, 0x3d0
@@ -49,7 +49,16 @@ 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;
+
+/* 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;
+
+/* Reset when reinitializing the CSR hash table is required. */
+static bool is_init_csr = false;
/* RISC-V disassembler architecture context type. */
typedef struct
@@ -205,6 +214,18 @@ init_riscv_dis_state_for_arch (void)
static void
init_riscv_dis_state_for_arch_and_options (void)
{
+ static bool init = false;
+ static enum riscv_spec_class prev_priv_spec;
+ /* Set current privileged specification. */
+ if (!is_custom_priv_spec)
+ priv_spec = default_priv_spec;
+ /* First call to this function. */
+ if (!init)
+ {
+ init = true;
+ /* Save initial options. */
+ prev_priv_spec = priv_spec;
+ }
/* If the architecture string is changed, update XLEN. */
if (is_arch_changed)
update_riscv_dis_xlen (NULL);
@@ -215,7 +236,12 @@ init_riscv_dis_state_for_arch_and_options (void)
= !riscv_subset_supports (&riscv_rps_dis, "zfinx")
? (is_numeric ? riscv_fpr_names_numeric : riscv_fpr_names_abi)
: riscv_gpr_names;
+ /* Reset CSR hash table if either the architecture or the privileged
+ specification version is changed. */
+ if (prev_priv_spec != priv_spec)
+ is_init_csr = false;
/* Save previous options and mark them "unchanged". */
+ prev_priv_spec = priv_spec;
is_arch_changed = false;
}
@@ -267,6 +293,7 @@ set_default_riscv_dis_options (void)
{
no_aliases = false;
is_numeric = false;
+ is_custom_priv_spec = false;
}
/* Parse RISC-V disassembler option (without arguments). */
@@ -314,21 +341,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
@@ -721,31 +745,26 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
case 'E':
{
static const char *riscv_csr_hash[4096]; /* Total 2^12 CSRs. */
- static bool init_csr = false;
unsigned int csr = EXTRACT_OPERAND (CSR, l);
- if (!init_csr)
+ if (!is_init_csr)
{
unsigned int i;
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)
#include "opcode/riscv-opc.h"
#undef DECLARE_CSR
- init_csr = true;
+ is_init_csr = true;
}
if (riscv_csr_hash[csr] != NULL)
@@ -1283,6 +1302,9 @@ riscv_get_disassembler (bfd *abfd)
in the attributes, use the default value. */
if (!default_arch)
default_arch = 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;
}
}