From 82a73b9836377af54e494eadc157069ffa52dbcb Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 5 Feb 2022 15:15:31 +0900 Subject: [PATCH 1/3] gdb, opcodes: Add non-enum disassembler options This commit adds support for non-enum disassembler options that allow arbitrary argument (not including ","). This is identified by `NULL' value of disasm_option_arg_t.values. gdb/ChangeLog: * gdb/disasm.c (set_disassembler_options): Add support for non-enum disassembler options. (show_disassembler_options_sfunc): Likewise. include/ChangeLog: * dis-asm.h (disasm_option_arg_t): Update comment of `values' to allow non-enum disassembler options. opcodes/ChangeLog: * riscv-dis.c (print_riscv_disassembler_options): Support non-enum disassembler options on printing disassembler help. * arc-dis.c (print_arc_disassembler_options): Likewise. * mips-dis.c (print_mips_disassembler_options): Likewise. --- gdb/disasm.c | 4 ++++ include/dis-asm.h | 3 ++- opcodes/arc-dis.c | 2 ++ opcodes/mips-dis.c | 2 ++ opcodes/riscv-dis.c | 2 ++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gdb/disasm.c b/gdb/disasm.c index cf27a32fbe7..4a81bb89971 100644 --- a/gdb/disasm.c +++ b/gdb/disasm.c @@ -1269,6 +1269,8 @@ set_disassembler_options (const char *prospective_options) if (memcmp (opt, valid_options->name[i], len) != 0) continue; arg = opt + len; + if (valid_options->arg[i]->values == NULL) + break; for (j = 0; valid_options->arg[i]->values[j] != NULL; j++) if (disassembler_options_cmp (arg, valid_options->arg[i]->values[j]) == 0) @@ -1390,6 +1392,8 @@ The following disassembler options are supported for use with the\n\ for (i = 0; valid_args[i].name != NULL; i++) { + if (valid_args[i].values == NULL) + continue; gdb_printf (file, _("\n\ For the options above, the following values are supported for \"%s\":\n "), valid_args[i].name); diff --git a/include/dis-asm.h b/include/dis-asm.h index 4f91df12498..be593794eba 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -311,7 +311,8 @@ typedef struct /* Option argument name to use in descriptions. */ const char *name; - /* Vector of acceptable option argument values, NULL-terminated. */ + /* Vector of acceptable option argument values, NULL-terminated. + NULL if any values are accepted. */ const char **values; } disasm_option_arg_t; diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 3490bad4f66..c8dc525f64d 100644 --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -1611,6 +1611,8 @@ print_arc_disassembler_options (FILE *stream) for (i = 0; args[i].name != NULL; ++i) { size_t len = 3; + if (args[i].values == NULL) + continue; fprintf (stream, _("\n\ For the options above, the following values are supported for \"%s\":\n "), args[i].name); diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 9db604ffb39..faeebccfc3b 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -2809,6 +2809,8 @@ with the -M switch (multiple options should be separated by commas):\n\n")); for (i = 0; args[i].name != NULL; i++) { + if (args[i].values == NULL) + continue; fprintf (stream, _("\n\ For the options above, the following values are supported for \"%s\":\n "), args[i].name); diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index 32e01893423..3970021cbef 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -1324,6 +1324,8 @@ with the -M switch (multiple options should be separated by commas):\n")); for (i = 0; args[i].name != NULL; i++) { + if (args[i].values == NULL) + continue; fprintf (stream, _("\n\ For the options above, the following values are supported for \"%s\":\n "), args[i].name); From 9a80cfd18949d357d54780629e8d7d811fbf8515 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 5 Feb 2022 15:39:41 +0900 Subject: [PATCH 2/3] RISC-V: Add arch disassembler option This commit adds arch=ARCH disassembler option to objdump and GDB. Note that XLEN part of ISA string given has a lower precedence than BFD architecture with specific XLEN (riscv:rv32 and riscv:rv64, also implicitly set on RISC-V ELF files). opcodes/ChangeLog: * riscv-dis.c (xlen_by_arch) New. (set_default_riscv_dis_options): Custom arch string is none by default. (update_riscv_dis_current_arch): Recompute arch string-originating XLEN. (parse_riscv_dis_option): Parse arch=ARCH option. (parse_riscv_dis_options): Reset arch string to default if required. (riscv_disassemble_insn): Update XLEN precedence rules. (riscv_get_disassembler): Consider custom arch string. (riscv_option_arg_t): Add arguments for arch=ARCH option. (riscv_options): Add arch=ARCH option. (disassembler_options_riscv): Add handling for arch=ARCH. --- opcodes/riscv-dis.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index 3970021cbef..c87e2d10639 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -42,6 +42,9 @@ static const char *default_arch = NULL; /* Current XLEN for the disassembler. */ static unsigned xlen = 0; +/* Current XLEN, as specified by the `arch' option. */ +static unsigned xlen_by_arch = 0; + /* Default ISA specification version (constant as of now). */ static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1; @@ -84,6 +87,9 @@ static bool is_numeric = false; /* Reset when reinitializing the CSR table is required. */ static bool is_init_csr = false; +/* If set, a custom arch option is specified. */ +static bool is_custom_arch = false; + /* Initialization (for arch and options). */ @@ -130,6 +136,7 @@ set_default_riscv_dis_options (void) { no_aliases = false; is_numeric = false; + is_custom_arch = false; } /* Update current architecture string @@ -138,8 +145,11 @@ set_default_riscv_dis_options (void) static void update_riscv_dis_current_arch (const char *arch) { + xlen = 0; riscv_release_subset_list (&riscv_subsets); riscv_parse_subset (&riscv_rps_dis, arch); + /* Ignore XLEN by arch string if arch is the initial default value. */ + xlen_by_arch = (arch == initial_default_arch) ? 0 : xlen; init_riscv_dis_state_for_arch (); } @@ -224,6 +234,11 @@ parse_riscv_dis_option (const char *option) option, value, name); } } + else if (strcmp (option, "arch") == 0) + { + is_custom_arch = true; + update_riscv_dis_current_arch (value); + } else { /* xgettext:c-format */ @@ -235,6 +250,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_arch = is_custom_arch; set_default_riscv_dis_options (); @@ -246,6 +262,8 @@ parse_riscv_dis_options (const char *opts_in) } free (opts); + if (prev_is_custom_arch && !is_custom_arch) + update_riscv_dis_current_arch (default_arch); } /* Print one argument from an array. */ @@ -759,11 +777,24 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info) info->target = 0; info->target2 = 0; - /* If XLEN is not known, get its value from the ELF class. */ + /* Set XLEN with following precedence rules: + 1. BFD architecture set by either: + a. -m riscv:rv[32|64] option (gdb: set arch riscv:rv[32|64]) + b. ELF class in actual ELF header (only on RISC-V ELF) + This is only effective if XLEN-specific BFD architecture is + chosen. If chosen BFD architecture is XLEN-neutral + (like riscv), BFD architecture is ignored on XLEN selection. + 2. RISC-V ISA string set by either: + a. -M arch=rv[32|64]... option + (gdb: set disassembler-options arch=...) + b. RISC-V ELF attributes (only on RISC-V ELF) + 3. ELF class in dummy ELF header */ if (info->mach == bfd_mach_riscv64) xlen = 64; else if (info->mach == bfd_mach_riscv32) xlen = 32; + else if (xlen_by_arch) + xlen = xlen_by_arch; else if (info->section != NULL) { Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner); @@ -1161,7 +1192,7 @@ riscv_get_disassembler (bfd *abfd) } } - if (update_riscv_dis_default_arch (default_arch_next)) + if (update_riscv_dis_default_arch (default_arch_next) && !is_custom_arch) update_riscv_dis_current_arch (default_arch_next); init_riscv_dis_state_for_arch_and_options (); return print_insn_riscv; @@ -1192,6 +1223,7 @@ riscv_symbol_is_valid (asymbol * sym, typedef enum { RISCV_OPTION_ARG_NONE = -1, + RISCV_OPTION_ARG_ARCH, RISCV_OPTION_ARG_PRIV_SPEC, RISCV_OPTION_ARG_COUNT @@ -1212,6 +1244,9 @@ static struct { "no-aliases", N_("Disassemble only into canonical instructions."), RISCV_OPTION_ARG_NONE }, + { "arch=", + N_("Disassemble using chosen ISA and extensions."), + RISCV_OPTION_ARG_ARCH }, { "priv-spec=", N_("Print the CSR according to the chosen privilege spec."), RISCV_OPTION_ARG_PRIV_SPEC } @@ -1236,6 +1271,9 @@ disassembler_options_riscv (void) args = XNEWVEC (disasm_option_arg_t, num_args + 1); + args[RISCV_OPTION_ARG_ARCH].name = "ARCH"; + args[RISCV_OPTION_ARG_ARCH].values = NULL; + args[RISCV_OPTION_ARG_PRIV_SPEC].name = "SPEC"; priv_spec_count = PRIV_SPEC_CLASS_DRAFT - PRIV_SPEC_CLASS_NONE - 1; args[RISCV_OPTION_ARG_PRIV_SPEC].values From b7b82601e7a3c2cba16421e7d9c3e3ccc9c4b436 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 4 Jun 2022 17:37:10 +0900 Subject: [PATCH 3/3] RISC-V: Add disassembler arch option tests This commit adds certain tests for arch=ARCH disassembler option (to override ISA and extensions). gas/ChangeLog: * testsuite/gas/riscv/dis-arch-override.s: New test. * testsuite/gas/riscv/dis-arch-override-1.d: Likewise. * testsuite/gas/riscv/dis-arch-override-2.d: Likewise. * testsuite/gas/riscv/dis-arch-override-3.d: Likewise. --- gas/testsuite/gas/riscv/dis-arch-override-1.d | 13 ++++++ gas/testsuite/gas/riscv/dis-arch-override-2.d | 13 ++++++ gas/testsuite/gas/riscv/dis-arch-override-3.d | 13 ++++++ gas/testsuite/gas/riscv/dis-arch-override.s | 45 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 gas/testsuite/gas/riscv/dis-arch-override-1.d create mode 100644 gas/testsuite/gas/riscv/dis-arch-override-2.d create mode 100644 gas/testsuite/gas/riscv/dis-arch-override-3.d create mode 100644 gas/testsuite/gas/riscv/dis-arch-override.s diff --git a/gas/testsuite/gas/riscv/dis-arch-override-1.d b/gas/testsuite/gas/riscv/dis-arch-override-1.d new file mode 100644 index 00000000000..f79546b3b22 --- /dev/null +++ b/gas/testsuite/gas/riscv/dis-arch-override-1.d @@ -0,0 +1,13 @@ +#as: -march=rv64imfd_zbb +#source: dis-arch-override.s +#objdump: -d + +.*:[ ]+file format .* + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+00c5f053[ ]+fadd.s[ ]+ft0,fa1,fa2 +[ ]+[0-9a-f]+:[ ]+02c5f053[ ]+fadd.d[ ]+ft0,fa1,fa2 +[ ]+[0-9a-f]+:[ ]+30102573[ ]+csrr[ ]+a0,misa +[ ]+[0-9a-f]+:[ ]+0805c53b[ ]+zext.h[ ]+a0,a1 diff --git a/gas/testsuite/gas/riscv/dis-arch-override-2.d b/gas/testsuite/gas/riscv/dis-arch-override-2.d new file mode 100644 index 00000000000..f2245d91286 --- /dev/null +++ b/gas/testsuite/gas/riscv/dis-arch-override-2.d @@ -0,0 +1,13 @@ +#as: -march=rv64imfd_zbb +#source: dis-arch-override.s +#objdump: -d -M arch=rv32im_zfinx_zbkb + +.*:[ ]+file format .* + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+00c5f053[ ]+fadd.s[ ]+zero,a1,a2 +[ ]+[0-9a-f]+:[ ]+02c5f053[ ]+\.4byte[ ]+0x2c5f053 +[ ]+[0-9a-f]+:[ ]+30102573[ ]+csrr[ ]+a0,misa +[ ]+[0-9a-f]+:[ ]+0805c53b[ ]+packw[ ]+a0,a1,zero diff --git a/gas/testsuite/gas/riscv/dis-arch-override-3.d b/gas/testsuite/gas/riscv/dis-arch-override-3.d new file mode 100644 index 00000000000..47f75b53e8a --- /dev/null +++ b/gas/testsuite/gas/riscv/dis-arch-override-3.d @@ -0,0 +1,13 @@ +#as: -march=rv64imfd_zbb +#source: dis-arch-override.s +#objdump: -d -m riscv -M arch=rv32im_zfinx_zbkb,numeric + +.*:[ ]+file format .* + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+00c5f053[ ]+fadd.s[ ]+x0,x11,x12 +[ ]+[0-9a-f]+:[ ]+02c5f053[ ]+\.4byte[ ]+0x2c5f053 +[ ]+[0-9a-f]+:[ ]+30102573[ ]+csrr[ ]+x10,misa +[ ]+[0-9a-f]+:[ ]+0805c53b[ ]+\.4byte[ ]+0x805c53b diff --git a/gas/testsuite/gas/riscv/dis-arch-override.s b/gas/testsuite/gas/riscv/dis-arch-override.s new file mode 100644 index 00000000000..0c2fec44ed3 --- /dev/null +++ b/gas/testsuite/gas/riscv/dis-arch-override.s @@ -0,0 +1,45 @@ +# Assembler configuration: +# -march=rv64imfd_zbb +# Disassembler configurations: +# Test 1: -d +# Test 2: -d -M arch=rv32im_zfinx_zbkb +# Test 3: -d -m riscv -M arch=rv32im_zfinx_zbkb,numeric + +target: + # Assembler : fadd.s (F) + # Disassembler (test 2/3) : fadd.s (Zfinx) + # Test that all three operands point to GPRs. + fadd.s ft0, fa1, fa2 + + # Assembler : fadd.d (D) + # Disassembler (test 2/3) : (invalid) + # On disassembler option on test 2, Zdinx is not present. So, + # it should be disassembled as an invalid instruction. + fadd.d ft0, fa1, fa2 + + # Assembler : csrr (Zicsr) + # Disassembler (test 2/3) : csrr (Zicsr) + # When assembling, Zicsr is implied by F. When disassembling, + # Zicsr is implied by Zfinx. On both cases, csrr should be + # disassembled as csrr. + csrr a0, misa + + # Assembler : zext.h (Zbb) + # Disassembler (test 2) : packw (Zbkb) + # Disassembler (test 3) : (invalid) + # Since zext.h specialized instruction does not exist in Zbkb + # and we disassemble the output with Zbkb, this instruction + # should be disassembled as a packw instruction (on RV64). + # + # We specify arch=rv32im_zfinx_zbkb on disassembling on test + # 2 and 3. But, XLEN part of the ISA string is effective + # only if XLEN-neutral machine is specified by `-m riscv' option + # (because we are disassembling 64-bit RISC-V ELF file, BFD + # architecture is set to `riscv:rv64' unless `-m' option + # is specified). + # + # As a result, test 3 (with `-m riscv' option) disassembles with + # RV32 but test 2 (without it) does with RV64. + # It changes the result of disassembling since packw instruction + # is invalid on RV32. + zext.h a0, a1