PR 10980
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index bc3a03b88b49c9ec07aa890aabf68d94627a7841..203f29fb775199dad386190cbad762cc35fba841 100644 (file)
@@ -1,20 +1,20 @@
 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
    Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2005
+   2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
 
-   This file is part of GDB, GAS, and the GNU binutils.
+   This file is part of the GNU opcodes library.
 
-   This program is free software; you can redistribute it and/or modify
+   This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
@@ -51,12 +51,15 @@ struct mips_cp0sel_name
   const char * const name;
 };
 
-/* The mips16 register names.  */
-static const char * const mips16_reg_names[] =
+/* The mips16 registers.  */
+static const unsigned int mips16_to_32_reg_map[] =
 {
-  "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
+  16, 17, 2, 3, 4, 5, 6, 7
 };
 
+#define mips16_reg_names(rn)   mips_gpr_names[mips16_to_32_reg_map[rn]]
+
+
 static const char * const mips_gpr_names_numeric[32] =
 {
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
@@ -121,6 +124,30 @@ static const char * const mips_cp0_names_numeric[32] =
   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
 };
 
+static const char * const mips_cp0_names_r3000[32] =
+{
+  "c0_index",     "c0_random",    "c0_entrylo",   "$3",
+  "c0_context",   "$5",           "$6",           "$7",
+  "c0_badvaddr",  "$9",           "c0_entryhi",   "$11",
+  "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
+  "$16",          "$17",          "$18",          "$19",
+  "$20",          "$21",          "$22",          "$23",
+  "$24",          "$25",          "$26",          "$27",
+  "$28",          "$29",          "$30",          "$31",
+};
+
+static const char * const mips_cp0_names_r4000[32] =
+{
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "$23",
+  "$24",          "$25",          "c0_ecc",       "c0_cacheerr",
+  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "$31",
+};
+
 static const char * const mips_cp0_names_mips3264[32] =
 {
   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
@@ -181,7 +208,28 @@ static const char * const mips_cp0_names_mips3264r2[32] =
 static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
 {
   {  4, 1, "c0_contextconfig"  },
+  {  0, 1, "c0_mvpcontrol"     },
+  {  0, 2, "c0_mvpconf0"       },
+  {  0, 3, "c0_mvpconf1"       },
+  {  1, 1, "c0_vpecontrol"     },
+  {  1, 2, "c0_vpeconf0"       },
+  {  1, 3, "c0_vpeconf1"       },
+  {  1, 4, "c0_yqmask"         },
+  {  1, 5, "c0_vpeschedule"    },
+  {  1, 6, "c0_vpeschefback"   },
+  {  2, 1, "c0_tcstatus"       },
+  {  2, 2, "c0_tcbind"         },
+  {  2, 3, "c0_tcrestart"      },
+  {  2, 4, "c0_tchalt"         },
+  {  2, 5, "c0_tccontext"      },
+  {  2, 6, "c0_tcschedule"     },
+  {  2, 7, "c0_tcschefback"    },
   {  5, 1, "c0_pagegrain"      },
+  {  6, 1, "c0_srsconf0"       },
+  {  6, 2, "c0_srsconf1"       },
+  {  6, 3, "c0_srsconf2"       },
+  {  6, 4, "c0_srsconf3"       },
+  {  6, 5, "c0_srsconf4"       },
   { 12, 1, "c0_intctl"         },
   { 12, 2, "c0_srsctl"         },
   { 12, 3, "c0_srsmap"         },
@@ -271,6 +319,56 @@ static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
   { 29, 3, "c0_datahi_d"       },
 };
 
+/* Xlr cop0 register names.  */
+static const char * const mips_cp0_names_xlr[32] = {
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "c0_debug",
+  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr_i",
+  "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
+};
+
+/* XLR's CP0 Select Registers.  */
+
+static const struct mips_cp0sel_name mips_cp0sel_names_xlr[] = {
+  {  9, 6, "c0_extintreq"       },
+  {  9, 7, "c0_extintmask"      },
+  { 15, 1, "c0_ebase"           },
+  { 16, 1, "c0_config1"         },
+  { 16, 2, "c0_config2"         },
+  { 16, 3, "c0_config3"         },
+  { 16, 7, "c0_procid2"         },
+  { 18, 1, "c0_watchlo,1"       },
+  { 18, 2, "c0_watchlo,2"       },
+  { 18, 3, "c0_watchlo,3"       },
+  { 18, 4, "c0_watchlo,4"       },
+  { 18, 5, "c0_watchlo,5"       },
+  { 18, 6, "c0_watchlo,6"       },
+  { 18, 7, "c0_watchlo,7"       },
+  { 19, 1, "c0_watchhi,1"       },
+  { 19, 2, "c0_watchhi,2"       },
+  { 19, 3, "c0_watchhi,3"       },
+  { 19, 4, "c0_watchhi,4"       },
+  { 19, 5, "c0_watchhi,5"       },
+  { 19, 6, "c0_watchhi,6"       },
+  { 19, 7, "c0_watchhi,7"       },
+  { 25, 1, "c0_perfcnt,1"       },
+  { 25, 2, "c0_perfcnt,2"       },
+  { 25, 3, "c0_perfcnt,3"       },
+  { 25, 4, "c0_perfcnt,4"       },
+  { 25, 5, "c0_perfcnt,5"       },
+  { 25, 6, "c0_perfcnt,6"       },
+  { 25, 7, "c0_perfcnt,7"       },
+  { 27, 1, "c0_cacheerr,1"      },
+  { 27, 2, "c0_cacheerr,2"      },
+  { 27, 3, "c0_cacheerr,3"      },
+  { 28, 1, "c0_datalo"          },
+  { 29, 1, "c0_datahi"          }
+};
+
 static const char * const mips_hwr_names_numeric[32] =
 {
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
@@ -322,11 +420,11 @@ const struct mips_arch_choice mips_arch_choices[] =
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
 
   { "r3000",   1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
-    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+    mips_cp0_names_r3000, NULL, 0, mips_hwr_names_numeric },
   { "r3900",   1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4000",   1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
-    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+    mips_cp0_names_r4000, NULL, 0, mips_hwr_names_numeric },
   { "r4010",   1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr4100",  1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
@@ -338,7 +436,7 @@ const struct mips_arch_choice mips_arch_choices[] =
   { "r4300",   1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4400",   1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
-    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+    mips_cp0_names_r4000, NULL, 0, mips_hwr_names_numeric },
   { "r4600",   1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4650",   1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
@@ -361,6 +459,10 @@ const struct mips_arch_choice mips_arch_choices[] =
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r12000",  1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r14000",  1, bfd_mach_mips14000, CPU_R14000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r16000",  1, bfd_mach_mips16000, CPU_R16000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "mips5",   1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
 
@@ -370,13 +472,14 @@ const struct mips_arch_choice mips_arch_choices[] =
      MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
      page 1.  */
   { "mips32",  1, bfd_mach_mipsisa32, CPU_MIPS32,
-    ISA_MIPS32 | INSN_MIPS16,
+    ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS,
     mips_cp0_names_mips3264,
     mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
     mips_hwr_names_numeric },
 
   { "mips32r2",        1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
-    ISA_MIPS32R2 | INSN_MIPS16,
+    (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
+     | INSN_MIPS3D | INSN_MT),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -389,7 +492,8 @@ const struct mips_arch_choice mips_arch_choices[] =
     mips_hwr_names_numeric },
 
   { "mips64r2",        1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
-    ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
+    (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2
+     | INSN_DSP64 | INSN_MT | INSN_MDMX),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -400,6 +504,24 @@ const struct mips_arch_choice mips_arch_choices[] =
     mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
     mips_hwr_names_numeric },
 
+  { "loongson2e",   1, bfd_mach_mips_loongson_2e, CPU_LOONGSON_2E,
+    ISA_MIPS3 | INSN_LOONGSON_2E, mips_cp0_names_numeric, 
+    NULL, 0, mips_hwr_names_numeric },
+
+  { "loongson2f",   1, bfd_mach_mips_loongson_2f, CPU_LOONGSON_2F,
+    ISA_MIPS3 | INSN_LOONGSON_2F, mips_cp0_names_numeric, 
+    NULL, 0, mips_hwr_names_numeric },
+
+  { "octeon",   1, bfd_mach_mips_octeon, CPU_OCTEON,
+    ISA_MIPS64R2 | INSN_OCTEON, mips_cp0_names_numeric, NULL, 0,
+    mips_hwr_names_numeric },
+
+  { "xlr", 1, bfd_mach_mips_xlr, CPU_XLR,
+    ISA_MIPS64 | INSN_XLR,
+    mips_cp0_names_xlr,
+    mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
+    mips_hwr_names_numeric },
+
   /* This entry, mips16, is here only for ISA/processor selection; do
      not print its name.  */
   { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
@@ -549,7 +671,7 @@ parse_mips_dis_option (const char *option, unsigned int len)
   const struct mips_arch_choice *chosen_arch;
 
   /* Try to match options that are simple flags */
-  if (strncmp (option, "no-aliases", 10) == 0)
+  if (CONST_STRNEQ (option, "no-aliases"))
     {
       no_aliases = 1;
       return;
@@ -688,7 +810,8 @@ static void
 print_insn_args (const char *d,
                 register unsigned long int l,
                 bfd_vma pc,
-                struct disassemble_info *info)
+                struct disassemble_info *info,
+                const struct mips_opcode *opp)
 {
   int op, delta;
   unsigned int lsb, msb, msbd;
@@ -728,6 +851,26 @@ print_insn_args (const char *d,
              (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
              break;
 
+           case '1':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI1) & OP_MASK_UDI1);
+             break;
+             
+           case '2':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI2) & OP_MASK_UDI2);
+             break;
+             
+           case '3':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI3) & OP_MASK_UDI3);
+             break;
+      
+           case '4':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI4) & OP_MASK_UDI4);
+             break;
+             
            case 'C':
            case 'H':
              msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
