Modify AArch64 Assembly and disassembly functions to be able to fail and report why.
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index 9cf737dedebdb33b99075a094ba203b2737637c2..984fcbb8026e4b1c2262581fce761670c148ffff 100644 (file)
@@ -1,5 +1,5 @@
 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
-   Copyright (C) 1989-2016 Free Software Foundation, Inc.
+   Copyright (C) 1989-2018 Free Software Foundation, Inc.
    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
 
    This file is part of the GNU opcodes library.
@@ -20,7 +20,7 @@
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
-#include "dis-asm.h"
+#include "disassemble.h"
 #include "libiberty.h"
 #include "opcode/mips.h"
 #include "opintl.h"
@@ -607,6 +607,13 @@ const struct mips_arch_choice mips_arch_choices[] =
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
 
+  { "interaptiv-mr2",  1, bfd_mach_mips_interaptiv_mr2, CPU_INTERAPTIV_MR2,
+    ISA_MIPS32R3,
+    ASE_MT | ASE_EVA | ASE_DSP | ASE_DSPR2 | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
+    mips_cp0_names_mips3264r2,
+    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+    mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
   { "sb1",     1, bfd_mach_mips_sb1, CPU_SB1,
     ISA_MIPS64 | INSN_SB1,  ASE_MIPS3D,
     mips_cp0_names_sb1,
@@ -658,7 +665,8 @@ const struct mips_arch_choice mips_arch_choices[] =
 
   /* This entry, mips16, is here only for ISA/processor selection; do
      not print its name.  */
-  { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64, 0,
+  { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64,
+    ASE_MIPS16E2 | ASE_MIPS16E2_MT,
     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
     mips_hwr_names_numeric },
 };
@@ -795,9 +803,25 @@ mips_convert_abiflags_ases (unsigned long afl_ases)
     opcode_ases |= ASE_XPA;
   if (afl_ases & AFL_ASE_DSPR3)
     opcode_ases |= ASE_DSPR3;
+  if (afl_ases & AFL_ASE_MIPS16E2)
+    opcode_ases |= ASE_MIPS16E2;
   return opcode_ases;
 }
 
+/* Calculate combination ASE flags from regular ASE flags.  */
+
+static unsigned long
+mips_calculate_combination_ases (unsigned long opcode_ases)
+{
+  unsigned long combination_ases = 0;
+
+  if ((opcode_ases & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT))
+    combination_ases |= ASE_XPA_VIRT;
+  if ((opcode_ases & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
+    combination_ases |= ASE_MIPS16E2_MT;
+  return combination_ases;
+}
+
 static void
 set_default_mips_dis_options (struct disassemble_info *info)
 {
@@ -847,11 +871,12 @@ set_default_mips_dis_options (struct disassemble_info *info)
       Elf_Internal_Ehdr *header = elf_elfheader (abfd);
       Elf_Internal_ABIFlags_v0 *abiflags = NULL;
 
-      /* We won't ever get here if !BFD64, because we won't then have
-        a MIPS/ELF BFD, however we need to guard against a link error
-        in a `--enable-targets=...' configuration with a 32-bit host,
-        where the MIPS target is a secondary.  */
-#ifdef BFD64
+      /* We won't ever get here if !HAVE_BFD_MIPS_ELF_GET_ABIFLAGS,
+        because we won't then have a MIPS/ELF BFD, however we need
+        to guard against a link error in a `--enable-targets=...'
+        configuration with a 32-bit host where the MIPS target is
+        a secondary, or with MIPS/ECOFF configurations.  */
+#ifdef HAVE_BFD_MIPS_ELF_GET_ABIFLAGS
       abiflags = bfd_mips_elf_get_abiflags (abfd);
 #endif
       /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
@@ -866,23 +891,15 @@ set_default_mips_dis_options (struct disassemble_info *info)
        mips_ase |= ASE_MDMX;
     }
 #endif
+  mips_ase |= mips_calculate_combination_ases (mips_ase);
 }
 
-static void
-parse_mips_dis_option (const char *option, unsigned int len)
-{
-  unsigned int i, optionlen, vallen;
-  const char *val;
-  const struct mips_abi_choice *chosen_abi;
-  const struct mips_arch_choice *chosen_arch;
-
-  /* Try to match options that are simple flags */
-  if (CONST_STRNEQ (option, "no-aliases"))
-    {
-      no_aliases = 1;
-      return;
-    }
+/* Parse an ASE disassembler option and set the corresponding global
+   ASE flag(s).  Return TRUE if successful, FALSE otherwise.  */
 
+static bfd_boolean
+parse_mips_ase_option (const char *option)
+{
   if (CONST_STRNEQ (option, "msa"))
     {
       mips_ase |= ASE_MSA;
@@ -891,7 +908,7 @@ parse_mips_dis_option (const char *option, unsigned int len)
           || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5
           || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6)
          mips_ase |= ASE_MSA64;
-      return;
+      return TRUE;
     }
 
   if (CONST_STRNEQ (option, "virt"))
@@ -902,15 +919,38 @@ parse_mips_dis_option (const char *option, unsigned int len)
          || mips_isa & ISA_MIPS64R5
          || mips_isa & ISA_MIPS64R6)
        mips_ase |= ASE_VIRT64;
-      return;
+      return TRUE;
     }
 
   if (CONST_STRNEQ (option, "xpa"))
     {
       mips_ase |= ASE_XPA;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+parse_mips_dis_option (const char *option, unsigned int len)
+{
+  unsigned int i, optionlen, vallen;
+  const char *val;
+  const struct mips_abi_choice *chosen_abi;
+  const struct mips_arch_choice *chosen_arch;
+
+  /* Try to match options that are simple flags */
+  if (CONST_STRNEQ (option, "no-aliases"))
+    {
+      no_aliases = 1;
       return;
     }
 
+  if (parse_mips_ase_option (option))
+    {
+      mips_ase |= mips_calculate_combination_ases (mips_ase);
+      return;
+    }
 
   /* Look for the = that delimits the end of the option name.  */
   for (i = 0; i < len; i++)
@@ -1190,6 +1230,81 @@ mips_seen_register (struct mips_print_arg_state *state,
     }
 }
 
+/* Print SAVE/RESTORE instruction operands according to the argument
+   register mask AMASK, the number of static registers saved NSREG,
+   the $ra, $s0 and $s1 register specifiers RA, S0 and S1 respectively,
+   and the frame size FRAME_SIZE.  */
+
+static void
+mips_print_save_restore (struct disassemble_info *info, unsigned int amask,
+                        unsigned int nsreg, unsigned int ra,
+                        unsigned int s0, unsigned int s1,
+                        unsigned int frame_size)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  unsigned int nargs, nstatics, smask, i, j;
+  void *is = info->stream;
+  const char *sep;
+
+  if (amask == MIPS_SVRS_ALL_ARGS)
+    {
+      nargs = 4;
+      nstatics = 0;
+    }
+  else if (amask == MIPS_SVRS_ALL_STATICS)
+    {
+      nargs = 0;
+      nstatics = 4;
+    }
+  else
+    {
+      nargs = amask >> 2;
+      nstatics = amask & 3;
+    }
+
+  sep = "";
+  if (nargs > 0)
+    {
+      infprintf (is, "%s", mips_gpr_names[4]);
+      if (nargs > 1)
+       infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]);
+      sep = ",";
+    }
+
+  infprintf (is, "%s%d", sep, frame_size);
+
+  if (ra)                      /* $ra */
+    infprintf (is, ",%s", mips_gpr_names[31]);
+
+  smask = 0;
+  if (s0)                      /* $s0 */
+    smask |= 1 << 0;
+  if (s1)                      /* $s1 */
+    smask |= 1 << 1;
+  if (nsreg > 0)               /* $s2-$s8 */
+    smask |= ((1 << nsreg) - 1) << 2;
+
+  for (i = 0; i < 9; i++)
+    if (smask & (1 << i))
+      {
+       infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
+       /* Skip over string of set bits.  */
+       for (j = i; smask & (2 << j); j++)
+         continue;
+       if (j > i)
+         infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+       i = j + 1;
+      }
+  /* Statics $ax - $a3.  */
+  if (nstatics == 1)
+    infprintf (is, ",%s", mips_gpr_names[7]);
+  else if (nstatics > 0)
+    infprintf (is, ",%s-%s",
+              mips_gpr_names[7 - nstatics + 1],
+              mips_gpr_names[7]);
+}
+
+
 /* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
    UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
    the base address for OP_PCREL operands.  */
