Commit | Line | Data |
---|---|---|
e0001a05 NC |
1 | /* xtensa-dis.c. Disassembly functions for Xtensa. |
2 | Copyright 2003 Free Software Foundation, Inc. | |
3 | Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) | |
4 | ||
5 | This file is part of GDB, GAS, and the GNU binutils. | |
6 | ||
7 | GDB, GAS, and the GNU binutils are free software; you can redistribute | |
8 | them and/or modify them under the terms of the GNU General Public | |
9 | License as published by the Free Software Foundation; either version 2, | |
10 | or (at your option) any later version. | |
11 | ||
12 | GDB, GAS, and the GNU binutils are distributed in the hope that they | |
13 | will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
14 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
15 | the GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this file; see the file COPYING. If not, write to the Free | |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
20 | USA. */ | |
21 | ||
22 | #include <stdlib.h> | |
23 | #include <stdio.h> | |
24 | #include <sys/types.h> | |
25 | #include <string.h> | |
26 | #include "xtensa-isa.h" | |
27 | #include "ansidecl.h" | |
28 | #include "sysdep.h" | |
29 | #include "dis-asm.h" | |
30 | ||
31 | #include <setjmp.h> | |
32 | ||
33 | #ifndef MAX | |
34 | #define MAX(a,b) (a > b ? a : b) | |
35 | #endif | |
36 | ||
37 | static char* state_names[256] = | |
38 | { | |
39 | "lbeg", /* 0 */ | |
40 | "lend", /* 1 */ | |
41 | "lcount", /* 2 */ | |
42 | "sar", /* 3 */ | |
43 | "br", /* 4 */ | |
44 | ||
45 | "reserved_5", /* 5 */ | |
46 | "reserved_6", /* 6 */ | |
47 | "reserved_7", /* 7 */ | |
48 | ||
49 | "av", /* 8 */ | |
50 | "avh", /* 9 */ | |
51 | "bv", /* 10 */ | |
52 | "sav", /* 11 */ | |
53 | "scompare1", /* 12 */ | |
54 | ||
55 | "reserved_13", /* 13 */ | |
56 | "reserved_14", /* 14 */ | |
57 | "reserved_15", /* 15 */ | |
58 | ||
59 | "acclo", /* 16 */ | |
60 | "acchi", /* 17 */ | |
61 | ||
62 | "reserved_18", /* 18 */ | |
63 | "reserved_19", /* 19 */ | |
64 | "reserved_20", /* 20 */ | |
65 | "reserved_21", /* 21 */ | |
66 | "reserved_22", /* 22 */ | |
67 | "reserved_23", /* 23 */ | |
68 | "reserved_24", /* 24 */ | |
69 | "reserved_25", /* 25 */ | |
70 | "reserved_26", /* 26 */ | |
71 | "reserved_27", /* 27 */ | |
72 | "reserved_28", /* 28 */ | |
73 | "reserved_29", /* 29 */ | |
74 | "reserved_30", /* 30 */ | |
75 | "reserved_31", /* 31 */ | |
76 | ||
77 | "mr0", /* 32 */ | |
78 | "mr1", /* 33 */ | |
79 | "mr2", /* 34 */ | |
80 | "mr3", /* 35 */ | |
81 | ||
82 | "reserved_36", /* 36 */ | |
83 | "reserved_37", /* 37 */ | |
84 | "reserved_38", /* 38 */ | |
85 | "reserved_39", /* 39 */ | |
86 | "reserved_40", /* 40 */ | |
87 | "reserved_41", /* 41 */ | |
88 | "reserved_42", /* 42 */ | |
89 | "reserved_43", /* 43 */ | |
90 | "reserved_44", /* 44 */ | |
91 | "reserved_45", /* 45 */ | |
92 | "reserved_46", /* 46 */ | |
93 | "reserved_47", /* 47 */ | |
94 | "reserved_48", /* 48 */ | |
95 | "reserved_49", /* 49 */ | |
96 | "reserved_50", /* 50 */ | |
97 | "reserved_51", /* 51 */ | |
98 | "reserved_52", /* 52 */ | |
99 | "reserved_53", /* 53 */ | |
100 | "reserved_54", /* 54 */ | |
101 | "reserved_55", /* 55 */ | |
102 | "reserved_56", /* 56 */ | |
103 | "reserved_57", /* 57 */ | |
104 | "reserved_58", /* 58 */ | |
105 | "reserved_59", /* 59 */ | |
106 | "reserved_60", /* 60 */ | |
107 | "reserved_61", /* 61 */ | |
108 | "reserved_62", /* 62 */ | |
109 | "reserved_63", /* 63 */ | |
110 | ||
111 | "reserved_64", /* 64 */ | |
112 | "reserved_65", /* 65 */ | |
113 | "reserved_66", /* 66 */ | |
114 | "reserved_67", /* 67 */ | |
115 | "reserved_68", /* 68 */ | |
116 | "reserved_69", /* 69 */ | |
117 | "reserved_70", /* 70 */ | |
118 | "reserved_71", /* 71 */ | |
119 | ||
120 | "wb", /* 72 */ | |
121 | "ws", /* 73 */ | |
122 | ||
123 | "reserved_74", /* 74 */ | |
124 | "reserved_75", /* 75 */ | |
125 | "reserved_76", /* 76 */ | |
126 | "reserved_77", /* 77 */ | |
127 | "reserved_78", /* 78 */ | |
128 | "reserved_79", /* 79 */ | |
129 | "reserved_80", /* 80 */ | |
130 | "reserved_81", /* 81 */ | |
131 | "reserved_82", /* 82 */ | |
132 | ||
133 | "ptevaddr", /* 83 */ | |
134 | ||
135 | "reserved_84", /* 84 */ | |
136 | "reserved_85", /* 85 */ | |
137 | "reserved_86", /* 86 */ | |
138 | "reserved_87", /* 87 */ | |
139 | "reserved_88", /* 88 */ | |
140 | "reserved_89", /* 89 */ | |
141 | ||
142 | "rasid", /* 90 */ | |
143 | "itlbcfg", /* 91 */ | |
144 | "dtlbcfg", /* 92 */ | |
145 | ||
146 | "reserved_93", /* 93 */ | |
147 | "reserved_94", /* 94 */ | |
148 | "reserved_95", /* 95 */ | |
149 | ||
150 | "ibreakenable", /* 96 */ | |
151 | ||
152 | "reserved_97", /* 97 */ | |
153 | ||
154 | "cacheattr", /* 98 */ | |
155 | ||
156 | "reserved_99", /* 99 */ | |
157 | "reserved_100", /* 100 */ | |
158 | "reserved_101", /* 101 */ | |
159 | "reserved_102", /* 102 */ | |
160 | "reserved_103", /* 103 */ | |
161 | ||
162 | "ddr", /* 104 */ | |
163 | ||
164 | "reserved_105", /* 105 */ | |
165 | "reserved_106", /* 106 */ | |
166 | "reserved_107", /* 107 */ | |
167 | "reserved_108", /* 108 */ | |
168 | "reserved_109", /* 109 */ | |
169 | "reserved_110", /* 110 */ | |
170 | "reserved_111", /* 111 */ | |
171 | "reserved_112", /* 112 */ | |
172 | "reserved_113", /* 113 */ | |
173 | "reserved_114", /* 114 */ | |
174 | "reserved_115", /* 115 */ | |
175 | "reserved_116", /* 116 */ | |
176 | "reserved_117", /* 117 */ | |
177 | "reserved_118", /* 118 */ | |
178 | "reserved_119", /* 119 */ | |
179 | "reserved_120", /* 120 */ | |
180 | "reserved_121", /* 121 */ | |
181 | "reserved_122", /* 122 */ | |
182 | "reserved_123", /* 123 */ | |
183 | "reserved_124", /* 124 */ | |
184 | "reserved_125", /* 125 */ | |
185 | "reserved_126", /* 126 */ | |
186 | "reserved_127", /* 127 */ | |
187 | ||
188 | "ibreaka0", /* 128 */ | |
189 | "ibreaka1", /* 129 */ | |
190 | "ibreaka2", /* 130 */ | |
191 | "ibreaka3", /* 131 */ | |
192 | "ibreaka4", /* 132 */ | |
193 | "ibreaka5", /* 133 */ | |
194 | "ibreaka6", /* 134 */ | |
195 | "ibreaka7", /* 135 */ | |
196 | "ibreaka8", /* 136 */ | |
197 | "ibreaka9", /* 137 */ | |
198 | "ibreaka10", /* 138 */ | |
199 | "ibreaka11", /* 139 */ | |
200 | "ibreaka12", /* 140 */ | |
201 | "ibreaka13", /* 141 */ | |
202 | "ibreaka14", /* 142 */ | |
203 | "ibreaka15", /* 143 */ | |
204 | ||
205 | "dbreaka0", /* 144 */ | |
206 | "dbreaka1", /* 145 */ | |
207 | "dbreaka2", /* 146 */ | |
208 | "dbreaka3", /* 147 */ | |
209 | "dbreaka4", /* 148 */ | |
210 | "dbreaka5", /* 149 */ | |
211 | "dbreaka6", /* 150 */ | |
212 | "dbreaka7", /* 151 */ | |
213 | "dbreaka8", /* 152 */ | |
214 | "dbreaka9", /* 153 */ | |
215 | "dbreaka10", /* 154 */ | |
216 | "dbreaka11", /* 155 */ | |
217 | "dbreaka12", /* 156 */ | |
218 | "dbreaka13", /* 157 */ | |
219 | "dbreaka14", /* 158 */ | |
220 | "dbreaka15", /* 159 */ | |
221 | ||
222 | "dbreakc0", /* 160 */ | |
223 | "dbreakc1", /* 161 */ | |
224 | "dbreakc2", /* 162 */ | |
225 | "dbreakc3", /* 163 */ | |
226 | "dbreakc4", /* 164 */ | |
227 | "dbreakc5", /* 165 */ | |
228 | "dbreakc6", /* 166 */ | |
229 | "dbreakc7", /* 167 */ | |
230 | "dbreakc8", /* 168 */ | |
231 | "dbreakc9", /* 169 */ | |
232 | "dbreakc10", /* 170 */ | |
233 | "dbreakc11", /* 171 */ | |
234 | "dbreakc12", /* 172 */ | |
235 | "dbreakc13", /* 173 */ | |
236 | "dbreakc14", /* 174 */ | |
237 | "dbreakc15", /* 175 */ | |
238 | ||
239 | "reserved_176", /* 176 */ | |
240 | ||
241 | "epc1", /* 177 */ | |
242 | "epc2", /* 178 */ | |
243 | "epc3", /* 179 */ | |
244 | "epc4", /* 180 */ | |
245 | "epc5", /* 181 */ | |
246 | "epc6", /* 182 */ | |
247 | "epc7", /* 183 */ | |
248 | "epc8", /* 184 */ | |
249 | "epc9", /* 185 */ | |
250 | "epc10", /* 186 */ | |
251 | "epc11", /* 187 */ | |
252 | "epc12", /* 188 */ | |
253 | "epc13", /* 189 */ | |
254 | "epc14", /* 190 */ | |
255 | "epc15", /* 191 */ | |
256 | "depc", /* 192 */ | |
257 | ||
258 | "reserved_193", /* 193 */ | |
259 | ||
260 | "eps2", /* 194 */ | |
261 | "eps3", /* 195 */ | |
262 | "eps4", /* 196 */ | |
263 | "eps5", /* 197 */ | |
264 | "eps6", /* 198 */ | |
265 | "eps7", /* 199 */ | |
266 | "eps8", /* 200 */ | |
267 | "eps9", /* 201 */ | |
268 | "eps10", /* 202 */ | |
269 | "eps11", /* 203 */ | |
270 | "eps12", /* 204 */ | |
271 | "eps13", /* 205 */ | |
272 | "eps14", /* 206 */ | |
273 | "eps15", /* 207 */ | |
274 | ||
275 | "reserved_208", /* 208 */ | |
276 | ||
277 | "excsave1", /* 209 */ | |
278 | "excsave2", /* 210 */ | |
279 | "excsave3", /* 211 */ | |
280 | "excsave4", /* 212 */ | |
281 | "excsave5", /* 213 */ | |
282 | "excsave6", /* 214 */ | |
283 | "excsave7", /* 215 */ | |
284 | "excsave8", /* 216 */ | |
285 | "excsave9", /* 217 */ | |
286 | "excsave10", /* 218 */ | |
287 | "excsave11", /* 219 */ | |
288 | "excsave12", /* 220 */ | |
289 | "excsave13", /* 221 */ | |
290 | "excsave14", /* 222 */ | |
291 | "excsave15", /* 223 */ | |
292 | "cpenable", /* 224 */ | |
293 | ||
294 | "reserved_225", /* 225 */ | |
295 | ||
296 | "interrupt", /* 226 */ | |
297 | "interrupt2", /* 227 */ | |
298 | "intenable", /* 228 */ | |
299 | ||
300 | "reserved_229", /* 229 */ | |
301 | ||
302 | "ps", /* 230 */ | |
303 | ||
304 | "reserved_231", /* 231 */ | |
305 | ||
306 | "exccause", /* 232 */ | |
307 | "debugcause", /* 233 */ | |
308 | "ccount", /* 234 */ | |
309 | "prid", /* 235 */ | |
310 | "icount", /* 236 */ | |
311 | "icountlvl", /* 237 */ | |
312 | "excvaddr", /* 238 */ | |
313 | ||
314 | "reserved_239", /* 239 */ | |
315 | ||
316 | "ccompare0", /* 240 */ | |
317 | "ccompare1", /* 241 */ | |
318 | "ccompare2", /* 242 */ | |
319 | "ccompare3", /* 243 */ | |
320 | ||
321 | "misc0", /* 244 */ | |
322 | "misc1", /* 245 */ | |
323 | "misc2", /* 246 */ | |
324 | "misc3", /* 247 */ | |
325 | ||
326 | "reserved_248", /* 248 */ | |
327 | "reserved_249", /* 249 */ | |
328 | "reserved_250", /* 250 */ | |
329 | "reserved_251", /* 251 */ | |
330 | "reserved_252", /* 252 */ | |
331 | "reserved_253", /* 253 */ | |
332 | "reserved_254", /* 254 */ | |
333 | "reserved_255", /* 255 */ | |
334 | }; | |
335 | ||
336 | ||
337 | int show_raw_fields; | |
338 | ||
339 | static int fetch_data | |
340 | PARAMS ((struct disassemble_info *info, bfd_vma memaddr, int numBytes)); | |
341 | static void print_xtensa_operand | |
342 | PARAMS ((bfd_vma, struct disassemble_info *, xtensa_operand, | |
343 | unsigned operand_val, int print_sr_name)); | |
344 | ||
345 | struct dis_private { | |
346 | bfd_byte *byte_buf; | |
347 | jmp_buf bailout; | |
348 | }; | |
349 | ||
350 | static int | |
351 | fetch_data (info, memaddr, numBytes) | |
352 | struct disassemble_info *info; | |
353 | bfd_vma memaddr; | |
354 | int numBytes; | |
355 | { | |
356 | int length, status = 0; | |
357 | struct dis_private *priv = (struct dis_private *) info->private_data; | |
358 | int insn_size = (numBytes != 0 ? numBytes : | |
359 | xtensa_insn_maxlength (xtensa_default_isa)); | |
360 | ||
361 | /* Read the maximum instruction size, padding with zeros if we go past | |
362 | the end of the text section. This code will automatically adjust | |
363 | length when we hit the end of the buffer. */ | |
364 | ||
365 | memset (priv->byte_buf, 0, insn_size); | |
366 | for (length = insn_size; length > 0; length--) | |
367 | { | |
368 | status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, | |
369 | info); | |
370 | if (status == 0) | |
371 | return length; | |
372 | } | |
373 | (*info->memory_error_func) (status, memaddr, info); | |
374 | longjmp (priv->bailout, 1); | |
375 | /*NOTREACHED*/ | |
376 | } | |
377 | ||
378 | ||
379 | static void | |
380 | print_xtensa_operand (memaddr, info, opnd, operand_val, print_sr_name) | |
381 | bfd_vma memaddr; | |
382 | struct disassemble_info *info; | |
383 | xtensa_operand opnd; | |
384 | unsigned operand_val; | |
385 | int print_sr_name; | |
386 | { | |
387 | char *kind = xtensa_operand_kind (opnd); | |
388 | int signed_operand_val; | |
389 | ||
390 | if (show_raw_fields) | |
391 | { | |
392 | if (operand_val < 0xa) | |
393 | (*info->fprintf_func) (info->stream, "%u", operand_val); | |
394 | else | |
395 | (*info->fprintf_func) (info->stream, "0x%x", operand_val); | |
396 | return; | |
397 | } | |
398 | ||
399 | operand_val = xtensa_operand_decode (opnd, operand_val); | |
400 | signed_operand_val = (int) operand_val; | |
401 | ||
402 | if (xtensa_operand_isPCRelative (opnd)) | |
403 | { | |
404 | operand_val = xtensa_operand_undo_reloc (opnd, operand_val, memaddr); | |
405 | info->target = operand_val; | |
406 | (*info->print_address_func) (info->target, info); | |
407 | } | |
408 | else if (!strcmp (kind, "i")) | |
409 | { | |
410 | if (print_sr_name | |
411 | && signed_operand_val >= 0 | |
412 | && signed_operand_val <= 255) | |
413 | (*info->fprintf_func) (info->stream, "%s", | |
414 | state_names[signed_operand_val]); | |
415 | else if ((signed_operand_val > -256) && (signed_operand_val < 256)) | |
416 | (*info->fprintf_func) (info->stream, "%d", signed_operand_val); | |
417 | else | |
418 | (*info->fprintf_func) (info->stream, "0x%x",signed_operand_val); | |
419 | } | |
420 | else | |
421 | (*info->fprintf_func) (info->stream, "%s%u", kind, operand_val); | |
422 | } | |
423 | ||
424 | ||
425 | /* Print the Xtensa instruction at address MEMADDR on info->stream. | |
426 | Returns length of the instruction in bytes. */ | |
427 | ||
428 | int | |
429 | print_insn_xtensa (memaddr, info) | |
430 | bfd_vma memaddr; | |
431 | struct disassemble_info *info; | |
432 | { | |
433 | unsigned operand_val; | |
434 | int bytes_fetched, size, maxsize, i, noperands; | |
435 | xtensa_isa isa; | |
436 | xtensa_opcode opc; | |
437 | char *op_name; | |
438 | int print_sr_name; | |
439 | struct dis_private priv; | |
440 | static bfd_byte *byte_buf = NULL; | |
441 | static xtensa_insnbuf insn_buffer = NULL; | |
442 | ||
443 | if (!xtensa_default_isa) | |
444 | (void) xtensa_isa_init (); | |
445 | ||
446 | info->target = 0; | |
447 | maxsize = xtensa_insn_maxlength (xtensa_default_isa); | |
448 | ||
449 | /* Set bytes_per_line to control the amount of whitespace between the hex | |
450 | values and the opcode. For Xtensa, we always print one "chunk" and we | |
451 | vary bytes_per_chunk to determine how many bytes to print. (objdump | |
452 | would apparently prefer that we set bytes_per_chunk to 1 and vary | |
453 | bytes_per_line but that makes it hard to fit 64-bit instructions on | |
454 | an 80-column screen.) The value of bytes_per_line here is not exactly | |
455 | right, because objdump adds an extra space for each chunk so that the | |
456 | amount of whitespace depends on the chunk size. Oh well, it's good | |
457 | enough.... Note that we set the minimum size to 4 to accomodate | |
458 | literal pools. */ | |
459 | info->bytes_per_line = MAX (maxsize, 4); | |
460 | ||
461 | /* Allocate buffers the first time through. */ | |
462 | if (!insn_buffer) | |
463 | insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); | |
464 | if (!byte_buf) | |
465 | byte_buf = (bfd_byte *) malloc (MAX (maxsize, 4)); | |
466 | ||
467 | priv.byte_buf = byte_buf; | |
468 | ||
469 | info->private_data = (PTR) &priv; | |
470 | if (setjmp (priv.bailout) != 0) | |
471 | /* Error return. */ | |
472 | return -1; | |
473 | ||
474 | /* Don't set "isa" before the setjmp to keep the compiler from griping. */ | |
475 | isa = xtensa_default_isa; | |
476 | ||
477 | /* Fetch the maximum size instruction. */ | |
478 | bytes_fetched = fetch_data (info, memaddr, 0); | |
479 | ||
480 | /* Copy the bytes into the decode buffer. */ | |
481 | memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * | |
482 | sizeof (xtensa_insnbuf_word))); | |
483 | xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf); | |
484 | ||
485 | opc = xtensa_decode_insn (isa, insn_buffer); | |
486 | if (opc == XTENSA_UNDEFINED | |
487 | || ((size = xtensa_insn_length (isa, opc)) > bytes_fetched)) | |
488 | { | |
489 | (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); | |
490 | return 1; | |
491 | } | |
492 | ||
493 | op_name = (char *) xtensa_opcode_name (isa, opc); | |
494 | (*info->fprintf_func) (info->stream, "%s", op_name); | |
495 | ||
496 | print_sr_name = (!strcasecmp (op_name, "wsr") | |
497 | || !strcasecmp (op_name, "xsr") | |
498 | || !strcasecmp (op_name, "rsr")); | |
499 | ||
500 | /* Print the operands (if any). */ | |
501 | noperands = xtensa_num_operands (isa, opc); | |
502 | if (noperands > 0) | |
503 | { | |
504 | int first = 1; | |
505 | ||
506 | (*info->fprintf_func) (info->stream, "\t"); | |
507 | for (i = 0; i < noperands; i++) | |
508 | { | |
509 | xtensa_operand opnd = xtensa_get_operand (isa, opc, i); | |
510 | ||
511 | if (first) | |
512 | first = 0; | |
513 | else | |
514 | (*info->fprintf_func) (info->stream, ", "); | |
515 | operand_val = xtensa_operand_get_field (opnd, insn_buffer); | |
516 | print_xtensa_operand (memaddr, info, opnd, operand_val, | |
517 | print_sr_name); | |
518 | } | |
519 | } | |
520 | ||
521 | info->bytes_per_chunk = size; | |
522 | info->display_endian = info->endian; | |
523 | ||
524 | return size; | |
525 | } | |
526 |