diff options
author | Anton Kolesov <Anton.Kolesov@synopsys.com> | 2017-03-16 15:21:31 +0300 |
---|---|---|
committer | Anton Kolesov <Anton.Kolesov@synopsys.com> | 2017-05-30 16:54:02 +0300 |
commit | 10045478d984f9924cb945423388ba25b7dd3ffe (patch) | |
tree | 0f5dd12a962563711bec6ec32ff73e0b6966cc8c /opcodes/arc-dis.c | |
parent | 940171d08654a9ff5bf9b8886f76e8189a02cf09 (diff) | |
download | fsf-binutils-gdb-10045478d984f9924cb945423388ba25b7dd3ffe.zip fsf-binutils-gdb-10045478d984f9924cb945423388ba25b7dd3ffe.tar.gz fsf-binutils-gdb-10045478d984f9924cb945423388ba25b7dd3ffe.tar.bz2 |
[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=<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 <anton.kolesov@synopsys.com>
* 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 <anton.kolesov@synopsys.com>
* doc/binutils.texi: Document new cpu=... disassembler options for ARC.
Diffstat (limited to 'opcodes/arc-dis.c')
-rw-r--r-- | opcodes/arc-dis.c | 131 |
1 files changed, 105 insertions, 26 deletions
diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 0cf4bff..edd0c07 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, _("\ |