@@ -1280,9 +1395,10 @@ print_insn_arg (struct disassemble_info *info,
        pcrel_op = (const struct mips_pcrel_operand *) operand;
        info->target = mips_decode_pcrel_operand (pcrel_op, base_pc, uval);
 
-       /* Preserve the ISA bit for the GDB disassembler,
-          otherwise clear it.  */
-       if (info->flavour != bfd_target_unknown_flavour)
+       /* For jumps and branches clear the ISA bit except for
+          the GDB disassembler.  */
+       if (pcrel_op->include_isa_bit
+           && info->flavour != bfd_target_unknown_flavour)
          info->target &= -2;
 
        (*info->print_address_func) (info->target, info);
@@ -1421,7 +1537,7 @@ print_insn_arg (struct disassemble_info *info,
       break;
 
     case OP_SAVE_RESTORE_LIST:
-      /* Should be handled by the caller due to extend behavior.  */
+      /* Should be handled by the caller due to complex behavior.  */
       abort ();
 
     case OP_MDMX_IMM_REG:
@@ -1460,6 +1576,10 @@ print_insn_arg (struct disassemble_info *info,
       infprintf (is, "$pc");
       break;
 
+    case OP_REG28:
+      print_reg (info, opcode, OP_REG_GP, 28);
+      break;
+
     case OP_VU0_SUFFIX:
     case OP_VU0_MATCH_SUFFIX:
       print_vu0_channel (info, operand, uval);
@@ -1573,15 +1693,13 @@ validate_insn_args (const struct mips_opcode *opcode,
                case OP_REPEAT_PREV_REG:
                case OP_REPEAT_DEST_REG:
                case OP_PC:
+               case OP_REG28:
                case OP_VU0_SUFFIX:
                case OP_VU0_MATCH_SUFFIX:
                case OP_IMM_INDEX:
                case OP_REG_INDEX:
-                 break;
-
                case OP_SAVE_RESTORE_LIST:
-               /* Should be handled by the caller due to extend behavior.  */
-                 abort ();
+                 break;
                }
            }
          if (*s == 'm' || *s == '+' || *s == '-')
@@ -1634,12 +1752,26 @@ print_insn_args (struct disassemble_info *info,
                         opcode->name, opcode->args);
              return;
            }
-         if (operand->type == OP_REG
-             && s[1] == ','
-             && s[2] == 'H'
-             && opcode->name[strlen (opcode->name) - 1] == '0')
+
+         if (operand->type == OP_SAVE_RESTORE_LIST)
+           {
+             /* Handle this case here because of the complex behavior.  */
+             unsigned int amask = (insn >> 15) & 0xf;
+             unsigned int nsreg = (insn >> 23) & 0x7;
+             unsigned int ra = insn & 0x1000;                  /* $ra */
+             unsigned int s0 = insn & 0x800;                   /* $s0 */
+             unsigned int s1 = insn & 0x400;                   /* $s1 */
+             unsigned int frame_size = (((insn >> 15) & 0xf0)
+                                        | ((insn >> 6) & 0x0f)) * 8;
+             mips_print_save_restore (info, amask, nsreg, ra, s0, s1,
+                                      frame_size);
+           }
+         else if (operand->type == OP_REG
+                  && s[1] == ','
+                  && s[2] == 'H'
+                  && opcode->name[strlen (opcode->name) - 1] == '0')
            {
-             /* Coprocessor register 0 with sel field (MT ASE).  */
+             /* Coprocessor register 0 with sel field.  */
              const struct mips_cp0sel_name *n;
              unsigned int reg, sel;
 
@@ -1822,6 +1954,7 @@ print_mips16_insn_arg (struct disassemble_info *info,
   const fprintf_ftype infprintf = info->fprintf_func;
   void *is = info->stream;
   const struct mips_operand *operand, *ext_operand;
+  unsigned short ext_size;
   unsigned int uval;
   bfd_vma baseaddr;
 
@@ -1850,70 +1983,15 @@ print_mips16_insn_arg (struct disassemble_info *info,
        {
          /* Handle this case here because of the complex interaction
             with the EXTEND opcode.  */
-         unsigned int amask, nargs, nstatics, nsreg, smask, frame_size, i, j;
-         const char *sep;
-
-         amask = extend & 0xf;
-         if (amask == MIPS16_ALL_ARGS)
-           {
-             nargs = 4;
-             nstatics = 0;
-           }
-         else if (amask == MIPS16_ALL_STATICS)
-           {
-             nargs = 0;
-             nstatics = 4;
-           }
-         else
-           {
-             nargs = amask >> 2;
-             nstatics = amask & 3;
-           }
-
-         sep = "";
-         if (nargs > 0)
-           {
-             infprintf (is, "%s", mips_gpr_names[4]);
-             if (nargs > 1)
-               infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]);
-             sep = ",";
-           }
-
-         frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8;
+         unsigned int amask = extend & 0xf;
+         unsigned int nsreg = (extend >> 8) & 0x7;
+         unsigned int ra = insn & 0x40;                        /* $ra */
+         unsigned int s0 = insn & 0x20;                        /* $s0 */
+         unsigned int s1 = insn & 0x10;                        /* $s1 */
+         unsigned int frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8;
          if (frame_size == 0 && !use_extend)
            frame_size = 128;
-         infprintf (is, "%s%d", sep, frame_size);
-
-         if (insn & 0x40)              /* $ra */
-           infprintf (is, ",%s", mips_gpr_names[31]);
-
-         nsreg = (extend >> 8) & 0x7;
-         smask = 0;
-         if (insn & 0x20)              /* $s0 */
-           smask |= 1 << 0;
-         if (insn & 0x10)              /* $s1 */
-           smask |= 1 << 1;
-         if (nsreg > 0)                /* $s2-$s8 */
-           smask |= ((1 << nsreg) - 1) << 2;
-
-         for (i = 0; i < 9; i++)
-           if (smask & (1 << i))
-             {
-               infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
-               /* Skip over string of set bits.  */
-               for (j = i; smask & (2 << j); j++)
-                 continue;
-               if (j > i)
-                 infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
-               i = j + 1;
-             }
-         /* Statics $ax - $a3.  */
-         if (nstatics == 1)
-           infprintf (is, ",%s", mips_gpr_names[7]);
-         else if (nstatics > 0)
-           infprintf (is, ",%s-%s",
-                      mips_gpr_names[7 - nstatics + 1],
-                      mips_gpr_names[7]);
+         mips_print_save_restore (info, amask, nsreg, ra, s0, s1, frame_size);
          break;
        }
 
@@ -1926,29 +2004,30 @@ print_mips16_insn_arg (struct disassemble_info *info,
          info->data_size = 1 << int_op->shift;
        }
 
-      if (operand->size == 26)
-       uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
-      else
+      ext_size = 0;
+      if (use_extend)
        {
-         /* Calculate the full field value.  */
-         uval = mips_extract_operand (operand, (extend << 16) | insn);
-         if (use_extend)
+         ext_operand = decode_mips16_operand (type, TRUE);
+         if (ext_operand != operand
+             || (operand->type == OP_INT && operand->lsb == 0
+                 && mips_opcode_32bit_p (opcode)))
            {
-             ext_operand = decode_mips16_operand (type, TRUE);
-             if (ext_operand != operand)
-               {
-                 operand = ext_operand;
-                 if (operand->size == 16)
-                   uval = (((extend & 0x1f) << 11) | (extend & 0x7e0)
-                           | (uval & 0x1f));
-                 else if (operand->size == 15)
-                   uval |= ((extend & 0xf) << 11) | (extend & 0x7f0);
-                 else
-                   uval = ((((extend >> 6) & 0x1f) | (extend & 0x20))
-                           & ((1U << operand->size) - 1));
-               }
+             ext_size = ext_operand->size;
+             operand = ext_operand;
            }
        }
+      if (operand->size == 26)
+       uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
+      else if (ext_size == 16 || ext_size == 9)
+       uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+      else if (ext_size == 15)
+       uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf);
+      else if (ext_size == 6)
+       uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
+      else
+       uval = mips_extract_operand (operand, (extend << 16) | insn);
+      if (ext_size == 9)
+       uval &= (1U << ext_size) - 1;
 
       baseaddr = memaddr + 2;
       if (operand->type == OP_PCREL)
@@ -2034,6 +2113,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
   struct mips_print_arg_state state;
   void *is = info->stream;
   bfd_boolean have_second;
+  bfd_boolean extend_only;
   unsigned int second;
   unsigned int first;
   unsigned int full;
@@ -2077,6 +2157,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
       return -1;
     }
 
