Don't use print_insn_XXX in GDB
[deliverable/binutils-gdb.git] / opcodes / arm-dis.c
index 0fb458658add7c83eea291a2045a3e288e4e26e9..a30afb9a7ee482cb9204cdac6faf5dc9e59a09c1 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction printing code for the ARM
-   Copyright (C) 1994-2016 Free Software Foundation, Inc.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
    Modification by James G. Smith (jsmith@cygnus.co.uk)
 
 
 #include "sysdep.h"
 
-#include "dis-asm.h"
+#include "disassemble.h"
 #include "opcode/arm.h"
 #include "opintl.h"
 #include "safe-ctype.h"
+#include "libiberty.h"
 #include "floatformat.h"
 
 /* FIXME: This shouldn't be done here.  */
 #define strneq(a,b,n)  (strncmp ((a), (b), (n)) == 0)
 #endif
 
-#ifndef NUM_ELEM
-#define NUM_ELEM(a)     (sizeof (a) / sizeof (a)[0])
-#endif
-
 /* Cached mapping symbol state.  */
 enum map_type
 {
@@ -116,6 +113,7 @@ struct opcode16
    %<bitfield>G         print as an iWMMXt general purpose or control register
    %<bitfield>D                print as a NEON D register
    %<bitfield>Q                print as a NEON Q register
+   %<bitfield>V                print as a NEON D or Q register
    %<bitfield>E                print a quarter-float immediate value
 
    %y<code>            print a single precision VFP reg.
@@ -408,6 +406,12 @@ static const struct opcode32 coprocessor_opcodes[] =
   {ARM_FEATURE_COPROC (FPU_FPA_EXT_V2),
     0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
 
+  /* ARMv8-M Mainline Security Extensions instructions.  */
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN),
+    0xec300a00, 0xfff0ffff, "vlldm\t%16-19r"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN),
+    0xec200a00, 0xfff0ffff, "vlstm\t%16-19r"},
+
   /* Register load/store.  */
   {ARM_FEATURE_COPROC (FPU_VFP_EXT_V1xD | FPU_NEON_EXT_V1),
     0x0d2d0b00, 0x0fbf0f01, "vpush%c\t%B"},
@@ -876,6 +880,28 @@ static const struct opcode32 coprocessor_opcodes[] =
     0xfc400000, 0xfff00000,
     "mcrr2%c\t%8-11d, %4-7d, %12-15R, %16-19R, cr%0-3d"},
 
+  /* ARMv8.3 AdvSIMD instructions in the space of coprocessor 8.  */
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfc800800, 0xfeb00f10, "vcadd%c.f16\t%12-15,22V, %16-19,7V, %0-3,5V, #%24?29%24'70"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfc900800, 0xfeb00f10, "vcadd%c.f32\t%12-15,22V, %16-19,7V, %0-3,5V, #%24?29%24'70"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfc200800, 0xff300f10, "vcmla%c.f16\t%12-15,22V, %16-19,7V, %0-3,5V, #%23'90"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfd200800, 0xff300f10, "vcmla%c.f16\t%12-15,22V, %16-19,7V, %0-3,5V, #%23?21%23?780"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfc300800, 0xff300f10, "vcmla%c.f32\t%12-15,22V, %16-19,7V, %0-3,5V, #%23'90"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfd300800, 0xff300f10, "vcmla%c.f32\t%12-15,22V, %16-19,7V, %0-3,5V, #%23?21%23?780"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfe000800, 0xffa00f10, "vcmla%c.f16\t%12-15,22V, %16-19,7V, %0-3D[%5?10], #%20'90"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfe200800, 0xffa00f10, "vcmla%c.f16\t%12-15,22V, %16-19,7V, %0-3D[%5?10], #%20?21%20?780"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfe800800, 0xffa00f10, "vcmla%c.f32\t%12-15,22V, %16-19,7V, %0-3,5D[0], #%20'90"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0xfea00800, 0xffa00f10, "vcmla%c.f32\t%12-15,22V, %16-19,7V, %0-3,5D[0], #%20?21%20?780"},
+
   /* V5 coprocessor instructions.  */
   {ARM_FEATURE_CORE_LOW (ARM_EXT_V5),
     0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"},
@@ -965,6 +991,10 @@ static const struct opcode32 coprocessor_opcodes[] =
   {ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
     0x0e300940, 0x0fb00f50, "vsub%c.f16\t%y1, %y2, %y0"},
 
+  /* ARMv8.3 javascript conversion instruction.  */
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A),
+    0x0eb90bc0, 0x0fbf0fd0, "vjcvt%c.s32.f64\t%y1, %z0"},
+
   {ARM_FEATURE_CORE_LOW (0), 0, 0, 0}
 };
 
