1/* xtensa-dis.c. Disassembly functions for Xtensa. 2 Copyright (C) 2003-2022 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 36extern xtensa_isa xtensa_default_isa; 37 38#ifndef MAX 39#define MAX(a,b) (a > b ? a : b) 40#endif 41 42int show_raw_fields; 43 44struct 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 57static void 58xtensa_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 98static property_table_entry * 99xtensa_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 134static int 135xtensa_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 162static int 163fetch_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 189static void 190print_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_func) (info->stream, "%d", signed_operand_val); 242 else 243 (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val); 244 } 245 } 246 else 247 { 248 int i = 1; 249 xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); 250 (*info->fprintf_func) (info->stream, "%s%u", 251 xtensa_regfile_shortname (isa, opnd_rf), 252 operand_val); 253 while (i < xtensa_operand_num_regs (isa, opc, opnd)) 254 { 255 operand_val++; 256 (*info->fprintf_func) (info->stream, ":%s%u", 257 xtensa_regfile_shortname (isa, opnd_rf), 258 operand_val); 259 i++; 260 } 261 } 262} 263 264 265/* Print the Xtensa instruction at address MEMADDR on info->stream. 266 Returns length of the instruction in bytes. */ 267 268int 269print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info) 270{ 271 unsigned operand_val; 272 int bytes_fetched, size, maxsize, i, n, noperands, nslots; 273 xtensa_isa isa; 274 xtensa_opcode opc; 275 xtensa_format fmt; 276 static struct dis_private priv; 277 static bfd_byte *byte_buf = NULL; 278 static xtensa_insnbuf insn_buffer = NULL; 279 static xtensa_insnbuf slot_buffer = NULL; 280 int first, first_slot, valid_insn; 281 property_table_entry *insn_block; 282 283 if (!xtensa_default_isa) 284 xtensa_default_isa = xtensa_isa_init (0, 0); 285 286 info->target = 0; 287 maxsize = xtensa_isa_maxlength (xtensa_default_isa); 288 289 /* Set bytes_per_line to control the amount of whitespace between the hex 290 values and the opcode. For Xtensa, we always print one "chunk" and we 291 vary bytes_per_chunk to determine how many bytes to print. (objdump 292 would apparently prefer that we set bytes_per_chunk to 1 and vary 293 bytes_per_line but that makes it hard to fit 64-bit instructions on 294 an 80-column screen.) The value of bytes_per_line here is not exactly 295 right, because objdump adds an extra space for each chunk so that the 296 amount of whitespace depends on the chunk size. Oh well, it's good 297 enough.... Note that we set the minimum size to 4 to accomodate 298 literal pools. */ 299 info->bytes_per_line = MAX (maxsize, 4); 300 301 /* Allocate buffers the first time through. */ 302 if (!insn_buffer) 303 { 304 insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); 305 slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); 306 byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4)); 307 } 308 309 priv.byte_buf = byte_buf; 310 311 info->private_data = (void *) &priv; 312 313 /* Prepare instruction tables. */ 314 315 if (info->section != NULL) 316 { 317 asection *section = info->section; 318 319 if (priv.last_section != section) 320 { 321 bfd *abfd = section->owner; 322 323 if (priv.last_section != NULL) 324 { 325 /* Reset insn_table_entries. */ 326 priv.insn_table_entry_count = 0; 327 free (priv.insn_table_entries); 328 priv.insn_table_entries = NULL; 329 } 330 priv.last_section = section; 331 332 /* Read insn_table_entries. */ 333 priv.insn_table_entry_count = 334 xtensa_read_table_entries (abfd, section, 335 &priv.insn_table_entries, 336 XTENSA_PROP_SEC_NAME, false); 337 if (priv.insn_table_entry_count == 0) 338 { 339 free (priv.insn_table_entries); 340 priv.insn_table_entries = NULL; 341 /* Backwards compatibility support. */ 342 priv.insn_table_entry_count = 343 xtensa_read_table_entries (abfd, section, 344 &priv.insn_table_entries, 345 XTENSA_INSN_SEC_NAME, false); 346 } 347 priv.insn_table_cur_idx = 0; 348 xtensa_coalesce_insn_tables (&priv); 349 } 350 /* Else nothing to do, same section as last time. */ 351 } 352 353 if (OPCODES_SIGSETJMP (priv.bailout) != 0) 354 /* Error return. */ 355 return -1; 356 357 /* Fetch the maximum size instruction. */ 358 bytes_fetched = fetch_data (info, memaddr); 359 360 insn_block = xtensa_find_table_entry (memaddr, info); 361 362 /* Don't set "isa" before the setjmp to keep the compiler from griping. */ 363 isa = xtensa_default_isa; 364 size = 0; 365 nslots = 0; 366 valid_insn = 0; 367 fmt = 0; 368 if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN)) 369 { 370 /* Copy the bytes into the decode buffer. */ 371 memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * 372 sizeof (xtensa_insnbuf_word))); 373 xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, 374 bytes_fetched); 375 376 fmt = xtensa_format_decode (isa, insn_buffer); 377 if (fmt != XTENSA_UNDEFINED 378 && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched) 379 && xtensa_instruction_fits (memaddr, size, insn_block)) 380 { 381 /* Make sure all the opcodes are valid. */ 382 valid_insn = 1; 383 nslots = xtensa_format_num_slots (isa, fmt); 384 for (n = 0; n < nslots; n++) 385 { 386 xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); 387 if (xtensa_opcode_decode (isa, fmt, n, slot_buffer) 388 == XTENSA_UNDEFINED) 389 { 390 valid_insn = 0; 391 break; 392 } 393 } 394 } 395 } 396 397 if (!valid_insn) 398 { 399 if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL) 400 && (memaddr & 3) == 0 && bytes_fetched >= 4) 401 { 402 info->bytes_per_chunk = 4; 403 return 4; 404 } 405 else 406 { 407 (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); 408 return 1; 409 } 410 } 411 412 if (nslots > 1) 413 (*info->fprintf_func) (info->stream, "{ "); 414 415 info->insn_type = dis_nonbranch; 416 info->insn_info_valid = 1; 417 418 first_slot = 1; 419 for (n = 0; n < nslots; n++) 420 { 421 if (first_slot) 422 first_slot = 0; 423 else 424 (*info->fprintf_func) (info->stream, "; "); 425 426 xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); 427 opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer); 428 (*info->fprintf_func) (info->stream, "%s", 429 xtensa_opcode_name (isa, opc)); 430 431 if (xtensa_opcode_is_branch (isa, opc)) 432 info->insn_type = dis_condbranch; 433 else if (xtensa_opcode_is_jump (isa, opc)) 434 info->insn_type = dis_branch; 435 else if (xtensa_opcode_is_call (isa, opc)) 436 info->insn_type = dis_jsr; 437 438 /* Print the operands (if any). */ 439 noperands = xtensa_opcode_num_operands (isa, opc); 440 first = 1; 441 for (i = 0; i < noperands; i++) 442 { 443 if (xtensa_operand_is_visible (isa, opc, i) == 0) 444 continue; 445 if (first) 446 { 447 (*info->fprintf_func) (info->stream, "\t"); 448 first = 0; 449 } 450 else 451 (*info->fprintf_func) (info->stream, ", "); 452 (void) xtensa_operand_get_field (isa, opc, i, fmt, n, 453 slot_buffer, &operand_val); 454 455 print_xtensa_operand (memaddr, info, opc, i, operand_val); 456 } 457 } 458 459 if (nslots > 1) 460 (*info->fprintf_func) (info->stream, " }"); 461 462 info->bytes_per_chunk = size; 463 info->display_endian = info->endian; 464 465 return size; 466} 467 468