include/opcode/
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index bf1ef40b883cb0c3bf43cd7110c99317c43551c0..333d4fee8b60bab800ccbd8f35afb17351b54a22 100644 (file)
@@ -591,8 +591,8 @@ const struct mips_arch_choice mips_arch_choices[] =
 
   { "mips32r2",        1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
     ISA_MIPS32R2,
-    (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_MIPS3D | ASE_MT
-     | ASE_MCU | ASE_VIRT),
+    (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
+     | ASE_MT | ASE_MCU | ASE_VIRT),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -606,8 +606,8 @@ const struct mips_arch_choice mips_arch_choices[] =
 
   { "mips64r2",        1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
     ISA_MIPS64R2,
-    (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_MT | ASE_MDMX
-     | ASE_MCU | ASE_VIRT | ASE_VIRT64),
+    (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
+     | ASE_MDMX | ASE_MCU | ASE_VIRT | ASE_VIRT64),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -977,9 +977,8 @@ print_insn_args (const char *d,
                 const struct mips_opcode *opp)
 {
   const fprintf_ftype infprintf = info->fprintf_func;
-  unsigned int lsb, msb, msbd;
+  unsigned int lsb, msb, msbd, cpreg;
   void *is = info->stream;
-  int op;
 
   lsb = 0;
 
@@ -1044,28 +1043,6 @@ print_insn_args (const char *d,
              infprintf (is, "0x%x", msbd + 1);
              break;
 
-           case 'D':
-             {
-               const struct mips_cp0sel_name *n;
-               unsigned int cp0reg, sel;
-
-               cp0reg = GET_OP (l, RD);
-               sel = GET_OP (l, SEL);
-
-               /* CP0 register including 'sel' code for mtcN (et al.), 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, cp0reg, sel);
-               if (n != NULL)
-                 infprintf (is, "%s", n->name);
-               else
-                 infprintf (is, "$%d,%d", cp0reg, sel);
-               break;
-             }
-
            case 'E':
              lsb = GET_OP (l, SHAMT) + 32;
              infprintf (is, "0x%x", lsb);
@@ -1089,28 +1066,6 @@ print_insn_args (const char *d,
              infprintf (is, "%s", mips_cp0_names[GET_OP (l, RT)]);
              break;
 
-           case 'T': /* Coprocessor 0 reg name */
-             {
-               const struct mips_cp0sel_name *n;
-               unsigned int cp0reg, sel;
-
-               cp0reg = GET_OP (l, RT);
-               sel = GET_OP (l, SEL);
-
-               /* 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, cp0reg, sel);
-               if (n != NULL)
-                 infprintf (is, "%s", n->name);
-               else
-                 infprintf (is, "$%d,%d", cp0reg, sel);
-               break;
-             }
-
            case 'x':           /* bbit bit index */
              infprintf (is, "0x%x", GET_OP (l, BBITIND));
              break;
@@ -1152,6 +1107,10 @@ print_insn_args (const char *d,
              infprintf (is, "%s", mips_fpr_names[GET_OP (l, FZ)]);
              break;
 
+           case 'j':   /* 9-bit signed offset in bit 7.  */
+             infprintf (is, "%d", GET_OP_S (l, EVAOFFSET));
+             break;
+
            default:
              /* xgettext:c-format */
              infprintf (is,
@@ -1360,26 +1319,44 @@ print_insn_args (const char *d,
          break;
 
        case 'E':
-         /* Coprocessor register for lwcN instructions, et al.
-
-            Note that there is no load/store cp0 instructions, and
-            that FPU (cp1) instructions disassemble this field using
-            'T' format.  Therefore, until we gain understanding of
-            cp2 register names, we can simply print the register
-            numbers.  */
-         infprintf (is, "$%d", GET_OP (l, RT));
-         break;
+         cpreg = GET_OP (l, RT);
+         goto copro;
 
        case 'G':
+         cpreg = GET_OP (l, RD);
+       copro:
          /* Coprocessor register for mtcN instructions, et al.  Note
             that FPU (cp1) instructions disassemble this field using
             'S' format.  Therefore, we only need to worry about cp0,
             cp2, and cp3.  */
-         op = GET_OP (l, OP);
-         if (op == OP_OP_COP0)
-           infprintf (is, "%s", mips_cp0_names[GET_OP (l, RD)]);
+         if (opp->name[strlen (opp->name) - 1] == '0')
+           {
+             if (d[1] == ',' && d[2] == 'H')
+               {
+                 const struct mips_cp0sel_name *n;
+                 unsigned int sel;
+
+                 sel = GET_OP (l, SEL);
+
+                 /* CP0 register including 'sel' code for mtcN (et al.), 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,
+                                              cpreg, sel);
+                 if (n != NULL)
+                   infprintf (is, "%s", n->name);
+                 else
+                   infprintf (is, "$%d,%d", cpreg, sel);
+                 d += 2;
+               }
+             else
+               infprintf (is, "%s", mips_cp0_names[cpreg]);
+           }
          else
-           infprintf (is, "$%d", GET_OP (l, RD));
+           infprintf (is, "$%d", cpreg);
          break;
 
        case 'K':
@@ -2052,6 +2029,23 @@ print_mips16_insn_arg (char type,
     }
 }
 
+
+/* Check if the given address is the last word of a MIPS16 PLT entry.
+   This word is data and depending on the value it may interfere with
+   disassembly of further PLT entries.  We make use of the fact PLT
+   symbols are marked BSF_SYNTHETIC.  */
+static bfd_boolean
+is_mips16_plt_tail (struct disassemble_info *info, bfd_vma addr)
+{
+  if (info->symbols
+      && info->symbols[0]
+      && (info->symbols[0]->flags & BSF_SYNTHETIC)
+      && addr == bfd_asymbol_value (info->symbols[0]) + 12)
+    return TRUE;
+
+  return FALSE;
+}
+
 /* Disassemble mips16 instructions.  */
 
 static int
@@ -2059,7 +2053,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
 {
   const fprintf_ftype infprintf = info->fprintf_func;
   int status;
-  bfd_byte buffer[2];
+  bfd_byte buffer[4];
   int length;
   int insn;
   bfd_boolean use_extend;
@@ -2072,11 +2066,32 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
   info->insn_info_valid = 1;
   info->branch_delay_insns = 0;
   info->data_size = 0;
-  info->insn_type = dis_nonbranch;
   info->target = 0;
   info->target2 = 0;
 
-  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+  /* Decode PLT entry's GOT slot address word.  */
+  if (is_mips16_plt_tail (info, memaddr))
+    {
+      info->insn_type = dis_noninsn;
+      status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+      if (status == 0)
+       {
+         unsigned int gotslot;
+
+         if (info->endian == BFD_ENDIAN_BIG)
+           gotslot = bfd_getb32 (buffer);
+         else
+           gotslot = bfd_getl32 (buffer);
+         infprintf (is, ".word\t0x%x", gotslot);
+
+         return 4;
+       }
+    }
+  else
+    {
+      info->insn_type = dis_nonbranch;
+      status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+    }
   if (status != 0)
     {
       (*info->memory_error_func) (status, memaddr, info);
@@ -2544,28 +2559,37 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
                  /* Coprocessor register for mtcN instructions, et al.  Note
                     that FPU (cp1) instructions disassemble this field using
                     'S' format.  Therefore, we only need to worry about cp0,
-                    cp2, and cp3.
-                    The microMIPS encoding does not have a coprocessor
-                    identifier field as such, so we must work out the
-                    coprocessor number by looking at the opcode.  */
-                 switch (insn
-                         & ~((MICROMIPSOP_MASK_RT << MICROMIPSOP_SH_RT)
-                             | (MICROMIPSOP_MASK_RS << MICROMIPSOP_SH_RS)))
+                    cp2, and cp3.  */
+                 if (op->name[strlen (op->name) - 1] == '0')
                    {
-                   case 0x000000fc:                            /* mfc0  */
-                   case 0x000002fc:                            /* mtc0  */
-                   case 0x000004fc:                            /* mfgc0  */
-                   case 0x000006fc:                            /* mtgc0  */
-                   case 0x580000fc:                            /* dmfc0 */
-                   case 0x580002fc:                            /* dmtc0 */
-                   case 0x580000e7:                            /* dmfgc0 */
-                   case 0x580002e7:                            /* dmtgc0 */
-                     infprintf (is, "%s", mips_cp0_names[GET_OP (insn, RS)]);
-                     break;
-                   default:
-                     infprintf (is, "$%d", GET_OP (insn, RS));
-                     break;
+                     if (s[1] == ',' && s[2] == 'H')
+                       {
+                         const struct mips_cp0sel_name *n;
+                         unsigned int cp0reg, sel;
+
+                         cp0reg = GET_OP (insn, RS);
+                         sel = GET_OP (insn, SEL);
+
+                         /* CP0 register including 'sel' code for mtcN
+                            (et al.), 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,
+                                                      cp0reg, sel);
+                         if (n != NULL)
+                           infprintf (is, "%s", n->name);
+                         else
+                           infprintf (is, "$%d,%d", cp0reg, sel);
+                         s += 2;
+                       }
+                     else
+                       infprintf (is, "%s", mips_cp0_names[GET_OP (insn, RS)]);
                    }
+                 else
+                   infprintf (is, "$%d", GET_OP (insn, RS));
                  break;
 
                case 'H':
@@ -2621,29 +2645,6 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
                      infprintf (is, "0x%x", msbd + 1);
                      break;
 
-                   case 'D':
-                     {
-                       const struct mips_cp0sel_name *n;
-                       unsigned int cp0reg, sel;
-
-                       cp0reg = GET_OP (insn, RS);
-                       sel = GET_OP (insn, SEL);
-
-                       /* CP0 register including 'sel' code for mtcN
-                          (et al.), 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,
-                                                    cp0reg, sel);
-                       if (n != NULL)
-                         infprintf (is, "%s", n->name);
-                       else
-                         infprintf (is, "$%d,%d", cp0reg, sel);
-                       break;
-                     }
-
                    case 'E':
                      lsb = GET_OP (insn, EXTLSB) + 32;
                      infprintf (is, "0x%x", lsb);
@@ -2659,6 +2660,11 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
                      infprintf (is, "0x%x", msbd + 1);
                      break;
 
+                   case 'j':   /* 9-bit signed offset in bit 0. */
+                     delta = GET_OP_S (insn, EVAOFFSET);
+                     infprintf (is, "%d", delta);
+                     break;
+
                    default:
                      /* xgettext:c-format */
                      infprintf (is,
@@ -2954,27 +2960,26 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
 static bfd_boolean
 is_compressed_mode_p (struct disassemble_info *info)
 {
-  elf_symbol_type *symbol;
-  int pos;
   int i;
-
-  for (i = 0; i < info->num_symbols; i++)
-    {
-      pos = info->symtab_pos + i;
-
-      if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour)
-       continue;
-
-      if (info->symtab[pos]->section != info->section)
-       continue;
-
-      symbol = (elf_symbol_type *) info->symtab[pos];
-      if ((!micromips_ase
-          && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
-         || (micromips_ase
-             && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
-           return 1;
-    }
+  int l;
+
+  for (i = info->symtab_pos, l = i + info->num_symbols; i < l; i++)
+    if (((info->symtab[i])->flags & BSF_SYNTHETIC) != 0
+       && ((!micromips_ase
+            && ELF_ST_IS_MIPS16 ((*info->symbols)->udata.i))
+           || (micromips_ase
+               && ELF_ST_IS_MICROMIPS ((*info->symbols)->udata.i))))
+      return 1;
+    else if (bfd_asymbol_flavour (info->symtab[i]) == bfd_target_elf_flavour
+             && info->symtab[i]->section == info->section)
+      {
+       elf_symbol_type *symbol = (elf_symbol_type *) info->symtab[i];
+       if ((!micromips_ase
+            && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
+           || (micromips_ase
+               && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
+         return 1;
+      }
 
   return 0;
 }
This page took 0.027269 seconds and 4 git commands to generate.