@@ -1721,7 +1751,7 @@ static const struct opcode32 arm_opcodes[] =
     "%22?sumlal%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
 
   /* V8.2 RAS extension instructions.  */
-  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A),
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS),
     0xe320f010, 0xffffffff, "esb"},
 
   /* V8 instructions.  */
@@ -2280,8 +2310,6 @@ static const struct opcode32 arm_opcodes[] =
     0x01300000, 0x0ff00010, "teq%p%c\t%16-19r, %o"},
   {ARM_FEATURE_CORE_LOW (ARM_EXT_V1),
     0x01300010, 0x0ff00010, "teq%p%c\t%16-19R, %o"},
-  {ARM_FEATURE_CORE_LOW (ARM_EXT_V5),
-    0x0130f000, 0x0ff0f010, "bx%c\t%0-3r"},
 
   {ARM_FEATURE_CORE_LOW (ARM_EXT_V1),
     0x03400000, 0x0fe00000, "cmp%p%c\t%16-19r, %o"},
@@ -2469,6 +2497,10 @@ static const struct opcode16 thumb_opcodes[] =
 {
   /* Thumb instructions.  */
 
+  /* ARMv8-M Security Extensions instructions.  */
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0x4784, 0xff87, "blxns\t%3-6r"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0x4704, 0xff07, "bxns\t%3-6r"},
+
   /* ARM V8 instructions.  */
   {ARM_FEATURE_CORE_LOW (ARM_EXT_V8),  0xbf50, 0xffff, "sevl%c"},
   {ARM_FEATURE_CORE_LOW (ARM_EXT_V8),  0xba80, 0xffc0, "hlt\t%0-5x"},
@@ -2674,14 +2706,19 @@ static const struct opcode16 thumb_opcodes[] =
    makes heavy use of special-case bit patterns.  */
 static const struct opcode32 thumb32_opcodes[] =
 {
-  /* V8-M instructions.  */
+  /* ARMv8-M and ARMv8-M Security Extensions instructions.  */
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0xe97fe97f, 0xffffffff, "sg"},
   {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M),
     0xe840f000, 0xfff0f0ff, "tt\t%8-11r, %16-19r"},
   {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M),
     0xe840f040, 0xfff0f0ff, "ttt\t%8-11r, %16-19r"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M),
+    0xe840f080, 0xfff0f0ff, "tta\t%8-11r, %16-19r"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M),
+    0xe840f0c0, 0xfff0f0ff, "ttat\t%8-11r, %16-19r"},
 
   /* ARM V8.2 RAS extension instructions.  */
-  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A),
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS),
     0xf3af8010, 0xffffffff, "esb"},
 
   /* V8 instructions.  */
