[ARC] Allow CPU to be enforced via disassemble_info options
authorAnton Kolesov <Anton.Kolesov@synopsys.com>
Thu, 16 Mar 2017 12:21:31 +0000 (15:21 +0300)
committerAnton Kolesov <Anton.Kolesov@synopsys.com>
Tue, 30 May 2017 13:54:02 +0000 (16:54 +0300)
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.

binutils/ChangeLog
binutils/doc/binutils.texi
opcodes/ChangeLog
opcodes/arc-dis.c

index 163211f2aa40dc729681cb9786164b34a1b54e92..1ecb04297b90eeb5577bdd0c4aa7221e8d79c801 100644 (file)
@@ -1,3 +1,7 @@
+2017-05-30  Anton Kolesov  <anton.kolesov@synopsys.com>
+
+       * doc/binutils.texi: Document new cpu=... disassembler options for ARC.
+
 2017-05-30  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR binutils/21519
index 23d8685b33b0c1685efd7b2bf3d7cddeb9c2228d..a2a670af29d128cc2cd0420137f962752d57508a 100644 (file)
@@ -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
index 8e7d4dbde5fa0951eee78051d320a7579a9e3027..888126e4e7c8356cbc4caa992d42d1c2fbab89f3 100644 (file)
@@ -1,3 +1,12 @@
+2017-05-30  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.
+
 2017-05-24  Yao Qi  <yao.qi@linaro.org>
 
        * alpha-dis.c: Include disassemble.h, don't include
index 0cf4bff1817bda0b325e8c77b2f50f0b224bfef6..edd0c0735a2510c7eeb6673161c2716592c01076 100644 (file)
@@ -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, _("\