xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/mips-dis.c (revision c88b1d6c2990dec69cf89c9efe884ddff6a0bbe5)
12159047fSniklas /* Print mips instructions for GDB, the GNU debugger, or for objdump.
22159047fSniklas    Copyright 1989, 1991, 1992 Free Software Foundation, Inc.
32159047fSniklas    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
42159047fSniklas 
52159047fSniklas This file is part of GDB.
62159047fSniklas 
72159047fSniklas This program is free software; you can redistribute it and/or modify
82159047fSniklas it under the terms of the GNU General Public License as published by
92159047fSniklas the Free Software Foundation; either version 2 of the License, or
102159047fSniklas (at your option) any later version.
112159047fSniklas 
122159047fSniklas This program is distributed in the hope that it will be useful,
132159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
142159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152159047fSniklas GNU General Public License for more details.
162159047fSniklas 
172159047fSniklas You should have received a copy of the GNU General Public License
182159047fSniklas along with this program; if not, write to the Free Software
192159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
202159047fSniklas 
212159047fSniklas #include <ansidecl.h>
222159047fSniklas #include "sysdep.h"
232159047fSniklas #include "dis-asm.h"
242159047fSniklas #include "opcode/mips.h"
252159047fSniklas 
262159047fSniklas /* Mips instructions are never longer than this many bytes.  */
272159047fSniklas #define MAXLEN 4
282159047fSniklas 
292159047fSniklas /* FIXME: This should be shared with gdb somehow.  */
302159047fSniklas #define REGISTER_NAMES 	\
312159047fSniklas     {	"zero",	"at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3", \
322159047fSniklas 	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7", \
332159047fSniklas 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7", \
342159047fSniklas 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra", \
352159047fSniklas 	"sr",	"lo",	"hi",	"bad",	"cause","pc",    \
362159047fSniklas 	"f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7", \
372159047fSniklas 	"f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15", \
382159047fSniklas 	"f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",\
392159047fSniklas 	"f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",\
402159047fSniklas 	"fsr",  "fir",  "fp",   "inx",  "rand", "tlblo","ctxt", "tlbhi",\
412159047fSniklas 	"epc",  "prid"\
422159047fSniklas     }
432159047fSniklas 
442159047fSniklas static CONST char * CONST reg_names[] = REGISTER_NAMES;
452159047fSniklas 
462159047fSniklas /* subroutine */
472159047fSniklas static void
482159047fSniklas print_insn_arg (d, l, pc, info)
492159047fSniklas      const char *d;
502159047fSniklas      register unsigned long int l;
512159047fSniklas      bfd_vma pc;
522159047fSniklas      struct disassemble_info *info;
532159047fSniklas {
542159047fSniklas   int delta;
552159047fSniklas 
562159047fSniklas   switch (*d)
572159047fSniklas     {
582159047fSniklas     case ',':
592159047fSniklas     case '(':
602159047fSniklas     case ')':
612159047fSniklas       (*info->fprintf_func) (info->stream, "%c", *d);
622159047fSniklas       break;
632159047fSniklas 
642159047fSniklas     case 's':
652159047fSniklas     case 'b':
662159047fSniklas     case 'r':
672159047fSniklas     case 'v':
682159047fSniklas       (*info->fprintf_func) (info->stream, "$%s",
692159047fSniklas 			     reg_names[(l >> OP_SH_RS) & OP_MASK_RS]);
702159047fSniklas       break;
712159047fSniklas 
722159047fSniklas     case 't':
732159047fSniklas     case 'w':
742159047fSniklas       (*info->fprintf_func) (info->stream, "$%s",
752159047fSniklas 			     reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
762159047fSniklas       break;
772159047fSniklas 
782159047fSniklas     case 'i':
792159047fSniklas     case 'u':
80*c88b1d6cSniklas       (*info->fprintf_func) (info->stream, "0x%x",
812159047fSniklas 			(l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
822159047fSniklas       break;
832159047fSniklas 
842159047fSniklas     case 'j': /* same as i, but sign-extended */
852159047fSniklas     case 'o':
862159047fSniklas       delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
872159047fSniklas       if (delta & 0x8000)
882159047fSniklas 	delta |= ~0xffff;
892159047fSniklas       (*info->fprintf_func) (info->stream, "%d",
902159047fSniklas 			     delta);
912159047fSniklas       break;
922159047fSniklas 
932159047fSniklas     case 'h':
942159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
952159047fSniklas 			     (unsigned int) ((l >> OP_SH_PREFX)
962159047fSniklas 					     & OP_MASK_PREFX));
972159047fSniklas       break;
982159047fSniklas 
992159047fSniklas     case 'k':
1002159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
1012159047fSniklas 			     (unsigned int) ((l >> OP_SH_CACHE)
1022159047fSniklas 					     & OP_MASK_CACHE));
1032159047fSniklas       break;
1042159047fSniklas 
1052159047fSniklas     case 'a':
1062159047fSniklas       (*info->print_address_func)
1072159047fSniklas 	(((pc & 0xF0000000) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)),
1082159047fSniklas 	 info);
1092159047fSniklas       break;
1102159047fSniklas 
1112159047fSniklas     case 'p':
1122159047fSniklas       /* sign extend the displacement */
1132159047fSniklas       delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
1142159047fSniklas       if (delta & 0x8000)
1152159047fSniklas 	delta |= ~0xffff;
1162159047fSniklas       (*info->print_address_func)
1172159047fSniklas 	((delta << 2) + pc + 4,
1182159047fSniklas 	 info);
1192159047fSniklas       break;
1202159047fSniklas 
1212159047fSniklas     case 'd':
1222159047fSniklas       (*info->fprintf_func) (info->stream, "$%s",
1232159047fSniklas 			     reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
1242159047fSniklas       break;
1252159047fSniklas 
1262159047fSniklas     case 'z':
1272159047fSniklas       (*info->fprintf_func) (info->stream, "$%s", reg_names[0]);
1282159047fSniklas       break;
1292159047fSniklas 
1302159047fSniklas     case '<':
1312159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
1322159047fSniklas 			     (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
1332159047fSniklas       break;
1342159047fSniklas 
1352159047fSniklas     case 'c':
1362159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
1372159047fSniklas 			     (l >> OP_SH_CODE) & OP_MASK_CODE);
1382159047fSniklas       break;
1392159047fSniklas 
1402159047fSniklas     case 'C':
1412159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
1422159047fSniklas 			     (l >> OP_SH_COPZ) & OP_MASK_COPZ);
1432159047fSniklas       break;
1442159047fSniklas 
1452159047fSniklas     case 'B':
1462159047fSniklas       (*info->fprintf_func) (info->stream, "0x%x",
1472159047fSniklas 			     (l >> OP_SH_SYSCALL) & OP_MASK_SYSCALL);
1482159047fSniklas       break;
1492159047fSniklas 
1502159047fSniklas     case 'S':
1512159047fSniklas     case 'V':
1522159047fSniklas       (*info->fprintf_func) (info->stream, "$f%d",
1532159047fSniklas 			     (l >> OP_SH_FS) & OP_MASK_FS);
1542159047fSniklas       break;
1552159047fSniklas 
1562159047fSniklas     case 'T':
1572159047fSniklas     case 'W':
1582159047fSniklas       (*info->fprintf_func) (info->stream, "$f%d",
1592159047fSniklas 			     (l >> OP_SH_FT) & OP_MASK_FT);
1602159047fSniklas       break;
1612159047fSniklas 
1622159047fSniklas     case 'D':
1632159047fSniklas       (*info->fprintf_func) (info->stream, "$f%d",
1642159047fSniklas 			     (l >> OP_SH_FD) & OP_MASK_FD);
1652159047fSniklas       break;
1662159047fSniklas 
1672159047fSniklas     case 'R':
1682159047fSniklas       (*info->fprintf_func) (info->stream, "$f%d",
1692159047fSniklas 			     (l >> OP_SH_FR) & OP_MASK_FR);
1702159047fSniklas       break;
1712159047fSniklas 
1722159047fSniklas     case 'E':
1732159047fSniklas       (*info->fprintf_func) (info->stream, "$%d",
1742159047fSniklas 			     (l >> OP_SH_RT) & OP_MASK_RT);
1752159047fSniklas       break;
1762159047fSniklas 
1772159047fSniklas     case 'G':
1782159047fSniklas       (*info->fprintf_func) (info->stream, "$%d",
1792159047fSniklas 			     (l >> OP_SH_RD) & OP_MASK_RD);
1802159047fSniklas       break;
1812159047fSniklas 
1822159047fSniklas     case 'N':
1832159047fSniklas       (*info->fprintf_func) (info->stream, "%d",
1842159047fSniklas 			     (l >> OP_SH_BCC) & OP_MASK_BCC);
1852159047fSniklas       break;
1862159047fSniklas 
1872159047fSniklas     case 'M':
1882159047fSniklas       (*info->fprintf_func) (info->stream, "%d",
1892159047fSniklas 			     (l >> OP_SH_CCC) & OP_MASK_CCC);
1902159047fSniklas       break;
1912159047fSniklas 
1922159047fSniklas     default:
1932159047fSniklas       (*info->fprintf_func) (info->stream,
1942159047fSniklas 			     "# internal error, undefined modifier(%c)", *d);
1952159047fSniklas       break;
1962159047fSniklas     }
1972159047fSniklas }
1982159047fSniklas 
1992159047fSniklas /* Print the mips instruction at address MEMADDR in debugged memory,
2002159047fSniklas    on using INFO.  Returns length of the instruction, in bytes, which is
2012159047fSniklas    always 4.  BIGENDIAN must be 1 if this is big-endian code, 0 if
2022159047fSniklas    this is little-endian code.  */
2032159047fSniklas 
2042159047fSniklas static int
2052159047fSniklas _print_insn_mips (memaddr, word, info)
2062159047fSniklas      bfd_vma memaddr;
2072159047fSniklas      struct disassemble_info *info;
2082159047fSniklas      unsigned long int word;
2092159047fSniklas {
2102159047fSniklas   register const struct mips_opcode *op;
2112159047fSniklas   static boolean init = 0;
2122159047fSniklas   static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
2132159047fSniklas 
2142159047fSniklas   /* Build a hash table to shorten the search time.  */
2152159047fSniklas   if (! init)
2162159047fSniklas     {
217*c88b1d6cSniklas       unsigned int i;
2182159047fSniklas 
2192159047fSniklas       for (i = 0; i <= OP_MASK_OP; i++)
2202159047fSniklas 	{
2212159047fSniklas 	  for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
2222159047fSniklas 	    {
2232159047fSniklas 	      if (op->pinfo == INSN_MACRO)
2242159047fSniklas 		continue;
2252159047fSniklas 	      if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
2262159047fSniklas 		{
2272159047fSniklas 		  mips_hash[i] = op;
2282159047fSniklas 		  break;
2292159047fSniklas 		}
2302159047fSniklas 	    }
2312159047fSniklas         }
2322159047fSniklas 
2332159047fSniklas       init = 1;
2342159047fSniklas     }
2352159047fSniklas 
2362159047fSniklas   op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
2372159047fSniklas   if (op != NULL)
2382159047fSniklas     {
2392159047fSniklas       for (; op < &mips_opcodes[NUMOPCODES]; op++)
2402159047fSniklas 	{
2412159047fSniklas 	  if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
2422159047fSniklas 	    {
2432159047fSniklas 	      register const char *d;
2442159047fSniklas 
2452159047fSniklas 	      (*info->fprintf_func) (info->stream, "%s", op->name);
2462159047fSniklas 
2472159047fSniklas 	      d = op->args;
2482159047fSniklas 	      if (d != NULL)
2492159047fSniklas 		{
2502159047fSniklas 		  (*info->fprintf_func) (info->stream, " ");
2512159047fSniklas 		  for (; *d != '\0'; d++)
2522159047fSniklas 		    print_insn_arg (d, word, memaddr, info);
2532159047fSniklas 		}
2542159047fSniklas 
2552159047fSniklas 	      return 4;
2562159047fSniklas 	    }
2572159047fSniklas 	}
2582159047fSniklas     }
2592159047fSniklas 
2602159047fSniklas   /* Handle undefined instructions.  */
2612159047fSniklas   (*info->fprintf_func) (info->stream, "0x%x", word);
2622159047fSniklas   return 4;
2632159047fSniklas }
2642159047fSniklas 
2652159047fSniklas int
2662159047fSniklas print_insn_big_mips (memaddr, info)
2672159047fSniklas      bfd_vma memaddr;
2682159047fSniklas      struct disassemble_info *info;
2692159047fSniklas {
2702159047fSniklas   bfd_byte buffer[4];
2712159047fSniklas   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
2722159047fSniklas   if (status == 0)
2732159047fSniklas     return _print_insn_mips (memaddr, (unsigned long) bfd_getb32 (buffer), info);
2742159047fSniklas   else
2752159047fSniklas     {
2762159047fSniklas       (*info->memory_error_func) (status, memaddr, info);
2772159047fSniklas       return -1;
2782159047fSniklas     }
2792159047fSniklas }
2802159047fSniklas 
2812159047fSniklas int
2822159047fSniklas print_insn_little_mips (memaddr, info)
2832159047fSniklas      bfd_vma memaddr;
2842159047fSniklas      struct disassemble_info *info;
2852159047fSniklas {
2862159047fSniklas   bfd_byte buffer[4];
2872159047fSniklas   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
2882159047fSniklas   if (status == 0)
2892159047fSniklas     return _print_insn_mips (memaddr, (unsigned long) bfd_getl32 (buffer), info);
2902159047fSniklas   else
2912159047fSniklas     {
2922159047fSniklas       (*info->memory_error_func) (status, memaddr, info);
2932159047fSniklas       return -1;
2942159047fSniklas     }
2952159047fSniklas }
296