| 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 | |