1 /* xtensa-dis.c. Disassembly functions for Xtensa. 2 Copyright (C) 2003-2024 Free Software Foundation, Inc. 3 Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) 4 5 This file is part of the GNU opcodes library. 6 7 This library 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 3, or (at your option) 10 any later version. 11 12 It is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this file; see the file COPYING. If not, write to the 19 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include "sysdep.h" 23 #include <stdlib.h> 24 #include <stdio.h> 25 #include <sys/types.h> 26 #include <string.h> 27 #include "xtensa-isa.h" 28 #include "ansidecl.h" 29 #include "libiberty.h" 30 #include "bfd.h" 31 #include "elf/xtensa.h" 32 #include "disassemble.h" 33 34 #include <setjmp.h> 35 36 extern xtensa_isa xtensa_default_isa; 37 38 #ifndef MAX 39 #define MAX(a,b) (a > b ? a : b) 40 #endif 41 42 int show_raw_fields; 43 44 struct dis_private 45 { 46 bfd_byte *byte_buf; 47 OPCODES_SIGJMP_BUF bailout; 48 /* Persistent fields, valid for last_section only. */ 49 asection *last_section; 50 property_table_entry *insn_table_entries; 51 int insn_table_entry_count; 52 /* Cached property table search position. */ 53 bfd_vma insn_table_cur_addr; 54 int insn_table_cur_idx; 55 }; 56 57 static void 58 xtensa_coalesce_insn_tables (struct dis_private *priv) 59 { 60 const int mask = ~(XTENSA_PROP_DATA | XTENSA_PROP_NO_TRANSFORM); 61 int count = priv->insn_table_entry_count; 62 int i, j; 63 64 /* Loop over all entries, combining adjacent ones that differ only in 65 the flag bits XTENSA_PROP_DATA and XTENSA_PROP_NO_TRANSFORM. */ 66 67 for (i = j = 0; j < count; ++i) 68 { 69 property_table_entry *entry = priv->insn_table_entries + i; 70 71 *entry = priv->insn_table_entries[j]; 72 73 for (++j; j < count; ++j) 74 { 75 property_table_entry *next = priv->insn_table_entries + j; 76 int fill = xtensa_compute_fill_extra_space (entry); 77 int size = entry->size + fill; 78 79 if (entry->address + size == next->address) 80 { 81 int entry_flags = entry->flags & mask; 82 int next_flags = next->flags & mask; 83 84 if (next_flags == entry_flags) 85 entry->size = next->address - entry->address + next->size; 86 else 87 break; 88 } 89 else 90 { 91 break; 92 } 93 } 94 } 95 priv->insn_table_entry_count = i; 96 } 97 98 static property_table_entry * 99 xtensa_find_table_entry (bfd_vma memaddr, struct disassemble_info *info) 100 { 101 struct dis_private *priv = (struct dis_private *) info->private_data; 102 int i; 103 104 if (priv->insn_table_entries == NULL 105 || priv->insn_table_entry_count < 0) 106 return NULL; 107 108 if (memaddr < priv->insn_table_cur_addr) 109 priv->insn_table_cur_idx = 0; 110 111 for (i = priv->insn_table_cur_idx; i < priv->insn_table_entry_count; ++i) 112 { 113 property_table_entry *block = priv->insn_table_entries + i; 114 115 if (block->size != 0) 116 { 117 if ((memaddr >= block->address 118 && memaddr < block->address + block->size) 119 || memaddr < block->address) 120 { 121 priv->insn_table_cur_addr = memaddr; 122 priv->insn_table_cur_idx = i; 123 return block; 124 } 125 } 126 } 127 return NULL; 128 } 129 130 /* Check whether an instruction crosses an instruction block boundary 131 (according to property tables). 132 If it does, return 0 (doesn't fit), else return 1. */ 133 134 static int 135 xtensa_instruction_fits (bfd_vma memaddr, int size, 136 property_table_entry *insn_block) 137 { 138 unsigned max_size; 139 140 /* If no property table info, assume it fits. */ 141 if (insn_block == NULL || size <= 0) 142 return 1; 143 144 /* If too high, limit nextstop by the next insn address. */ 145 if (insn_block->address > memaddr) 146 { 147 /* memaddr is not in an instruction block, but is followed by one. */ 148 max_size = insn_block->address - memaddr; 149 } 150 else 151 { 152 /* memaddr is in an instruction block, go no further than the end. */ 153 max_size = insn_block->address + insn_block->size - memaddr; 154 } 155 156 /* Crossing a boundary, doesn't "fit". */ 157 if ((unsigned)size > max_size) 158 return 0; 159 return 1; 160 } 161 162 static int 163 fetch_data (struct disassemble_info *info, bfd_vma memaddr) 164 { 165 int length, status = 0; 166 struct dis_private *priv = (struct dis_private *) info->private_data; 167 int insn_size = xtensa_isa_maxlength (xtensa_default_isa); 168 169 insn_size = MAX (insn_size, 4); 170 171 /* Read the maximum instruction size, padding with zeros if we go past 172 the end of the text section. This code will automatically adjust 173 length when we hit the end of the buffer. */ 174 175 memset (priv->byte_buf, 0, insn_size); 176 for (length = insn_size; length > 0; length--) 177 { 178 status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, 179 info); 180 if (status == 0) 181 return length; 182 } 183 (*info->memory_error_func) (status, memaddr, info); 184 OPCODES_SIGLONGJMP (priv->bailout, 1); 185 /*NOTREACHED*/ 186 } 187 188 189 static void 190 print_xtensa_operand (bfd_vma memaddr, 191 struct disassemble_info *info, 192 xtensa_opcode opc, 193 int opnd, 194 unsigned operand_val) 195 { 196 xtensa_isa isa = xtensa_default_isa; 197 int signed_operand_val, status; 198 bfd_byte litbuf[4]; 199 200 if (show_raw_fields) 201 { 202 if (operand_val < 0xa) 203 (*info->fprintf_func) (info->stream, "%u", operand_val); 204 else 205 (*info->fprintf_func) (info->stream, "0x%x", operand_val); 206 return; 207 } 208 209 (void) xtensa_operand_decode (isa, opc, opnd, &operand_val); 210 signed_operand_val = (int) operand_val; 211 212 if (xtensa_operand_is_register (isa, opc, opnd) == 0) 213 { 214 if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1) 215 { 216 (void) xtensa_operand_undo_reloc (isa, opc, opnd, 217 &operand_val, memaddr); 218 info->target = operand_val; 219 (*info->print_address_func) (info->target, info); 220 /* Also display value loaded by L32R (but not if reloc exists, 221 those tend to be wrong): */ 222 if ((info->flags & INSN_HAS_RELOC) == 0 223 && !strcmp ("l32r", xtensa_opcode_name (isa, opc))) 224 status = (*info->read_memory_func) (operand_val, litbuf, 4, info); 225 else 226 status = -1; 227 228 if (status == 0) 229 { 230 unsigned literal = bfd_get_bits (litbuf, 32, 231 info->endian == BFD_ENDIAN_BIG); 232 233 (*info->fprintf_func) (info->stream, " ("); 234 (*info->print_address_func) (literal, info); 235 (*info->fprintf_func) (info->stream, ")"); 236 } 237 } 238 else 239 { 240 if ((signed_operand_val > -256) && (signed_operand_val < 256)) 241 (*info->fprintf_styled_func) (info->stream, dis_style_immediate, 242 "%d", signed_operand_val); 243 else 244 (*info->fprintf_styled_func) (info->stream, dis_style_immediate, 245 "0x%x", signed_operand_val); 246 } 247 } 248 else 249 { 250 int i = 1; 251 xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); 252 (*info->fprintf_styled_func) (info->stream, dis_style_register, 253 "%s%u", 254 xtensa_regfile_shortname (isa, opnd_rf), 255 operand_val); 256 while (i < xtensa_operand_num_regs (isa, opc, opnd)) 257 { 258 operand_val++; 259 (*info->fprintf_styled_func) (info->stream, dis_style_register, 260 ":%s%u", 261 xtensa_regfile_shortname (isa, opnd_rf), 262 operand_val); 263 i++; 264 } 265 } 266 } 267 268 269 /* Print the Xtensa instruction at address MEMADDR on info->stream. 270 Returns length of the instruction in bytes. */ 271 272 int 273 print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info) 274 { 275 unsigned operand_val; 276 int bytes_fetched, size, maxsize, i, n, noperands, nslots; 277 xtensa_isa isa; 278 xtensa_opcode opc; 279 xtensa_format fmt; 280 static struct dis_private priv; 281 static bfd_byte *byte_buf = NULL; 282 static xtensa_insnbuf insn_buffer = NULL; 283 static xtensa_insnbuf slot_buffer = NULL; 284 int first, first_slot, valid_insn; 285 property_table_entry *insn_block; 286 enum dis_insn_type insn_type; 287 bfd_vma target; 288 289 if (!xtensa_default_isa) 290 xtensa_default_isa = xtensa_isa_init (0, 0); 291 292 info->target = 0; 293 maxsize = xtensa_isa_maxlength (xtensa_default_isa); 294 295 /* Set bytes_per_line to control the amount of whitespace between the hex 296 values and the opcode. For Xtensa, we always print one "chunk" and we 297 vary bytes_per_chunk to determine how many bytes to print. (objdump 298 would apparently prefer that we set bytes_per_chunk to 1 and vary 299 bytes_per_line but that makes it hard to fit 64-bit instructions on 300 an 80-column screen.) The value of bytes_per_line here is not exactly 301 right, because objdump adds an extra space for each chunk so that the 302 amount of whitespace depends on the chunk size. Oh well, it's good 303 enough.... Note that we set the minimum size to 4 to accomodate 304 literal pools. */ 305 info->bytes_per_line = MAX (maxsize, 4); 306 307 /* Allocate buffers the first time through. */ 308 if (!insn_buffer) 309 { 310 insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); 311 slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); 312 byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4)); 313 } 314 315 priv.byte_buf = byte_buf; 316 317 info->private_data = (void *) &priv; 318 319 /* Prepare instruction tables. */ 320 321 if (info->section != NULL) 322 { 323 asection *section = info->section; 324 325 if (priv.last_section != section) 326 { 327 bfd *abfd = section->owner; 328 329 if (priv.last_section != NULL) 330 { 331 /* Reset insn_table_entries. */ 332 priv.insn_table_entry_count = 0; 333 free (priv.insn_table_entries); 334 priv.insn_table_entries = NULL; 335 } 336 priv.last_section = section; 337 338 /* Read insn_table_entries. */ 339 priv.insn_table_entry_count = 340 xtensa_read_table_entries (abfd, section, 341 &priv.insn_table_entries, 342 XTENSA_PROP_SEC_NAME, false); 343 if (priv.insn_table_entry_count == 0) 344 { 345 free (priv.insn_table_entries); 346 priv.insn_table_entries = NULL; 347 /* Backwards compatibility support. */ 348 priv.insn_table_entry_count = 349 xtensa_read_table_entries (abfd, section, 350 &priv.insn_table_entries, 351 XTENSA_INSN_SEC_NAME, false); 352 } 353 priv.insn_table_cur_idx = 0; 354 xtensa_coalesce_insn_tables (&priv); 355 } 356 /* Else nothing to do, same section as last time. */ 357 } 358 359 if (OPCODES_SIGSETJMP (priv.bailout) != 0) 360 /* Error return. */ 361 return -1; 362 363 /* Fetch the maximum size instruction. */ 364 bytes_fetched = fetch_data (info, memaddr); 365 366 insn_block = xtensa_find_table_entry (memaddr, info); 367 368 /* Don't set "isa" before the setjmp to keep the compiler from griping. */ 369 isa = xtensa_default_isa; 370 size = 0; 371 nslots = 0; 372 valid_insn = 0; 373 fmt = 0; 374 if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN)) 375 { 376 /* Copy the bytes into the decode buffer. */ 377 memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * 378 sizeof (xtensa_insnbuf_word))); 379 xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, 380 bytes_fetched); 381 382 fmt = xtensa_format_decode (isa, insn_buffer); 383 if (fmt != XTENSA_UNDEFINED 384 && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched) 385 && xtensa_instruction_fits (memaddr, size, insn_block)) 386 { 387 /* Make sure all the opcodes are valid. */ 388 valid_insn = 1; 389 nslots = xtensa_format_num_slots (isa, fmt); 390 for (n = 0; n < nslots; n++) 391 { 392 xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); 393 if (xtensa_opcode_decode (isa, fmt, n, slot_buffer) 394 == XTENSA_UNDEFINED) 395 { 396 valid_insn = 0; 397 break; 398 } 399 } 400 } 401 } 402 403 if (!valid_insn) 404 { 405 if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL) 406 && (memaddr & 3) == 0 && bytes_fetched >= 4) 407 { 408 info->bytes_per_chunk = 4; 409 return 4; 410 } 411 else 412 { 413 (*info->fprintf_styled_func) (info->stream, 414 dis_style_assembler_directive, 415 ".byte"); 416 (*info->fprintf_func) (info->stream, "\t"); 417 (*info->fprintf_styled_func) (info->stream, 418 dis_style_immediate, 419 "%#02x", priv.byte_buf[0]); 420 return 1; 421 } 422 } 423 424 if (nslots > 1) 425 (*info->fprintf_func) (info->stream, "{ "); 426 427 insn_type = dis_nonbranch; 428 target = 0; 429 first_slot = 1; 430 for (n = 0; n < nslots; n++) 431 { 432 int imm_pcrel = 0; 433 434 if (first_slot) 435 first_slot = 0; 436 else 437 (*info->fprintf_func) (info->stream, "; "); 438 439 xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); 440 opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer); 441 (*info->fprintf_styled_func) (info->stream, 442 dis_style_mnemonic, "%s", 443 xtensa_opcode_name (isa, opc)); 444 445 if (xtensa_opcode_is_branch (isa, opc)) 446 info->insn_type = dis_condbranch; 447 else if (xtensa_opcode_is_jump (isa, opc)) 448 info->insn_type = dis_branch; 449 else if (xtensa_opcode_is_call (isa, opc)) 450 info->insn_type = dis_jsr; 451 else 452 info->insn_type = dis_nonbranch; 453 454 /* Print the operands (if any). */ 455 noperands = xtensa_opcode_num_operands (isa, opc); 456 first = 1; 457 for (i = 0; i < noperands; i++) 458 { 459 if (xtensa_operand_is_visible (isa, opc, i) == 0) 460 continue; 461 if (first) 462 { 463 (*info->fprintf_func) (info->stream, "\t"); 464 first = 0; 465 } 466 else 467 (*info->fprintf_func) (info->stream, ", "); 468 (void) xtensa_operand_get_field (isa, opc, i, fmt, n, 469 slot_buffer, &operand_val); 470 471 print_xtensa_operand (memaddr, info, opc, i, operand_val); 472 if (xtensa_operand_is_PCrelative (isa, opc, i)) 473 ++imm_pcrel; 474 } 475 if (!imm_pcrel) 476 info->insn_type = dis_nonbranch; 477 if (info->insn_type != dis_nonbranch) 478 { 479 insn_type = info->insn_type; 480 target = info->target; 481 } 482 } 483 info->insn_type = insn_type; 484 info->target = target; 485 info->insn_info_valid = 1; 486 487 if (nslots > 1) 488 (*info->fprintf_func) (info->stream, " }"); 489 490 info->bytes_per_chunk = size; 491 info->display_endian = info->endian; 492 493 return size; 494 } 495 496