745b6bfb61e4dfc4d8aa16ffa89198fd5bf266a3
1 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
2 Copyright 1989, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
3 Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
5 This file is part of GDB, GAS, and the GNU binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include "opcode/mips.h"
26 /* FIXME: These are needed to figure out if this is a mips16 symbol or
27 not. It would be better to think of a cleaner way to do this. */
31 static int print_insn_mips16
PARAMS ((bfd_vma
, struct disassemble_info
*));
32 static void print_mips16_insn_arg
33 PARAMS ((int, const struct mips_opcode
*, int, boolean
, int, bfd_vma
,
34 struct disassemble_info
*));
36 /* Mips instructions are never longer than this many bytes. */
39 static void print_insn_arg
PARAMS ((const char *, unsigned long, bfd_vma
,
40 struct disassemble_info
*));
41 static int _print_insn_mips
PARAMS ((bfd_vma
, unsigned long int,
42 struct disassemble_info
*));
45 /* FIXME: This should be shared with gdb somehow. */
46 #define REGISTER_NAMES \
47 { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \
48 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \
49 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
50 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \
51 "sr", "lo", "hi", "bad", "cause","pc", \
52 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
53 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
54 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\
55 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\
56 "fsr", "fir", "fp", "inx", "rand", "tlblo","ctxt", "tlbhi",\
60 static CONST
char * CONST reg_names
[] = REGISTER_NAMES
;
62 /* The mips16 register names. */
63 static const char * const mips16_reg_names
[] =
65 "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
70 print_insn_arg (d
, l
, pc
, info
)
72 register unsigned long int l
;
74 struct disassemble_info
*info
;
83 (*info
->fprintf_func
) (info
->stream
, "%c", *d
);
90 (*info
->fprintf_func
) (info
->stream
, "$%s",
91 reg_names
[(l
>> OP_SH_RS
) & OP_MASK_RS
]);
96 (*info
->fprintf_func
) (info
->stream
, "$%s",
97 reg_names
[(l
>> OP_SH_RT
) & OP_MASK_RT
]);
102 (*info
->fprintf_func
) (info
->stream
, "0x%x",
103 (l
>> OP_SH_IMMEDIATE
) & OP_MASK_IMMEDIATE
);
106 case 'j': /* same as i, but sign-extended */
108 delta
= (l
>> OP_SH_DELTA
) & OP_MASK_DELTA
;
111 (*info
->fprintf_func
) (info
->stream
, "%d",
116 (*info
->fprintf_func
) (info
->stream
, "0x%x",
117 (unsigned int) ((l
>> OP_SH_PREFX
)
122 (*info
->fprintf_func
) (info
->stream
, "0x%x",
123 (unsigned int) ((l
>> OP_SH_CACHE
)
128 (*info
->print_address_func
)
129 (((pc
& 0xF0000000) | (((l
>> OP_SH_TARGET
) & OP_MASK_TARGET
) << 2)),
134 /* sign extend the displacement */
135 delta
= (l
>> OP_SH_DELTA
) & OP_MASK_DELTA
;
138 (*info
->print_address_func
)
139 ((delta
<< 2) + pc
+ 4,
144 (*info
->fprintf_func
) (info
->stream
, "$%s",
145 reg_names
[(l
>> OP_SH_RD
) & OP_MASK_RD
]);
149 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[0]);
153 (*info
->fprintf_func
) (info
->stream
, "0x%x",
154 (l
>> OP_SH_SHAMT
) & OP_MASK_SHAMT
);
158 (*info
->fprintf_func
) (info
->stream
, "0x%x",
159 (l
>> OP_SH_CODE
) & OP_MASK_CODE
);
163 (*info
->fprintf_func
) (info
->stream
, "0x%x",
164 (l
>> OP_SH_COPZ
) & OP_MASK_COPZ
);
168 (*info
->fprintf_func
) (info
->stream
, "0x%x",
169 (l
>> OP_SH_SYSCALL
) & OP_MASK_SYSCALL
);
174 (*info
->fprintf_func
) (info
->stream
, "$f%d",
175 (l
>> OP_SH_FS
) & OP_MASK_FS
);
180 (*info
->fprintf_func
) (info
->stream
, "$f%d",
181 (l
>> OP_SH_FT
) & OP_MASK_FT
);
185 (*info
->fprintf_func
) (info
->stream
, "$f%d",
186 (l
>> OP_SH_FD
) & OP_MASK_FD
);
190 (*info
->fprintf_func
) (info
->stream
, "$f%d",
191 (l
>> OP_SH_FR
) & OP_MASK_FR
);
195 (*info
->fprintf_func
) (info
->stream
, "$%d",
196 (l
>> OP_SH_RT
) & OP_MASK_RT
);
200 (*info
->fprintf_func
) (info
->stream
, "$%d",
201 (l
>> OP_SH_RD
) & OP_MASK_RD
);
205 (*info
->fprintf_func
) (info
->stream
, "$fcc%d",
206 (l
>> OP_SH_BCC
) & OP_MASK_BCC
);
210 (*info
->fprintf_func
) (info
->stream
, "$fcc%d",
211 (l
>> OP_SH_CCC
) & OP_MASK_CCC
);
215 (*info
->fprintf_func
) (info
->stream
,
216 "# internal error, undefined modifier(%c)", *d
);
221 /* Print the mips instruction at address MEMADDR in debugged memory,
222 on using INFO. Returns length of the instruction, in bytes, which is
223 always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
224 this is little-endian code. */
227 _print_insn_mips (memaddr
, word
, info
)
229 unsigned long int word
;
230 struct disassemble_info
*info
;
232 register const struct mips_opcode
*op
;
233 static boolean init
= 0;
234 static const struct mips_opcode
*mips_hash
[OP_MASK_OP
+ 1];
236 /* Build a hash table to shorten the search time. */
241 for (i
= 0; i
<= OP_MASK_OP
; i
++)
243 for (op
= mips_opcodes
; op
< &mips_opcodes
[NUMOPCODES
]; op
++)
245 if (op
->pinfo
== INSN_MACRO
)
247 if (i
== ((op
->match
>> OP_SH_OP
) & OP_MASK_OP
))
258 op
= mips_hash
[(word
>> OP_SH_OP
) & OP_MASK_OP
];
261 for (; op
< &mips_opcodes
[NUMOPCODES
]; op
++)
263 if (op
->pinfo
!= INSN_MACRO
&& (word
& op
->mask
) == op
->match
)
265 register const char *d
;
267 (*info
->fprintf_func
) (info
->stream
, "%s", op
->name
);
270 if (d
!= NULL
&& *d
!= '\0')
272 (*info
->fprintf_func
) (info
->stream
, "\t");
273 for (; *d
!= '\0'; d
++)
274 print_insn_arg (d
, word
, memaddr
, info
);
282 /* Handle undefined instructions. */
283 (*info
->fprintf_func
) (info
->stream
, "0x%x", word
);
288 print_insn_big_mips (memaddr
, info
)
290 struct disassemble_info
*info
;
296 || (info
->flavour
== bfd_target_elf_flavour
297 && info
->symbol
!= NULL
298 && (((elf_symbol_type
*) info
->symbol
)->internal_elf_sym
.st_other
300 return print_insn_mips16 (memaddr
, info
);
302 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
304 return _print_insn_mips (memaddr
, (unsigned long) bfd_getb32 (buffer
),
308 (*info
->memory_error_func
) (status
, memaddr
, info
);
314 print_insn_little_mips (memaddr
, info
)
316 struct disassemble_info
*info
;
322 || (info
->flavour
== bfd_target_elf_flavour
323 && info
->symbol
!= NULL
324 && (((elf_symbol_type
*) info
->symbol
)->internal_elf_sym
.st_other
326 return print_insn_mips16 (memaddr
, info
);
328 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
330 return _print_insn_mips (memaddr
, (unsigned long) bfd_getl32 (buffer
),
334 (*info
->memory_error_func
) (status
, memaddr
, info
);
339 /* Disassemble mips16 instructions. */
342 print_insn_mips16 (memaddr
, info
)
344 struct disassemble_info
*info
;
352 const struct mips_opcode
*op
, *opend
;
354 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2, info
);
357 (*info
->memory_error_func
) (status
, memaddr
, info
);
363 if (info
->endian
== BFD_ENDIAN_BIG
)
364 insn
= bfd_getb16 (buffer
);
366 insn
= bfd_getl16 (buffer
);
368 /* Handle the extend opcode specially. */
370 if ((insn
& 0xf800) == 0xf000)
373 extend
= insn
& 0x7ff;
377 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2, info
);
380 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
381 (unsigned int) extend
);
382 (*info
->memory_error_func
) (status
, memaddr
, info
);
386 if (info
->endian
== BFD_ENDIAN_BIG
)
387 insn
= bfd_getb16 (buffer
);
389 insn
= bfd_getl16 (buffer
);
391 /* Check for an extend opcode followed by an extend opcode. */
392 if ((insn
& 0xf800) == 0xf000)
394 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
395 (unsigned int) extend
);
402 /* FIXME: Should probably use a hash table on the major opcode here. */
404 opend
= mips16_opcodes
+ bfd_mips16_num_opcodes
;
405 for (op
= mips16_opcodes
; op
< opend
; op
++)
407 if (op
->pinfo
!= INSN_MACRO
&& (insn
& op
->mask
) == op
->match
)
411 if (strchr (op
->args
, 'a') != NULL
)
415 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
416 (unsigned int) extend
);
424 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2,
429 if (info
->endian
== BFD_ENDIAN_BIG
)
430 extend
= bfd_getb16 (buffer
);
432 extend
= bfd_getl16 (buffer
);
437 (*info
->fprintf_func
) (info
->stream
, "%s", op
->name
);
438 if (op
->args
[0] != '\0')
439 (*info
->fprintf_func
) (info
->stream
, "\t");
441 for (s
= op
->args
; *s
!= '\0'; s
++)
445 && (((insn
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
)
446 == ((insn
>> MIPS16OP_SH_RY
) & MIPS16OP_MASK_RY
)))
448 /* Skip the register and the comma. */
454 && (((insn
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
)
455 == ((insn
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
)))
457 /* Skip the register and the comma. */
461 print_mips16_insn_arg (*s
, op
, insn
, use_extend
, extend
, memaddr
,
470 (*info
->fprintf_func
) (info
->stream
, "0x%x", extend
| 0xf000);
471 (*info
->fprintf_func
) (info
->stream
, "0x%x", insn
);
476 /* Disassemble an operand for a mips16 instruction. */
479 print_mips16_insn_arg (type
, op
, l
, use_extend
, extend
, memaddr
, info
)
481 const struct mips_opcode
*op
;
486 struct disassemble_info
*info
;
493 (*info
->fprintf_func
) (info
->stream
, "%c", type
);
498 (*info
->fprintf_func
) (info
->stream
, "$%s",
499 mips16_reg_names
[((l
>> MIPS16OP_SH_RY
)
500 & MIPS16OP_MASK_RY
)]);
505 (*info
->fprintf_func
) (info
->stream
, "$%s",
506 mips16_reg_names
[((l
>> MIPS16OP_SH_RX
)
507 & MIPS16OP_MASK_RX
)]);
511 (*info
->fprintf_func
) (info
->stream
, "$%s",
512 mips16_reg_names
[((l
>> MIPS16OP_SH_RZ
)
513 & MIPS16OP_MASK_RZ
)]);
517 (*info
->fprintf_func
) (info
->stream
, "$%s",
518 mips16_reg_names
[((l
>> MIPS16OP_SH_MOVE32Z
)
519 & MIPS16OP_MASK_MOVE32Z
)]);
523 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[0]);
527 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[29]);
531 (*info
->fprintf_func
) (info
->stream
, "$pc");
535 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[31]);
539 (*info
->fprintf_func
) (info
->stream
, "$%s",
540 reg_names
[((l
>> MIPS16OP_SH_REGR32
)
541 & MIPS16OP_MASK_REGR32
)]);
545 (*info
->fprintf_func
) (info
->stream
, "$%s",
546 reg_names
[MIPS16OP_EXTRACT_REG32R (l
)]);
572 int immed
, nbits
, shift
, signedp
, extbits
, pcrel
, extu
, branch
;
584 immed
= (l
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
;
590 immed
= (l
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
;
596 immed
= (l
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
;
602 immed
= (l
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
;
608 immed
= (l
>> MIPS16OP_SH_IMM4
) & MIPS16OP_MASK_IMM4
;
614 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
619 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
624 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
629 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
633 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
638 immed
= (l
>> MIPS16OP_SH_IMM6
) & MIPS16OP_MASK_IMM6
;
642 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
647 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
652 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
656 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
661 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
667 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
672 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
679 immed
= (l
>> MIPS16OP_SH_IMM11
) & MIPS16OP_MASK_IMM11
;
687 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
693 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
699 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
708 if (signedp
&& immed
>= (1 << (nbits
- 1)))
711 if ((type
== '<' || type
== '>' || type
== '[' || type
== '[')
718 immed
|= ((extend
& 0x1f) << 11) | (extend
& 0x7e0);
719 else if (extbits
== 15)
720 immed
|= ((extend
& 0xf) << 11) | (extend
& 0x7f0);
722 immed
= ((extend
>> 6) & 0x1f) | (extend
& 0x20);
723 immed
&= (1 << extbits
) - 1;
724 if (! extu
&& immed
>= (1 << (extbits
- 1)))
725 immed
-= 1 << extbits
;
729 (*info
->fprintf_func
) (info
->stream
, "%d", immed
);
738 baseaddr
= memaddr
+ 2;
749 /* If this instruction is in the delay slot of a jr
750 instruction, the base address is the address of the
751 jr instruction. If it is in the delay slot of jalr
752 instruction, the base address is the address of the
753 jalr instruction. This test is unreliable: we have
754 no way of knowing whether the previous word is
755 instruction or data. */
756 status
= (*info
->read_memory_func
) (memaddr
- 4, buffer
, 2,
759 && (((info
->endian
== BFD_ENDIAN_BIG
760 ? bfd_getb16 (buffer
)
761 : bfd_getl16 (buffer
))
762 & 0xf800) == 0x1800))
763 baseaddr
= memaddr
- 4;
766 status
= (*info
->read_memory_func
) (memaddr
- 2, buffer
,
769 && (((info
->endian
== BFD_ENDIAN_BIG
770 ? bfd_getb16 (buffer
)
771 : bfd_getl16 (buffer
))
772 & 0xf81f) == 0xe800))
773 baseaddr
= memaddr
- 2;
776 val
= (baseaddr
& ~ ((1 << shift
) - 1)) + immed
;
777 (*info
->print_address_func
) (val
, info
);
785 l
= ((l
& 0x1f) << 23) | ((l
& 0x3e0) << 13) | (extend
<< 2);
786 (*info
->print_address_func
) ((memaddr
& 0xf0000000) | l
, info
);
792 int need_comma
, amask
, smask
;
796 l
= (l
>> MIPS16OP_SH_IMM6
) & MIPS16OP_MASK_IMM6
;
798 amask
= (l
>> 3) & 7;
799 if (amask
== 5 || amask
== 6)
801 (*info
->fprintf_func
) (info
->stream
, "??");
804 else if (amask
> 0 && amask
< 7)
806 (*info
->fprintf_func
) (info
->stream
, "%s", reg_names
[4]);
808 (*info
->fprintf_func
) (info
->stream
, "-%s",
809 reg_names
[amask
+ 3]);
813 smask
= (l
>> 1) & 3;
816 (*info
->fprintf_func
) (info
->stream
, "%s??",
817 need_comma
? "," : "");
822 (*info
->fprintf_func
) (info
->stream
, "%s%s",
823 need_comma
? "," : "",
826 (*info
->fprintf_func
) (info
->stream
, "-%s",
827 reg_names
[smask
+ 15]);
832 (*info
->fprintf_func
) (info
->stream
, "%s%s",
833 need_comma
? "," : "",
This page took 0.087551 seconds and 4 git commands to generate.