]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/xtensa-dis.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / opcodes / xtensa-dis.c
CommitLineData
e0001a05 1/* xtensa-dis.c. Disassembly functions for Xtensa.
fd67aa11 2 Copyright (C) 2003-2024 Free Software Foundation, Inc.
e0001a05
NC
3 Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com)
4
9b201bb5 5 This file is part of the GNU opcodes library.
e0001a05 6
9b201bb5
NC
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.
e0001a05 11
9b201bb5
NC
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.
e0001a05 16
9b201bb5
NC
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. */
e0001a05 21
df7b86aa 22#include "sysdep.h"
e0001a05
NC
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"
43cd72b9 29#include "libiberty.h"
4b8e28c7
MF
30#include "bfd.h"
31#include "elf/xtensa.h"
88c1242d 32#include "disassemble.h"
e0001a05
NC
33
34#include <setjmp.h>
35
43cd72b9
BW
36extern xtensa_isa xtensa_default_isa;
37
e0001a05
NC
38#ifndef MAX
39#define MAX(a,b) (a > b ? a : b)
40#endif
41
e0001a05
NC
42int show_raw_fields;
43
43cd72b9
BW
44struct dis_private
45{
e0001a05 46 bfd_byte *byte_buf;
8df14d78 47 OPCODES_SIGJMP_BUF bailout;
4b8e28c7
MF
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;
e0001a05
NC
55};
56
4b8e28c7
MF
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}
43cd72b9 161
e0001a05 162static int
7fa3d080 163fetch_data (struct disassemble_info *info, bfd_vma memaddr)
e0001a05
NC
164{
165 int length, status = 0;
166 struct dis_private *priv = (struct dis_private *) info->private_data;
43cd72b9 167 int insn_size = xtensa_isa_maxlength (xtensa_default_isa);
e0001a05 168
4b8e28c7
MF
169 insn_size = MAX (insn_size, 4);
170
e0001a05
NC
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);
8df14d78 184 OPCODES_SIGLONGJMP (priv->bailout, 1);
e0001a05
NC
185 /*NOTREACHED*/
186}
187
188
189static void
7fa3d080
BW
190print_xtensa_operand (bfd_vma memaddr,
191 struct disassemble_info *info,
192 xtensa_opcode opc,
193 int opnd,
194 unsigned operand_val)
e0001a05 195{
43cd72b9 196 xtensa_isa isa = xtensa_default_isa;
b3ea7639
MF
197 int signed_operand_val, status;
198 bfd_byte litbuf[4];
43e65147 199
e0001a05
NC
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
43cd72b9 209 (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
e0001a05
NC
210 signed_operand_val = (int) operand_val;
211
43cd72b9 212 if (xtensa_operand_is_register (isa, opc, opnd) == 0)
e0001a05 213 {
43cd72b9
BW
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);
b3ea7639
MF
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 }
43cd72b9 237 }
e0001a05 238 else
43cd72b9
BW
239 {
240 if ((signed_operand_val > -256) && (signed_operand_val < 256))
39086586
MF
241 (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
242 "%d", signed_operand_val);
43cd72b9 243 else
39086586
MF
244 (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
245 "0x%x", signed_operand_val);
43cd72b9 246 }
e0001a05
NC
247 }
248 else
43cd72b9
BW
249 {
250 int i = 1;
251 xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
39086586
MF
252 (*info->fprintf_styled_func) (info->stream, dis_style_register,
253 "%s%u",
254 xtensa_regfile_shortname (isa, opnd_rf),
255 operand_val);
43cd72b9
BW
256 while (i < xtensa_operand_num_regs (isa, opc, opnd))
257 {
258 operand_val++;
39086586
MF
259 (*info->fprintf_styled_func) (info->stream, dis_style_register,
260 ":%s%u",
261 xtensa_regfile_shortname (isa, opnd_rf),
262 operand_val);
43cd72b9 263 i++;
43e65147 264 }
43cd72b9 265 }
e0001a05
NC
266}
267
268
269/* Print the Xtensa instruction at address MEMADDR on info->stream.
270 Returns length of the instruction in bytes. */
271
272int
7fa3d080 273print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
e0001a05
NC
274{
275 unsigned operand_val;
43cd72b9 276 int bytes_fetched, size, maxsize, i, n, noperands, nslots;
e0001a05
NC
277 xtensa_isa isa;
278 xtensa_opcode opc;
43cd72b9 279 xtensa_format fmt;
4b8e28c7 280 static struct dis_private priv;
e0001a05
NC
281 static bfd_byte *byte_buf = NULL;
282 static xtensa_insnbuf insn_buffer = NULL;
43cd72b9 283 static xtensa_insnbuf slot_buffer = NULL;
ce72cd46 284 int first, first_slot, valid_insn;
4b8e28c7 285 property_table_entry *insn_block;
e80512c8
MF
286 enum dis_insn_type insn_type;
287 bfd_vma target;
e0001a05
NC
288
289 if (!xtensa_default_isa)
43cd72b9 290 xtensa_default_isa = xtensa_isa_init (0, 0);
e0001a05
NC
291
292 info->target = 0;
43cd72b9 293 maxsize = xtensa_isa_maxlength (xtensa_default_isa);
e0001a05
NC
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)
43cd72b9
BW
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 }
e0001a05
NC
314
315 priv.byte_buf = byte_buf;
316
7fa3d080 317 info->private_data = (void *) &priv;
4b8e28c7
MF
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;
d96bf37b 333 free (priv.insn_table_entries);
4b8e28c7
MF
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,
78933a4a 342 XTENSA_PROP_SEC_NAME, false);
4b8e28c7
MF
343 if (priv.insn_table_entry_count == 0)
344 {
d96bf37b 345 free (priv.insn_table_entries);
4b8e28c7
MF
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,
78933a4a 351 XTENSA_INSN_SEC_NAME, false);
4b8e28c7
MF
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
8df14d78 359 if (OPCODES_SIGSETJMP (priv.bailout) != 0)
e0001a05
NC
360 /* Error return. */
361 return -1;
362
e0001a05 363 /* Fetch the maximum size instruction. */
118fecd3 364 bytes_fetched = fetch_data (info, memaddr);
e0001a05 365
4b8e28c7 366 insn_block = xtensa_find_table_entry (memaddr, info);
43cd72b9 367
ce72cd46
AM
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;
4b8e28c7 374 if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
43cd72b9 375 {
4b8e28c7
MF
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))
43cd72b9 386 {
4b8e28c7
MF
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++)
43cd72b9 391 {
4b8e28c7
MF
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 }
43cd72b9
BW
399 }
400 }
401 }
e0001a05 402
43cd72b9 403 if (!valid_insn)
e0001a05 404 {
4b8e28c7
MF
405 if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
406 && (memaddr & 3) == 0 && bytes_fetched >= 4)
407 {
c1cbb7d8 408 info->bytes_per_chunk = 4;
4b8e28c7
MF
409 return 4;
410 }
411 else
412 {
39086586
MF
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]);
4b8e28c7
MF
420 return 1;
421 }
e0001a05
NC
422 }
423
43cd72b9
BW
424 if (nslots > 1)
425 (*info->fprintf_func) (info->stream, "{ ");
e0001a05 426
e80512c8
MF
427 insn_type = dis_nonbranch;
428 target = 0;
43cd72b9
BW
429 first_slot = 1;
430 for (n = 0; n < nslots; n++)
e0001a05 431 {
e80512c8
MF
432 int imm_pcrel = 0;
433
43cd72b9
BW
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);
39086586
MF
441 (*info->fprintf_styled_func) (info->stream,
442 dis_style_mnemonic, "%s",
443 xtensa_opcode_name (isa, opc));
e0001a05 444
6aee2cb2
MF
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;
e80512c8
MF
451 else
452 info->insn_type = dis_nonbranch;
6aee2cb2 453
43cd72b9
BW
454 /* Print the operands (if any). */
455 noperands = xtensa_opcode_num_operands (isa, opc);
456 first = 1;
e0001a05
NC
457 for (i = 0; i < noperands; i++)
458 {
43cd72b9
BW
459 if (xtensa_operand_is_visible (isa, opc, i) == 0)
460 continue;
e0001a05 461 if (first)
43cd72b9
BW
462 {
463 (*info->fprintf_func) (info->stream, "\t");
464 first = 0;
465 }
e0001a05
NC
466 else
467 (*info->fprintf_func) (info->stream, ", ");
43cd72b9
BW
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);
e80512c8
MF
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;
43cd72b9 481 }
e0001a05 482 }
e80512c8
MF
483 info->insn_type = insn_type;
484 info->target = target;
485 info->insn_info_valid = 1;
e0001a05 486
43cd72b9
BW
487 if (nslots > 1)
488 (*info->fprintf_func) (info->stream, " }");
489
e0001a05
NC
490 info->bytes_per_chunk = size;
491 info->display_endian = info->endian;
492
493 return size;
494}
495