From 10045478d984f9924cb945423388ba25b7dd3ffe Mon Sep 17 00:00:00 2001 From: Anton Kolesov Date: Thu, 16 Mar 2017 15:21:31 +0300 Subject: [PATCH] [ARC] Allow CPU to be enforced via disassemble_info options Currently print_insn_arc relies on BFD mach and ELF private headers to distinguish between various ARC architectures. Sometimes those values are not correct or available, mainly in the case of debugging targets without and ELF file available. Changing a BFD mach is not a problem for the debugger, because this is a generic BFD field, and GDB, for example, already sets it according to information provided in XML target description or specified via GDB 'set arch' command. However, things are more complicated for ELF private headers, since it requires existing of an actual ELF file. To workaround this problem this patch allows CPU model to be specified via disassemble info options. If CPU is specified in options, then it will take a higher precedence than whatever might be specified in ELF file. This is mostly needed for ARC EM and ARC HS, because they have the same "architecture" (mach) ARCv2 and differ in their private ELF headers. Other ARC architectures can be distinguished between each other purely via "mach" field. Proposed disassemble option format is "cpu=", where CPU can be any valid ARC CPU name as supported by GAS. Note that this creates a seeming redundancy with objdump -m/--architecture option, however -mEM and -mHS still result in "ARCv2" architecture internally, while -Mcpu={HS,EM} would have an actual effect on disassembler. opcodes/ChangeLog: yyyy-mm-dd Anton Kolesov * arc-dis.c (enforced_isa_mask): Declare. (cpu_types): Likewise. (parse_cpu_option): New function. (parse_disassembler_options): Use it. (print_insn_arc): Use enforced_isa_mask. (print_arc_disassembler_options): Document new options. binutils/ChangeLog: yyyy-mm-dd Anton Kolesov * doc/binutils.texi: Document new cpu=... disassembler options for ARC. --- binutils/ChangeLog | 4 ++ binutils/doc/binutils.texi | 8 +++ opcodes/ChangeLog | 9 +++ opcodes/arc-dis.c | 131 +++++++++++++++++++++++++++++-------- 4 files changed, 126 insertions(+), 26 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 163211f2aa..1ecb04297b 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,7 @@ +2017-05-30 Anton Kolesov + + * doc/binutils.texi: Document new cpu=... disassembler options for ARC. + 2017-05-30 H.J. Lu PR binutils/21519 diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 23d8685b33..a2a670af29 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -2314,6 +2314,14 @@ of double precision assist instructions, @option{fpus} selects the printing of FPU single precision FP instructions, while @option{fpud} selects the printing of FPU souble precision FP instructions. +@option{cpu=...} allows to enforce a particular ISA when disassembling +instructions, overriding the @option{-m} value or whatever is in the ELF file. +This might be useful to select ARC EM or HS ISA, because architecture is same +for those and disassembler relies on private ELF header data to decide if code +is for EM or HS. This option might be specified multiple times - only the +latest value will be used. Valid values are same as for the assembler +@option{-mcpu=...} option. + If the target is an ARM architecture then this switch can be used to select which register name set is used during disassembler. Specifying @option{-M reg-names-std} (the default) will select the register names as diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 8e7d4dbde5..888126e4e7 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,12 @@ +2017-05-30 Anton Kolesov + + * arc-dis.c (enforced_isa_mask): Declare. + (cpu_types): Likewise. + (parse_cpu_option): New function. + (parse_disassembler_options): Use it. + (print_insn_arc): Use enforced_isa_mask. + (print_arc_disassembler_options): Document new options. + 2017-05-24 Yao Qi * alpha-dis.c: Include disassemble.h, don't include diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 0cf4bff181..edd0c0735a 100644 --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -117,6 +117,11 @@ typedef struct skipclass disassembling. */ static linkclass decodelist = NULL; +/* ISA mask value enforced via disassembler info options. ARC_OPCODE_NONE + value means that no CPU is enforced. */ + +static unsigned enforced_isa_mask = ARC_OPCODE_NONE; + /* Macros section. */ #ifdef DEBUG @@ -770,6 +775,49 @@ parse_option (const char *option) fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); } +#define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARC600, "ARC600" } +#define ARC_CPU_TYPE_A7xx(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARC700, "ARC700" } +#define ARC_CPU_TYPE_AV2EM(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARCv2EM, "ARC EM" } +#define ARC_CPU_TYPE_AV2HS(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARCv2HS, "ARC HS" } +#define ARC_CPU_TYPE_NONE \ + { 0, 0, 0 } + +/* A table of CPU names and opcode sets. */ +static const struct cpu_type +{ + const char *name; + unsigned flags; + const char *isa; +} + cpu_types[] = +{ + #include "elf/arc-cpu.def" +}; + +/* Helper for parsing the CPU options. Accept any of the ARC architectures + values. OPTION should be a value passed to cpu=. */ + +static unsigned +parse_cpu_option (const char *option) +{ + int i; + + for (i = 0; cpu_types[i].name; ++i) + { + if (!strcasecmp (cpu_types[i].name, option)) + { + return cpu_types[i].flags; + } + } + + fprintf (stderr, _("Unrecognised disassembler CPU option: %s\n"), option); + return ARC_OPCODE_NONE; +} + /* Go over the options list and parse it. */ static void @@ -778,6 +826,12 @@ parse_disassembler_options (const char *options) if (options == NULL) return; + /* Disassembler might be reused for difference CPU's, and cpu option set for + the first one shouldn't be applied to second (which might not have + explicit cpu in its options. Therefore it is required to reset enforced + CPU when new options are being parsed. */ + enforced_isa_mask = ARC_OPCODE_NONE; + while (*options) { /* Skip empty options. */ @@ -787,7 +841,13 @@ parse_disassembler_options (const char *options) continue; } - parse_option (options); + /* A CPU option? Cannot use STRING_COMMA_LEN because strncmp is also a + preprocessor macro. */ + if (strncmp (options, "cpu=", 4) == 0) + /* Strip leading `cpu=`. */ + enforced_isa_mask = parse_cpu_option (options + 4); + else + parse_option (options); while (*options != ',' && *options != '\0') ++ options; @@ -859,7 +919,7 @@ print_insn_arc (bfd_vma memaddr, int status; unsigned int insn_len; unsigned long long insn = 0; - unsigned isa_mask; + unsigned isa_mask = ARC_OPCODE_NONE; const struct arc_opcode *opcode; bfd_boolean need_comma; bfd_boolean open_braket; @@ -867,7 +927,6 @@ print_insn_arc (bfd_vma memaddr, const struct arc_operand *operand; int value; struct arc_operand_iterator iter; - Elf_Internal_Ehdr *header = NULL; struct arc_disassemble_info *arc_infop; if (info->disassembler_options) @@ -885,34 +944,44 @@ print_insn_arc (bfd_vma memaddr, highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0); lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1); - if (info->section && info->section->owner) - header = elf_elfheader (info->section->owner); - - switch (info->mach) + /* Figure out CPU type, unless it was enforced via disassembler options. */ + if (enforced_isa_mask == ARC_OPCODE_NONE) { - case bfd_mach_arc_arc700: - isa_mask = ARC_OPCODE_ARC700; - break; + Elf_Internal_Ehdr *header = NULL; - case bfd_mach_arc_arc600: - isa_mask = ARC_OPCODE_ARC600; - break; + if (info->section && info->section->owner) + header = elf_elfheader (info->section->owner); - case bfd_mach_arc_arcv2: - default: - isa_mask = ARC_OPCODE_ARCv2EM; - /* TODO: Perhaps remove defitinion of header since it is only used at - this location. */ - if (header != NULL - && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS) + switch (info->mach) { - isa_mask = ARC_OPCODE_ARCv2HS; - /* FPU instructions are not extensions for HS. */ - add_to_decodelist (FLOAT, SP); - add_to_decodelist (FLOAT, DP); - add_to_decodelist (FLOAT, CVT); + case bfd_mach_arc_arc700: + isa_mask = ARC_OPCODE_ARC700; + break; + + case bfd_mach_arc_arc600: + isa_mask = ARC_OPCODE_ARC600; + break; + + case bfd_mach_arc_arcv2: + default: + isa_mask = ARC_OPCODE_ARCv2EM; + /* TODO: Perhaps remove definition of header since it is only used at + this location. */ + if (header != NULL + && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS) + isa_mask = ARC_OPCODE_ARCv2HS; + break; } - break; + } + else + isa_mask = enforced_isa_mask; + + if (isa_mask == ARC_OPCODE_ARCv2HS) + { + /* FPU instructions are not extensions for HS. */ + add_to_decodelist (FLOAT, SP); + add_to_decodelist (FLOAT, DP); + add_to_decodelist (FLOAT, CVT); } /* This variable may be set by the instruction decoder. It suggests @@ -1278,10 +1347,20 @@ arc_get_disassembler (bfd *abfd) void print_arc_disassembler_options (FILE *stream) { + int i; + fprintf (stream, _("\n\ The following ARC specific disassembler options are supported for use \n\ with -M switch (multiple options should be separated by commas):\n")); + /* cpu=... options. */ + for (i = 0; cpu_types[i].name; ++i) + { + /* As of now all value CPU values are less than 16 characters. */ + fprintf (stream, " cpu=%-16s\tEnforce %s ISA.\n", + cpu_types[i].name, cpu_types[i].isa); + } + fprintf (stream, _("\ dsp Recognize DSP instructions.\n")); fprintf (stream, _("\ -- 2.34.1