]>
Commit | Line | Data |
---|---|---|
d0ba1cea ILT |
1 | /* Print mips instructions for GDB, the GNU debugger, or for objdump. |
2 | Copyright 1989, 1991, 1992 Free Software Foundation, Inc. | |
3 | Contributed by Nobuyuki Hikichi([email protected]). | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
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. | |
11 | ||
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. | |
16 | ||
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., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
5d0734a7 | 21 | #include <ansidecl.h> |
d0ba1cea | 22 | #include "sysdep.h" |
5d0734a7 | 23 | #include "dis-asm.h" |
d0ba1cea ILT |
24 | #include "opcode/mips.h" |
25 | ||
26 | /* FIXME: we need direct access to the swapping functions. */ | |
27 | #include "libbfd.h" | |
28 | ||
d0ba1cea ILT |
29 | /* Mips instructions are never longer than this many bytes. */ |
30 | #define MAXLEN 4 | |
d0ba1cea ILT |
31 | \f |
32 | /* FIXME: This should be shared with gdb somehow. */ | |
33 | #define REGISTER_NAMES \ | |
34 | { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ | |
35 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ | |
36 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ | |
37 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ | |
38 | "sr", "lo", "hi", "bad", "cause","pc", \ | |
39 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ | |
40 | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ | |
41 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\ | |
42 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\ | |
43 | "fsr", "fir", "fp", "inx", "rand", "tlblo","ctxt", "tlbhi",\ | |
44 | "epc", "prid"\ | |
45 | } | |
46 | ||
47 | static CONST char * CONST reg_names[] = REGISTER_NAMES; | |
48 | \f | |
49 | /* subroutine */ | |
5d0734a7 JK |
50 | static void |
51 | print_insn_arg (d, l, pc, info) | |
547998d2 | 52 | const char *d; |
5d0734a7 | 53 | register unsigned long int l; |
d0ba1cea | 54 | bfd_vma pc; |
5d0734a7 | 55 | struct disassemble_info *info; |
d0ba1cea | 56 | { |
fde326fb ILT |
57 | int delta; |
58 | ||
d0ba1cea ILT |
59 | switch (*d) |
60 | { | |
61 | case ',': | |
62 | case '(': | |
63 | case ')': | |
5d0734a7 | 64 | (*info->fprintf_func) (info->stream, "%c", *d); |
d0ba1cea ILT |
65 | break; |
66 | ||
67 | case 's': | |
fde326fb ILT |
68 | case 'b': |
69 | case 'r': | |
70 | case 'v': | |
5d0734a7 JK |
71 | (*info->fprintf_func) (info->stream, "$%s", |
72 | reg_names[(l >> OP_SH_RS) & OP_MASK_RS]); | |
d0ba1cea ILT |
73 | break; |
74 | ||
75 | case 't': | |
fde326fb | 76 | case 'w': |
5d0734a7 JK |
77 | (*info->fprintf_func) (info->stream, "$%s", |
78 | reg_names[(l >> OP_SH_RT) & OP_MASK_RT]); | |
d0ba1cea ILT |
79 | break; |
80 | ||
81 | case 'i': | |
fde326fb | 82 | case 'u': |
5d0734a7 JK |
83 | (*info->fprintf_func) (info->stream, "%d", |
84 | (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); | |
d0ba1cea ILT |
85 | break; |
86 | ||
87 | case 'j': /* same as i, but sign-extended */ | |
fde326fb ILT |
88 | case 'o': |
89 | delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; | |
90 | if (delta & 0x8000) | |
91 | delta |= ~0xffff; | |
5d0734a7 | 92 | (*info->fprintf_func) (info->stream, "%d", |
fde326fb | 93 | delta); |
d0ba1cea ILT |
94 | break; |
95 | ||
96 | case 'a': | |
fde326fb ILT |
97 | (*info->print_address_func) |
98 | (((pc & 0xF0000000) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)), | |
99 | info); | |
d0ba1cea ILT |
100 | break; |
101 | ||
fde326fb ILT |
102 | case 'p': |
103 | /* sign extend the displacement */ | |
104 | delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; | |
105 | if (delta & 0x8000) | |
106 | delta |= ~0xffff; | |
107 | (*info->print_address_func) | |
108 | ((delta << 2) + pc + 4, | |
109 | info); | |
d0ba1cea ILT |
110 | break; |
111 | ||
112 | case 'd': | |
5d0734a7 JK |
113 | (*info->fprintf_func) (info->stream, "$%s", |
114 | reg_names[(l >> OP_SH_RD) & OP_MASK_RD]); | |
d0ba1cea ILT |
115 | break; |
116 | ||
547998d2 ILT |
117 | case 'z': |
118 | (*info->fprintf_func) (info->stream, "$%s", reg_names[0]); | |
119 | break; | |
120 | ||
fde326fb | 121 | case '<': |
5d0734a7 JK |
122 | (*info->fprintf_func) (info->stream, "0x%x", |
123 | (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); | |
d0ba1cea ILT |
124 | break; |
125 | ||
fde326fb | 126 | case 'c': |
5d0734a7 JK |
127 | (*info->fprintf_func) (info->stream, "0x%x", |
128 | (l >> OP_SH_CODE) & OP_MASK_CODE); | |
d0ba1cea ILT |
129 | break; |
130 | ||
fde326fb ILT |
131 | case 'C': |
132 | (*info->fprintf_func) (info->stream, "0x%x", | |
133 | (l >> OP_SH_COPZ) & OP_MASK_COPZ); | |
134 | break; | |
135 | ||
136 | case 'B': | |
137 | (*info->fprintf_func) (info->stream, "0x%x", | |
138 | (l >> OP_SH_SYSCALL) & OP_MASK_SYSCALL); | |
139 | break; | |
140 | ||
d0ba1cea | 141 | case 'S': |
fde326fb | 142 | case 'V': |
5d0734a7 JK |
143 | (*info->fprintf_func) (info->stream, "$f%d", |
144 | (l >> OP_SH_FS) & OP_MASK_FS); | |
d0ba1cea ILT |
145 | break; |
146 | ||
147 | case 'T': | |
fde326fb | 148 | case 'W': |
5d0734a7 JK |
149 | (*info->fprintf_func) (info->stream, "$f%d", |
150 | (l >> OP_SH_FT) & OP_MASK_FT); | |
d0ba1cea ILT |
151 | break; |
152 | ||
153 | case 'D': | |
5d0734a7 JK |
154 | (*info->fprintf_func) (info->stream, "$f%d", |
155 | (l >> OP_SH_FD) & OP_MASK_FD); | |
d0ba1cea ILT |
156 | break; |
157 | ||
fde326fb ILT |
158 | case 'E': |
159 | (*info->fprintf_func) (info->stream, "$%d", | |
160 | (l >> OP_SH_RT) & OP_MASK_RT); | |
161 | break; | |
162 | ||
163 | case 'G': | |
164 | (*info->fprintf_func) (info->stream, "$%d", | |
165 | (l >> OP_SH_RD) & OP_MASK_RD); | |
166 | break; | |
167 | ||
d0ba1cea | 168 | default: |
5d0734a7 JK |
169 | (*info->fprintf_func) (info->stream, |
170 | "# internal error, undefined modifier(%c)", *d); | |
d0ba1cea ILT |
171 | break; |
172 | } | |
173 | } | |
174 | \f | |
175 | /* Print the mips instruction at address MEMADDR in debugged memory, | |
5d0734a7 | 176 | on using INFO. Returns length of the instruction, in bytes, which is |
d0ba1cea ILT |
177 | always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if |
178 | this is little-endian code. */ | |
179 | ||
180 | int | |
5d0734a7 | 181 | _print_insn_mips (memaddr, word, info) |
d0ba1cea | 182 | bfd_vma memaddr; |
5d0734a7 JK |
183 | struct disassemble_info *info; |
184 | unsigned long int word; | |
d0ba1cea ILT |
185 | { |
186 | register int i; | |
547998d2 | 187 | register const char *d; |
d0ba1cea | 188 | |
fde326fb | 189 | for (i = 0; i < NUMOPCODES; i++) |
d0ba1cea | 190 | { |
fde326fb ILT |
191 | if (mips_opcodes[i].pinfo != INSN_MACRO) |
192 | { | |
193 | register unsigned int match = mips_opcodes[i].match; | |
194 | register unsigned int mask = mips_opcodes[i].mask; | |
195 | if ((word & mask) == match) | |
196 | break; | |
197 | } | |
d0ba1cea ILT |
198 | } |
199 | ||
200 | /* Handle undefined instructions. */ | |
fde326fb | 201 | if (i == NUMOPCODES) |
d0ba1cea | 202 | { |
5d0734a7 | 203 | (*info->fprintf_func) (info->stream, "0x%x", word); |
d0ba1cea ILT |
204 | return 4; |
205 | } | |
206 | ||
5d0734a7 | 207 | (*info->fprintf_func) (info->stream, "%s", mips_opcodes[i].name); |
d0ba1cea ILT |
208 | |
209 | if (!(d = mips_opcodes[i].args)) | |
210 | return 4; | |
211 | ||
5d0734a7 | 212 | (*info->fprintf_func) (info->stream, " "); |
d0ba1cea ILT |
213 | |
214 | while (*d) | |
5d0734a7 | 215 | print_insn_arg (d++, word, memaddr, info); |
d0ba1cea ILT |
216 | |
217 | return 4; | |
218 | } | |
5d0734a7 JK |
219 | |
220 | int | |
221 | print_insn_big_mips (memaddr, info) | |
222 | bfd_vma memaddr; | |
223 | struct disassemble_info *info; | |
224 | { | |
225 | bfd_byte buffer[4]; | |
226 | int status = (*info->read_memory_func) (memaddr, buffer, 4, info); | |
227 | if (status == 0) | |
228 | return _print_insn_mips (memaddr, _do_getb32 (buffer), info); | |
229 | else | |
230 | { | |
231 | (*info->memory_error_func) (status, memaddr, info); | |
232 | return -1; | |
233 | } | |
234 | } | |
235 | ||
236 | int | |
237 | print_insn_little_mips (memaddr, info) | |
238 | bfd_vma memaddr; | |
239 | struct disassemble_info *info; | |
240 | { | |
241 | bfd_byte buffer[4]; | |
242 | int status = (*info->read_memory_func) (memaddr, buffer, 4, info); | |
243 | if (status == 0) | |
244 | return _print_insn_mips (memaddr, _do_getl32 (buffer), info); | |
245 | else | |
246 | { | |
247 | (*info->memory_error_func) (status, memaddr, info); | |
248 | return -1; | |
249 | } | |
250 | } |