This is the mail archive of the binutils-cvs@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] [ARC] Allow CPU to be enforced via disassemble_info options


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=10045478d984f9924cb945423388ba25b7dd3ffe

commit 10045478d984f9924cb945423388ba25b7dd3ffe
Author: Anton Kolesov <Anton.Kolesov@synopsys.com>
Date:   Thu Mar 16 15:21:31 2017 +0300

    [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.

Diff:
---
 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 163211f..1ecb042 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 23d8685..a2a670a 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 8e7d4db..888126e 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -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
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, _("\


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]