aboutsummaryrefslogtreecommitdiff
path: root/opcodes/arc-dis.c
diff options
context:
space:
mode:
authorAnton Kolesov <Anton.Kolesov@synopsys.com>2017-03-16 15:21:31 +0300
committerAnton Kolesov <Anton.Kolesov@synopsys.com>2017-05-30 16:54:02 +0300
commit10045478d984f9924cb945423388ba25b7dd3ffe (patch)
tree0f5dd12a962563711bec6ec32ff73e0b6966cc8c /opcodes/arc-dis.c
parent940171d08654a9ff5bf9b8886f76e8189a02cf09 (diff)
downloadgdb-10045478d984f9924cb945423388ba25b7dd3ffe.zip
gdb-10045478d984f9924cb945423388ba25b7dd3ffe.tar.gz
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.c131
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, _("\