@@ -771,6 +914,61 @@ print_insn_args (const char *d,
              (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
              break;
 
+           case 't': /* Coprocessor 0 reg name */
+             (*info->fprintf_func) (info->stream, "%s",
+                                    mips_cp0_names[(l >> OP_SH_RT) &
+                                                    OP_MASK_RT]);
+             break;
+
+           case 'T': /* Coprocessor 0 reg name */
+             {
+               const struct mips_cp0sel_name *n;
+               unsigned int cp0reg, sel;
+
+               cp0reg = (l >> OP_SH_RT) & OP_MASK_RT;
+               sel = (l >> OP_SH_SEL) & OP_MASK_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)
+                 (*info->fprintf_func) (info->stream, "%s", n->name);
+               else
+                 (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
+               break;
+             }
+
+           case 'x':           /* bbit bit index */
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_BBITIND) & OP_MASK_BBITIND);
+             break;
+
+           case 'p':           /* cins, cins32, exts and exts32 position */
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_CINSPOS) & OP_MASK_CINSPOS);
+             break;
+
+           case 's':           /* cins and exts length-minus-one */
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1);
+             break;
+
+           case 'S':           /* cins32 and exts32 length-minus-one field */
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1);
+             break;
+
+           case 'Q':           /* seqi/snei immediate field */
+             op = (l >> OP_SH_SEQI) & OP_MASK_SEQI;
+             /* Sign-extend it.  */
+             op = (op ^ 512) - 512;
+             (*info->fprintf_func) (info->stream, "%d", op);
+             break;
+
            default:
              /* xgettext:c-format */
              (*info->fprintf_func) (info->stream,
@@ -780,6 +978,98 @@ print_insn_args (const char *d,
            }
          break;
 
+       case '2':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_BP) & OP_MASK_BP);
+         break;
+
+       case '3':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_SA3) & OP_MASK_SA3);
+         break;
+
+       case '4':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_SA4) & OP_MASK_SA4);
+         break;
+
+       case '5':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_IMM8) & OP_MASK_IMM8);
+         break;
+
+       case '6':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_RS) & OP_MASK_RS);
+         break;
+
+       case '7':
+         (*info->fprintf_func) (info->stream, "$ac%ld",
+                                (l >> OP_SH_DSPACC) & OP_MASK_DSPACC);
+         break;
+
+       case '8':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_WRDSP) & OP_MASK_WRDSP);
+         break;
+
+       case '9':
+         (*info->fprintf_func) (info->stream, "$ac%ld",
+                                (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S);
+         break;
+
+       case '0': /* dsp 6-bit signed immediate in bit 20 */
+         delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT);
+         if (delta & 0x20) /* test sign bit */
+           delta |= ~OP_MASK_DSPSFT;
+         (*info->fprintf_func) (info->stream, "%d", delta);
+         break;
+
+       case ':': /* dsp 7-bit signed immediate in bit 19 */
+         delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7);
+         if (delta & 0x40) /* test sign bit */
+           delta |= ~OP_MASK_DSPSFT_7;
+         (*info->fprintf_func) (info->stream, "%d", delta);
+         break;
+
+       case '\'':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_RDDSP) & OP_MASK_RDDSP);
+         break;
+
+       case '@': /* dsp 10-bit signed immediate in bit 16 */
+         delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
+         if (delta & 0x200) /* test sign bit */
+           delta |= ~OP_MASK_IMM10;
+         (*info->fprintf_func) (info->stream, "%d", delta);
+         break;
+
+       case '!':
+         (*info->fprintf_func) (info->stream, "%ld",
+                                (l >> OP_SH_MT_U) & OP_MASK_MT_U);
+         break;
+
+       case '$':
+         (*info->fprintf_func) (info->stream, "%ld",
+                                (l >> OP_SH_MT_H) & OP_MASK_MT_H);
+         break;
+
+       case '*':
+         (*info->fprintf_func) (info->stream, "$ac%ld",
+                                (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T);
+         break;
+
+       case '&':
+         (*info->fprintf_func) (info->stream, "$ac%ld",
+                                (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D);
+         break;
+
+       case 'g':
+         /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2.  */
+         (*info->fprintf_func) (info->stream, "$%ld",
+                                (l >> OP_SH_RD) & OP_MASK_RD);
+         break;
+
        case 's':
        case 'b':
        case 'r':
@@ -796,7 +1086,7 @@ print_insn_args (const char *d,
 
        case 'i':
        case 'u':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
          break;
 
@@ -824,6 +1114,10 @@ print_insn_args (const char *d,
        case 'a':
          info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
                          | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
+         /* For gdb disassembler, force odd address on jalx.  */
+         if (info->flavour == bfd_target_unknown_flavour
+             && strcmp (opp->name, "jalx") == 0)
+           info->target |= 1;
          (*info->print_address_func) (info->target, info);
          break;
 
@@ -870,32 +1164,34 @@ print_insn_args (const char *d,
          break;
 
        case '<':
-         (*info->fprintf_func) (info->stream, "0x%x",
+       case '1':
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
          break;
 
        case 'c':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_CODE) & OP_MASK_CODE);
          break;
 
        case 'q':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
          break;
 
        case 'C':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
          break;
 
        case 'B':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
+
                                 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
          break;
 
        case 'J':
-         (*info->fprintf_func) (info->stream, "0x%x",
+         (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
          break;
 
@@ -929,7 +1225,7 @@ print_insn_args (const char *d,
             'T' format.  Therefore, until we gain understanding of
             cp2 register names, we can simply print the register
             numbers.  */
-         (*info->fprintf_func) (info->stream, "$%d",
+         (*info->fprintf_func) (info->stream, "$%ld",
                                 (l >> OP_SH_RT) & OP_MASK_RT);
          break;
 
@@ -943,7 +1239,7 @@ print_insn_args (const char *d,
            (*info->fprintf_func) (info->stream, "%s",
                                   mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
          else
-           (*info->fprintf_func) (info->stream, "$%d",
+           (*info->fprintf_func) (info->stream, "$%ld",
                                   (l >> OP_SH_RD) & OP_MASK_RD);
          break;
 
@@ -953,37 +1249,39 @@ print_insn_args (const char *d,
          break;
 
        case 'N':
-         (*info->fprintf_func) (info->stream, "$fcc%d",
+         (*info->fprintf_func) (info->stream,
+                                ((opp->pinfo & (FP_D | FP_S)) != 0
+                                 ? "$fcc%ld" : "$cc%ld"),
                                 (l >> OP_SH_BCC) & OP_MASK_BCC);
          break;
 
        case 'M':
-         (*info->fprintf_func) (info->stream, "$fcc%d",
+         (*info->fprintf_func) (info->stream, "$fcc%ld",
                                 (l >> OP_SH_CCC) & OP_MASK_CCC);
          break;
 
        case 'P':
-         (*info->fprintf_func) (info->stream, "%d",
+         (*info->fprintf_func) (info->stream, "%ld",
                                 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
          break;
 
        case 'e':
-         (*info->fprintf_func) (info->stream, "%d",
+         (*info->fprintf_func) (info->stream, "%ld",
                                 (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
          break;
 
        case '%':
-         (*info->fprintf_func) (info->stream, "%d",
+         (*info->fprintf_func) (info->stream, "%ld",
                                 (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
          break;
 
        case 'H':
-         (*info->fprintf_func) (info->stream, "%d",
+         (*info->fprintf_func) (info->stream, "%ld",
                                 (l >> OP_SH_SEL) & OP_MASK_SEL);
          break;
 
        case 'O':
-         (*info->fprintf_func) (info->stream, "%d",
+         (*info->fprintf_func) (info->stream, "%ld",
                                 (l >> OP_SH_ALN) & OP_MASK_ALN);
          break;
 
@@ -999,42 +1297,42 @@ print_insn_args (const char *d,
                for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
                  if ((vsel & 1) == 0)
                    break;
-               (*info->fprintf_func) (info->stream, "$v%d[%d]",
+               (*info->fprintf_func) (info->stream, "$v%ld[%d]",
                                       (l >> OP_SH_FT) & OP_MASK_FT,
                                       vsel >> 1);
              }
            else if ((vsel & 0x08) == 0)
              {
-               (*info->fprintf_func) (info->stream, "$v%d",
+               (*info->fprintf_func) (info->stream, "$v%ld",
                                       (l >> OP_SH_FT) & OP_MASK_FT);
              }
            else
              {
-               (*info->fprintf_func) (info->stream, "0x%x",
+               (*info->fprintf_func) (info->stream, "0x%lx",
                                       (l >> OP_SH_FT) & OP_MASK_FT);
              }
          }
          break;
 
        case 'X':
-         (*info->fprintf_func) (info->stream, "$v%d",
+         (*info->fprintf_func) (info->stream, "$v%ld",
                                 (l >> OP_SH_FD) & OP_MASK_FD);
          break;
 
        case 'Y':
-         (*info->fprintf_func) (info->stream, "$v%d",
+         (*info->fprintf_func) (info->stream, "$v%ld",
                                 (l >> OP_SH_FS) & OP_MASK_FS);
          break;
 
        case 'Z':
-         (*info->fprintf_func) (info->stream, "$v%d",
+         (*info->fprintf_func) (info->stream, "$v%ld",
                                 (l >> OP_SH_FT) & OP_MASK_FT);
          break;
 
        default:
          /* xgettext:c-format */
          (*info->fprintf_func) (info->stream,
-                                _("# internal error, undefined modifier(%c)"),
+                                _("# internal error, undefined modifier (%c)"),
                                 *d);
          return;
        }
@@ -1131,7 +1429,7 @@ print_insn_mips (bfd_vma memaddr,
              if (d != NULL && *d != '\0')
                {
                  (*info->fprintf_func) (info->stream, "\t");
-                 print_insn_args (d, word, memaddr, info);
+                 print_insn_args (d, word, memaddr, info, op);
                }
 
              return INSNLEN;
@@ -1141,7 +1439,7 @@ print_insn_mips (bfd_vma memaddr,
 
   /* Handle undefined instructions.  */
   info->insn_type = dis_noninsn;
-  (*info->fprintf_func) (info->stream, "0x%x", word);
+  (*info->fprintf_func) (info->stream, "0x%lx", word);
   return INSNLEN;
 }
 \f
@@ -1167,27 +1465,27 @@ print_mips16_insn_arg (char type,
     case 'y':
     case 'w':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RY)
-                                              & MIPS16OP_MASK_RY)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RY)
+                                              & MIPS16OP_MASK_RY)));
       break;
 
     case 'x':
     case 'v':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RX)
-                                              & MIPS16OP_MASK_RX)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RX)
+                                              & MIPS16OP_MASK_RX)));
       break;
 
     case 'z':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RZ)
-                                              & MIPS16OP_MASK_RZ)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RZ)
+                                              & MIPS16OP_MASK_RZ)));
       break;
 
     case 'Z':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
-                                              & MIPS16OP_MASK_MOVE32Z)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z)
+                                              & MIPS16OP_MASK_MOVE32Z)));
       break;
 
     case '0':
@@ -1469,15 +1767,26 @@ print_mips16_insn_arg (char type,
                  }
              }
            info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
+           if (pcrel && branch
+               && info->flavour == bfd_target_unknown_flavour)
+             /* For gdb disassembler, maintain odd address.  */
+             info->target |= 1;
            (*info->print_address_func) (info->target, info);
          }
       }
       break;
 
     case 'a':
-      if (! use_extend)
-       extend = 0;
-      l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+      {
+       int jalx = l & 0x400;
+
+       if (! use_extend)
+         extend = 0;
+       l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+       if (!jalx && info->flavour == bfd_target_unknown_flavour)
+         /* For gdb disassembler, maintain odd address.  */
+         l |= 1;
+      }
       info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
       (*info->print_address_func) (info->target, info);
       info->insn_type = dis_jsr;
@@ -1540,6 +1849,92 @@ print_mips16_insn_arg (char type,
       }
       break;
 
+    case 'm':
+    case 'M':
+      /* MIPS16e save/restore.  */
+      {
+      int need_comma = 0;
+      int amask, args, statics;
+      int nsreg, smask;
+      int framesz;
+      int i, j;
+
+      l = l & 0x7f;
+      if (use_extend)
+        l |= extend << 16;
+
+      amask = (l >> 16) & 0xf;
+      if (amask == MIPS16_ALL_ARGS)
+        {
+          args = 4;
+          statics = 0;
+        }
+      else if (amask == MIPS16_ALL_STATICS)
+        {
+          args = 0;
+          statics = 4;
+        }
+      else
+        {
+          args = amask >> 2;
+          statics = amask & 3;
+        }
+
+      if (args > 0) {
+          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+          if (args > 1)
+            (*info->fprintf_func) (info->stream, "-%s",
+                                   mips_gpr_names[4 + args - 1]);
+          need_comma = 1;
+      }
+
+      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
+      if (framesz == 0 && !use_extend)
+        framesz = 128;
+
+      (*info->fprintf_func) (info->stream, "%s%d", 
+                             need_comma ? "," : "",
+                             framesz);
+
+      if (l & 0x40)                   /* $ra */
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
+
+      nsreg = (l >> 24) & 0x7;
+      smask = 0;
+      if (l & 0x20)                   /* $s0 */
+        smask |= 1 << 0;
+      if (l & 0x10)                   /* $s1 */
+        smask |= 1 << 1;
+      if (nsreg > 0)                  /* $s2-$s8 */
+        smask |= ((1 << nsreg) - 1) << 2;
+
+      /* Find first set static reg bit.  */
+      for (i = 0; i < 9; i++)
+        {
+          if (smask & (1 << i))
+            {
+              (*info->fprintf_func) (info->stream, ",%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)
+                (*info->fprintf_func) (info->stream, "-%s",
+                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+              i = j + 1;
+            }
+        }
+
+      /* Statics $ax - $a3.  */
+      if (statics == 1)
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+      else if (statics > 0) 
+        (*info->fprintf_func) (info->stream, ",%s-%s", 
+                               mips_gpr_names[7 - statics + 1],
+                               mips_gpr_names[7]);
+      }
+      break;
+
     default:
       /* xgettext:c-format */
       (*info->fprintf_func)
@@ -1732,10 +2127,10 @@ _print_insn_mips (bfd_vma memaddr,
 
 #if SYMTAB_AVAILABLE
   if (info->mach == bfd_mach_mips16
-      || (info->flavour == bfd_target_elf_flavour
-         && info->symbols != NULL
-         && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
-             == STO_MIPS16)))
+      || (info->symbols != NULL
+         && bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour
+         && ELF_ST_IS_MIPS16 ((*(elf_symbol_type **) info->symbols)
+                              ->internal_elf_sym.st_other)))
     return print_insn_mips16 (memaddr, info);
 #endif
 
This page took 0.040331 seconds and 4 git commands to generate.