1 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
2 Copyright 1989, 91, 92, 93, 94, 95, 96, 1997 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 info
->bytes_per_chunk
= 4;
259 info
->display_endian
= info
->endian
;
261 op
= mips_hash
[(word
>> OP_SH_OP
) & OP_MASK_OP
];
264 for (; op
< &mips_opcodes
[NUMOPCODES
]; op
++)
266 if (op
->pinfo
!= INSN_MACRO
&& (word
& op
->mask
) == op
->match
)
268 register const char *d
;
270 (*info
->fprintf_func
) (info
->stream
, "%s", op
->name
);
273 if (d
!= NULL
&& *d
!= '\0')
275 (*info
->fprintf_func
) (info
->stream
, "\t");
276 for (; *d
!= '\0'; d
++)
277 print_insn_arg (d
, word
, memaddr
, info
);
285 /* Handle undefined instructions. */
286 (*info
->fprintf_func
) (info
->stream
, "0x%x", word
);
291 print_insn_big_mips (memaddr
, info
)
293 struct disassemble_info
*info
;
299 || (info
->flavour
== bfd_target_elf_flavour
300 && info
->symbol
!= NULL
301 && (((elf_symbol_type
*) info
->symbol
)->internal_elf_sym
.st_other
303 return print_insn_mips16 (memaddr
, info
);
305 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
307 return _print_insn_mips (memaddr
, (unsigned long) bfd_getb32 (buffer
),
311 (*info
->memory_error_func
) (status
, memaddr
, info
);
317 print_insn_little_mips (memaddr
, info
)
319 struct disassemble_info
*info
;
325 || (info
->flavour
== bfd_target_elf_flavour
326 && info
->symbol
!= NULL
327 && (((elf_symbol_type
*) info
->symbol
)->internal_elf_sym
.st_other
329 return print_insn_mips16 (memaddr
, info
);
331 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
333 return _print_insn_mips (memaddr
, (unsigned long) bfd_getl32 (buffer
),
337 (*info
->memory_error_func
) (status
, memaddr
, info
);
342 /* Disassemble mips16 instructions. */
345 print_insn_mips16 (memaddr
, info
)
347 struct disassemble_info
*info
;
355 const struct mips_opcode
*op
, *opend
;
357 info
->bytes_per_chunk
= 2;
358 info
->display_endian
= info
->endian
;
360 info
->insn_info_valid
= 1;
361 info
->branch_delay_insns
= 0;
363 info
->insn_type
= dis_nonbranch
;
367 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2, info
);
370 (*info
->memory_error_func
) (status
, memaddr
, info
);
376 if (info
->endian
== BFD_ENDIAN_BIG
)
377 insn
= bfd_getb16 (buffer
);
379 insn
= bfd_getl16 (buffer
);
381 /* Handle the extend opcode specially. */
383 if ((insn
& 0xf800) == 0xf000)
386 extend
= insn
& 0x7ff;
390 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2, info
);
393 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
394 (unsigned int) extend
);
395 (*info
->memory_error_func
) (status
, memaddr
, info
);
399 if (info
->endian
== BFD_ENDIAN_BIG
)
400 insn
= bfd_getb16 (buffer
);
402 insn
= bfd_getl16 (buffer
);
404 /* Check for an extend opcode followed by an extend opcode. */
405 if ((insn
& 0xf800) == 0xf000)
407 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
408 (unsigned int) extend
);
409 info
->insn_type
= dis_noninsn
;
416 /* FIXME: Should probably use a hash table on the major opcode here. */
418 opend
= mips16_opcodes
+ bfd_mips16_num_opcodes
;
419 for (op
= mips16_opcodes
; op
< opend
; op
++)
421 if (op
->pinfo
!= INSN_MACRO
&& (insn
& op
->mask
) == op
->match
)
425 if (strchr (op
->args
, 'a') != NULL
)
429 (*info
->fprintf_func
) (info
->stream
, "extend 0x%x",
430 (unsigned int) extend
);
431 info
->insn_type
= dis_noninsn
;
439 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 2,
444 if (info
->endian
== BFD_ENDIAN_BIG
)
445 extend
= bfd_getb16 (buffer
);
447 extend
= bfd_getl16 (buffer
);
452 (*info
->fprintf_func
) (info
->stream
, "%s", op
->name
);
453 if (op
->args
[0] != '\0')
454 (*info
->fprintf_func
) (info
->stream
, "\t");
456 for (s
= op
->args
; *s
!= '\0'; s
++)
460 && (((insn
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
)
461 == ((insn
>> MIPS16OP_SH_RY
) & MIPS16OP_MASK_RY
)))
463 /* Skip the register and the comma. */
469 && (((insn
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
)
470 == ((insn
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
)))
472 /* Skip the register and the comma. */
476 print_mips16_insn_arg (*s
, op
, insn
, use_extend
, extend
, memaddr
,
480 if ((op
->pinfo
& INSN_UNCOND_BRANCH_DELAY
) != 0)
482 info
->branch_delay_insns
= 1;
483 if (info
->insn_type
!= dis_jsr
)
484 info
->insn_type
= dis_branch
;
492 (*info
->fprintf_func
) (info
->stream
, "0x%x", extend
| 0xf000);
493 (*info
->fprintf_func
) (info
->stream
, "0x%x", insn
);
494 info
->insn_type
= dis_noninsn
;
499 /* Disassemble an operand for a mips16 instruction. */
502 print_mips16_insn_arg (type
, op
, l
, use_extend
, extend
, memaddr
, info
)
504 const struct mips_opcode
*op
;
509 struct disassemble_info
*info
;
516 (*info
->fprintf_func
) (info
->stream
, "%c", type
);
521 (*info
->fprintf_func
) (info
->stream
, "$%s",
522 mips16_reg_names
[((l
>> MIPS16OP_SH_RY
)
523 & MIPS16OP_MASK_RY
)]);
528 (*info
->fprintf_func
) (info
->stream
, "$%s",
529 mips16_reg_names
[((l
>> MIPS16OP_SH_RX
)
530 & MIPS16OP_MASK_RX
)]);
534 (*info
->fprintf_func
) (info
->stream
, "$%s",
535 mips16_reg_names
[((l
>> MIPS16OP_SH_RZ
)
536 & MIPS16OP_MASK_RZ
)]);
540 (*info
->fprintf_func
) (info
->stream
, "$%s",
541 mips16_reg_names
[((l
>> MIPS16OP_SH_MOVE32Z
)
542 & MIPS16OP_MASK_MOVE32Z
)]);
546 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[0]);
550 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[29]);
554 (*info
->fprintf_func
) (info
->stream
, "$pc");
558 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[31]);
562 (*info
->fprintf_func
) (info
->stream
, "$%s",
563 reg_names
[((l
>> MIPS16OP_SH_REGR32
)
564 & MIPS16OP_MASK_REGR32
)]);
568 (*info
->fprintf_func
) (info
->stream
, "$%s",
569 reg_names
[MIPS16OP_EXTRACT_REG32R (l
)]);
595 int immed
, nbits
, shift
, signedp
, extbits
, pcrel
, extu
, branch
;
607 immed
= (l
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
;
613 immed
= (l
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
;
619 immed
= (l
>> MIPS16OP_SH_RZ
) & MIPS16OP_MASK_RZ
;
625 immed
= (l
>> MIPS16OP_SH_RX
) & MIPS16OP_MASK_RX
;
631 immed
= (l
>> MIPS16OP_SH_IMM4
) & MIPS16OP_MASK_IMM4
;
637 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
638 info
->insn_type
= dis_dref
;
644 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
645 info
->insn_type
= dis_dref
;
651 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
652 if ((op
->pinfo
& MIPS16_INSN_READ_PC
) == 0
653 && (op
->pinfo
& MIPS16_INSN_READ_SP
) == 0)
655 info
->insn_type
= dis_dref
;
662 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
663 info
->insn_type
= dis_dref
;
668 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
673 immed
= (l
>> MIPS16OP_SH_IMM6
) & MIPS16OP_MASK_IMM6
;
677 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
682 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
683 /* FIXME: This might be lw, or it might be addiu to $sp or
684 $pc. We assume it's load. */
685 info
->insn_type
= dis_dref
;
691 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
692 info
->insn_type
= dis_dref
;
697 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
702 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
708 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
713 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
717 info
->insn_type
= dis_condbranch
;
721 immed
= (l
>> MIPS16OP_SH_IMM11
) & MIPS16OP_MASK_IMM11
;
725 info
->insn_type
= dis_branch
;
730 immed
= (l
>> MIPS16OP_SH_IMM8
) & MIPS16OP_MASK_IMM8
;
732 /* FIXME: This can be lw or la. We assume it is lw. */
733 info
->insn_type
= dis_dref
;
739 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
741 info
->insn_type
= dis_dref
;
747 immed
= (l
>> MIPS16OP_SH_IMM5
) & MIPS16OP_MASK_IMM5
;
756 if (signedp
&& immed
>= (1 << (nbits
- 1)))
759 if ((type
== '<' || type
== '>' || type
== '[' || type
== '[')
766 immed
|= ((extend
& 0x1f) << 11) | (extend
& 0x7e0);
767 else if (extbits
== 15)
768 immed
|= ((extend
& 0xf) << 11) | (extend
& 0x7f0);
770 immed
= ((extend
>> 6) & 0x1f) | (extend
& 0x20);
771 immed
&= (1 << extbits
) - 1;
772 if (! extu
&& immed
>= (1 << (extbits
- 1)))
773 immed
-= 1 << extbits
;
777 (*info
->fprintf_func
) (info
->stream
, "%d", immed
);
786 baseaddr
= memaddr
+ 2;
797 /* If this instruction is in the delay slot of a jr
798 instruction, the base address is the address of the
799 jr instruction. If it is in the delay slot of jalr
800 instruction, the base address is the address of the
801 jalr instruction. This test is unreliable: we have
802 no way of knowing whether the previous word is
803 instruction or data. */
804 status
= (*info
->read_memory_func
) (memaddr
- 4, buffer
, 2,
807 && (((info
->endian
== BFD_ENDIAN_BIG
808 ? bfd_getb16 (buffer
)
809 : bfd_getl16 (buffer
))
810 & 0xf800) == 0x1800))
811 baseaddr
= memaddr
- 4;
814 status
= (*info
->read_memory_func
) (memaddr
- 2, buffer
,
817 && (((info
->endian
== BFD_ENDIAN_BIG
818 ? bfd_getb16 (buffer
)
819 : bfd_getl16 (buffer
))
820 & 0xf81f) == 0xe800))
821 baseaddr
= memaddr
- 2;
824 val
= (baseaddr
& ~ ((1 << shift
) - 1)) + immed
;
825 (*info
->print_address_func
) (val
, info
);
834 l
= ((l
& 0x1f) << 23) | ((l
& 0x3e0) << 13) | (extend
<< 2);
835 (*info
->print_address_func
) ((memaddr
& 0xf0000000) | l
, info
);
836 info
->insn_type
= dis_jsr
;
837 info
->target
= (memaddr
& 0xf0000000) | l
;
838 info
->branch_delay_insns
= 1;
844 int need_comma
, amask
, smask
;
848 l
= (l
>> MIPS16OP_SH_IMM6
) & MIPS16OP_MASK_IMM6
;
850 amask
= (l
>> 3) & 7;
852 if (amask
> 0 && amask
< 5)
854 (*info
->fprintf_func
) (info
->stream
, "$%s", reg_names
[4]);
856 (*info
->fprintf_func
) (info
->stream
, "-$%s",
857 reg_names
[amask
+ 3]);
861 smask
= (l
>> 1) & 3;
864 (*info
->fprintf_func
) (info
->stream
, "%s??",
865 need_comma
? "," : "");
870 (*info
->fprintf_func
) (info
->stream
, "%s$%s",
871 need_comma
? "," : "",
874 (*info
->fprintf_func
) (info
->stream
, "-$%s",
875 reg_names
[smask
+ 15]);
881 (*info
->fprintf_func
) (info
->stream
, "%s$%s",
882 need_comma
? "," : "",
887 if (amask
== 5 || amask
== 6)
889 (*info
->fprintf_func
) (info
->stream
, "%s$f0",
890 need_comma
? "," : "");
892 (*info
->fprintf_func
) (info
->stream
, "-$f1");
This page took 0.064236 seconds and 4 git commands to generate.