@@ -3156,18 +3193,20 @@ arm_regname;
 
 static const arm_regname regnames[] =
 {
-  { "raw" , "Select raw register names",
+  { "reg-names-raw", N_("Select raw register names"),
     { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
-  { "gcc",  "Select register names used by GCC",
+  { "reg-names-gcc", N_("Select register names used by GCC"),
     { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
-  { "std",  "Select register names used in ARM's ISA documentation",
+  { "reg-names-std", N_("Select register names used in ARM's ISA documentation"),
     { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp",  "lr",  "pc" }},
-  { "apcs", "Select register names used in the APCS",
+  { "force-thumb", N_("Assume all insns are Thumb insns"), {NULL} },
+  { "no-force-thumb", N_("Examine preceding label to determine an insn's type"), {NULL} },
+  { "reg-names-apcs", N_("Select register names used in the APCS"),
     { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
-  { "atpcs", "Select register names used in the ATPCS",
+  { "reg-names-atpcs", N_("Select register names used in the ATPCS"),
     { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  "v8",  "IP",  "SP",  "LR",  "PC" }},
-  { "special-atpcs", "Select special register names used in the ATPCS",
-    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }},
+  { "reg-names-special-atpcs", N_("Select special register names used in the ATPCS"),
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }}
 };
 
 static const char *const iwmmxt_wwnames[] =
@@ -3193,7 +3232,7 @@ static const char *const iwmmxt_cregnames[] =
 /* Default to GCC register name set.  */
 static unsigned int regname_selected = 1;
 
-#define NUM_ARM_REGNAMES  NUM_ELEM (regnames)
+#define NUM_ARM_OPTIONS   ARRAY_SIZE (regnames)
 #define arm_regnames      regnames[regname_selected].reg_names
 
 static bfd_boolean force_thumb = FALSE;
@@ -3212,31 +3251,6 @@ static bfd_vma ifthen_address;
 
 \f
 /* Functions.  */
-int
-get_arm_regname_num_options (void)
-{
-  return NUM_ARM_REGNAMES;
-}
-
-int
-set_arm_regname_option (int option)
-{
-  int old = regname_selected;
-  regname_selected = option;
-  return old;
-}
-
-int
-get_arm_regnames (int option,
-                 const char **setname,
-                 const char **setdescription,
-                 const char *const **register_names)
-{
-  *setname = regnames[option].name;
-  *setdescription = regnames[option].description;
-  *register_names = regnames[option].reg_names;
-  return 16;
-}
 
 /* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?.
    Returns pointer to following character of the format string and
@@ -3654,10 +3668,15 @@ print_insn_coprocessor (bfd_vma pc,
                          }
                        func (stream, "%s", arm_regnames[value]);
                        break;
+                     case 'V':
+                       if (given & (1 << 6))
+                         goto Q;
+                       /* FALLTHROUGH */
                      case 'D':
                        func (stream, "d%ld", value);
                        break;
                      case 'Q':
+                     Q:
                        if (value & 1)
                          func (stream, "<illegal reg q%ld.5>", value >> 1);
                        else
@@ -4671,6 +4690,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
 
                    case 'S':
                      allow_unpredictable = TRUE;
+                     /* Fall through.  */
                    case 's':
                       if ((given & 0x004f0000) == 0x004f0000)
                        {
@@ -5412,20 +5432,31 @@ psr_name (int regno)
 {
   switch (regno)
     {
-    case 0: return "APSR";
-    case 1: return "IAPSR";
-    case 2: return "EAPSR";
-    case 3: return "PSR";
-    case 5: return "IPSR";
-    case 6: return "EPSR";
-    case 7: return "IEPSR";
-    case 8: return "MSP";
-    case 9: return "PSP";
-    case 16: return "PRIMASK";
-    case 17: return "BASEPRI";
-    case 18: return "BASEPRI_MAX";
-    case 19: return "FAULTMASK";
-    case 20: return "CONTROL";
+    case 0x0: return "APSR";
+    case 0x1: return "IAPSR";
+    case 0x2: return "EAPSR";
+    case 0x3: return "PSR";
+    case 0x5: return "IPSR";
+    case 0x6: return "EPSR";
+    case 0x7: return "IEPSR";
+    case 0x8: return "MSP";
+    case 0x9: return "PSP";
+    case 0xa: return "MSPLIM";
+    case 0xb: return "PSPLIM";
+    case 0x10: return "PRIMASK";
+    case 0x11: return "BASEPRI";
+    case 0x12: return "BASEPRI_MAX";
+    case 0x13: return "FAULTMASK";
+    case 0x14: return "CONTROL";
+    case 0x88: return "MSP_NS";
+    case 0x89: return "PSP_NS";
+    case 0x8a: return "MSPLIM_NS";
+    case 0x8b: return "PSPLIM_NS";
+    case 0x90: return "PRIMASK_NS";
+    case 0x91: return "BASEPRI_NS";
+    case 0x93: return "FAULTMASK_NS";
+    case 0x94: return "CONTROL_NS";
+    case 0x98: return "SP_NS";
     default: return "<unknown>";
     }
 }
@@ -5700,7 +5731,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
                      if (off || !U)
                        {
                          func (stream, ", #%c%u", U ? '+' : '-', off * 4);
-                         value_in_comment = off * 4 * U ? 1 : -1;
+                         value_in_comment = off * 4 * (U ? 1 : -1);
                        }
                      func (stream, "]");
                      if (W)
@@ -5712,7 +5743,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
                      if (W)
                        {
                          func (stream, "#%c%u", U ? '+' : '-', off * 4);
-                         value_in_comment = off * 4 * U ? 1 : -1;
+                         value_in_comment = off * 4 * (U ? 1 : -1);
                        }
                      else
                        {
@@ -6065,64 +6096,39 @@ arm_symbol_is_valid (asymbol * sym,
   return (name && *name != '$' && strncmp (name, "__tagsym$$", 10));
 }
 
-/* Parse an individual disassembler option.  */
+/* Parse the string of disassembler options.  */
 
-void
-parse_arm_disassembler_option (char *option)
+static void
+parse_arm_disassembler_options (const char *options)
 {
-  if (option == NULL)
-    return;
+  const char *opt;
 
-  if (CONST_STRNEQ (option, "reg-names-"))
+  FOR_EACH_DISASSEMBLER_OPTION (opt, options)
     {
-      int i;
-
-      option += 10;
-
-      for (i = NUM_ARM_REGNAMES; i--;)
-       if (strneq (option, regnames[i].name, strlen (regnames[i].name)))
-         {
-           regname_selected = i;
-           break;
-         }
+      if (CONST_STRNEQ (opt, "reg-names-"))
+       {
+         unsigned int i;
+         for (i = 0; i < NUM_ARM_OPTIONS; i++)
+           if (disassembler_options_cmp (opt, regnames[i].name) == 0)
+             {
+               regname_selected = i;
+               break;
+             }
 
-      if (i < 0)
-       /* XXX - should break 'option' at following delimiter.  */
-       fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
+         if (i >= NUM_ARM_OPTIONS)
+           fprintf (stderr, _("Unrecognised register name set: %s\n"), opt);
+       }
+      else if (CONST_STRNEQ (opt, "force-thumb"))
+       force_thumb = 1;
+      else if (CONST_STRNEQ (opt, "no-force-thumb"))
+       force_thumb = 0;
+      else
+       fprintf (stderr, _("Unrecognised disassembler option: %s\n"), opt);
     }
-  else if (CONST_STRNEQ (option, "force-thumb"))
-    force_thumb = 1;
-  else if (CONST_STRNEQ (option, "no-force-thumb"))
-    force_thumb = 0;
-  else
-    /* XXX - should break 'option' at following delimiter.  */
-    fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
 
   return;
 }
 
-/* Parse the string of disassembler options, spliting it at whitespaces
-   or commas.  (Whitespace separators supported for backwards compatibility).  */
-
-static void
-parse_disassembler_options (char *options)
-{
-  if (options == NULL)
-    return;
-
-  while (*options)
-    {
-      parse_arm_disassembler_option (options);
-
-      /* Skip forward to next seperator.  */
-      while ((*options) && (! ISSPACE (*options)) && (*options != ','))
-       ++ options;
-      /* Skip forward past seperators.  */
-      while (ISSPACE (*options) || (*options == ','))
-       ++ options;
-    }
-}
-
 static bfd_boolean
 mapping_symbol_for_insn (bfd_vma pc, struct disassemble_info *info,
                         enum map_type *map_symbol);
@@ -6271,7 +6277,8 @@ get_sym_code_type (struct disassemble_info *info,
   /* If the symbol has function type then use that.  */
   if (type == STT_FUNC || type == STT_GNU_IFUNC)
     {
-      if (ARM_SYM_BRANCH_TYPE (&es->internal_elf_sym) == ST_BRANCH_TO_THUMB)
+      if (ARM_GET_SYM_BRANCH_TYPE (es->internal_elf_sym.st_target_internal)
+         == ST_BRANCH_TO_THUMB)
        *map_type = MAP_THUMB;
       else
        *map_type = MAP_ARM;
@@ -6413,7 +6420,7 @@ print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
 
   if (info->disassembler_options)
     {
-      parse_disassembler_options (info->disassembler_options);
+      parse_arm_disassembler_options (info->disassembler_options);
 
       /* To avoid repeated parsing of these options, we remove them here.  */
       info->disassembler_options = NULL;
@@ -6477,7 +6484,7 @@ print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
         we finished last time.  */
       /* PR 14006.  When the address is 0 we are either at the start of the
         very first function, or else the first function in a new, unlinked
-        executable section (eg because uf -ffunction-sections).  Either way
+        executable section (eg because of -ffunction-sections).  Either way
         start scanning from the beginning of the symbol table, not where we
         left off last time.  */
       if (pc == 0)
@@ -6638,9 +6645,9 @@ print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
          es = *(elf_symbol_type **)(info->symbols);
          type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
 
-         is_thumb = ((ARM_SYM_BRANCH_TYPE (&es->internal_elf_sym)
-                      == ST_BRANCH_TO_THUMB)
-                     || type == STT_ARM_16BIT);
+         is_thumb =
+           ((ARM_GET_SYM_BRANCH_TYPE (es->internal_elf_sym.st_target_internal)
+             == ST_BRANCH_TO_THUMB) || type == STT_ARM_16BIT);
        }
       else if (bfd_asymbol_flavour (*info->symbols)
               == bfd_target_mach_o_flavour)
@@ -6782,21 +6789,51 @@ print_insn_little_arm (bfd_vma pc, struct disassemble_info *info)
   return print_insn (pc, info, TRUE);
 }
 
+const disasm_options_t *
+disassembler_options_arm (void)
+{
+  static disasm_options_t *opts = NULL;
+
+  if (opts == NULL)
+    {
+      unsigned int i;
+      opts = XNEW (disasm_options_t);
+      opts->name = XNEWVEC (const char *, NUM_ARM_OPTIONS + 1);
+      opts->description = XNEWVEC (const char *, NUM_ARM_OPTIONS + 1);
+      for (i = 0; i < NUM_ARM_OPTIONS; i++)
+       {
+         opts->name[i] = regnames[i].name;
+         if (regnames[i].description != NULL)
+           opts->description[i] = _(regnames[i].description);
+         else
+           opts->description[i] = NULL;
+       }
+      /* The array we return must be NULL terminated.  */
+      opts->name[i] = NULL;
+      opts->description[i] = NULL;
+    }
+
+  return opts;
+}
+
 void
 print_arm_disassembler_options (FILE *stream)
 {
-  int i;
-
+  unsigned int i, max_len = 0;
   fprintf (stream, _("\n\
 The following ARM specific disassembler options are supported for use with\n\
 the -M switch:\n"));
 
-  for (i = NUM_ARM_REGNAMES; i--;)
-    fprintf (stream, "  reg-names-%s %*c%s\n",
-            regnames[i].name,
-            (int)(14 - strlen (regnames[i].name)), ' ',
-            regnames[i].description);
+  for (i = 0; i < NUM_ARM_OPTIONS; i++)
+    {
+      unsigned int len = strlen (regnames[i].name);
+      if (max_len < len)
+       max_len = len;
+    }
 
-  fprintf (stream, "  force-thumb              Assume all insns are Thumb insns\n");
-  fprintf (stream, "  no-force-thumb           Examine preceding label to determine an insn's type\n\n");
+  for (i = 0, max_len++; i < NUM_ARM_OPTIONS; i++)
+    fprintf (stream, "  %s%*c %s\n",
+            regnames[i].name,
+            (int)(max_len - strlen (regnames[i].name)), ' ',
+            _(regnames[i].description));
 }
This page took 0.031608 seconds and 4 git commands to generate.