+  extend_only = FALSE;
+
   if (info->endian == BFD_ENDIAN_BIG)
     first = bfd_getb16 (buffer);
   else
@@ -2128,8 +2210,17 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
        }
       else if ((first & 0xf800) == 0xf000
               && have_second
+              && !extend_only
               && (second & op->mask) == op->match)
-       match = MATCH_FULL;
+       {
+         if (op->pinfo2 & INSN2_SHORT_ONLY)
+           {
+             match = MATCH_NONE;
+             extend_only = TRUE;
+           }
+         else
+           match = MATCH_FULL;
+       }
       else
        match = MATCH_NONE;
 
@@ -2160,19 +2251,49 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
                  ++s;
                  continue;
                }
-             switch (match)
+             if (s[0] == 'N'
+                 && s[1] == ','
+                 && s[2] == 'O'
+                 && op->name[strlen (op->name) - 1] == '0')
                {
-                 case MATCH_FULL:
-                   print_mips16_insn_arg (info, &state, op, *s, memaddr + 2,
-                                          second, TRUE, first, s[1] == '(');
-                   break;
-                 case MATCH_SHORT:
-                   print_mips16_insn_arg (info, &state, op, *s, memaddr,
-                                          first, FALSE, 0, s[1] == '(');
-                   break;
-                 case MATCH_NONE:      /* Stop the compiler complaining.  */
-                   break;
+                 /* Coprocessor register 0 with sel field.  */
+                 const struct mips_cp0sel_name *n;
+                 const struct mips_operand *operand;
+                 unsigned int reg, sel;
+
+                 operand = decode_mips16_operand (*s, TRUE);
+                 reg = mips_extract_operand (operand, (first << 16) | second);
+                 s += 2;
+                 operand = decode_mips16_operand (*s, TRUE);
+                 sel = mips_extract_operand (operand, (first << 16) | second);
+
+                 /* CP0 register including 'sel' code for mftc0, to be
+                    printed textually if known.  If not known, print both
+                    CP0 register name and sel numerically since CP0 register
+                    with sel 0 may have a name unrelated to register being
+                    printed.  */
+                 n = lookup_mips_cp0sel_name (mips_cp0sel_names,
+                                              mips_cp0sel_names_len,
+                                              reg, sel);
+                 if (n != NULL)
+                   infprintf (is, "%s", n->name);
+                 else
+                   infprintf (is, "$%d,%d", reg, sel);
                }
+             else
+               switch (match)
+                 {
+                   case MATCH_FULL:
+                     print_mips16_insn_arg (info, &state, op, *s, memaddr + 2,
+                                            second, TRUE, first, s[1] == '(');
+                     break;
+                   case MATCH_SHORT:
+                     print_mips16_insn_arg (info, &state, op, *s, memaddr,
+                                            first, FALSE, 0, s[1] == '(');
+                     break;
+                   case MATCH_NONE:    /* Stop the compiler complaining.  */
+                     break;
+                 }
            }
 
          /* Figure out branch instruction type and delay slot information.  */
@@ -2433,6 +2554,9 @@ print_mips_disassembler_options (FILE *stream)
 The following MIPS specific disassembler options are supported for use\n\
 with the -M switch (multiple options should be separated by commas):\n"));
 
+  fprintf (stream, _("\n\
+  no-aliases               Use canonical instruction forms.\n"));
+
   fprintf (stream, _("\n\
   msa                      Recognize MSA instructions.\n"));
 
This page took 0.035702 seconds and 4 git commands to generate.