Coverage Report

Created: 2023-08-28 06:23

/src/binutils-gdb/opcodes/xtensa-dis.c
Line
Count
Source (jump to first uncovered line)
1
/* xtensa-dis.c.  Disassembly functions for Xtensa.
2
   Copyright (C) 2003-2023 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
0
#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
0
{
60
0
  const int mask = ~(XTENSA_PROP_DATA | XTENSA_PROP_NO_TRANSFORM);
61
0
  int count = priv->insn_table_entry_count;
62
0
  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
0
  for (i = j = 0; j < count; ++i)
68
0
    {
69
0
      property_table_entry *entry = priv->insn_table_entries + i;
70
71
0
      *entry = priv->insn_table_entries[j];
72
73
0
      for (++j; j < count; ++j)
74
0
  {
75
0
    property_table_entry *next = priv->insn_table_entries + j;
76
0
    int fill = xtensa_compute_fill_extra_space (entry);
77
0
    int size = entry->size + fill;
78
79
0
    if (entry->address + size == next->address)
80
0
      {
81
0
        int entry_flags = entry->flags & mask;
82
0
        int next_flags = next->flags & mask;
83
84
0
        if (next_flags == entry_flags)
85
0
    entry->size = next->address - entry->address + next->size;
86
0
        else
87
0
    break;
88
0
      }
89
0
    else
90
0
      {
91
0
        break;
92
0
      }
93
0
  }
94
0
    }
95
0
  priv->insn_table_entry_count = i;
96
0
}
97
98
static property_table_entry *
99
xtensa_find_table_entry (bfd_vma memaddr, struct disassemble_info *info)
100
0
{
101
0
  struct dis_private *priv = (struct dis_private *) info->private_data;
102
0
  int i;
103
104
0
  if (priv->insn_table_entries == NULL
105
0
      || priv->insn_table_entry_count < 0)
106
0
    return NULL;
107
108
0
  if (memaddr < priv->insn_table_cur_addr)
109
0
    priv->insn_table_cur_idx = 0;
110
111
0
  for (i = priv->insn_table_cur_idx; i < priv->insn_table_entry_count; ++i)
112
0
    {
113
0
      property_table_entry *block = priv->insn_table_entries + i;
114
115
0
      if (block->size != 0)
116
0
  {
117
0
    if ((memaddr >= block->address
118
0
         && memaddr < block->address + block->size)
119
0
        || memaddr < block->address)
120
0
      {
121
0
        priv->insn_table_cur_addr = memaddr;
122
0
        priv->insn_table_cur_idx = i;
123
0
        return block;
124
0
      }
125
0
  }
126
0
    }
127
0
  return NULL;
128
0
}
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
0
{
138
0
  unsigned max_size;
139
140
  /* If no property table info, assume it fits.  */
141
0
  if (insn_block == NULL || size <= 0)
142
0
    return 1;
143
144
  /* If too high, limit nextstop by the next insn address.  */
145
0
  if (insn_block->address > memaddr)
146
0
    {
147
      /* memaddr is not in an instruction block, but is followed by one.  */
148
0
      max_size = insn_block->address - memaddr;
149
0
    }
150
0
  else
151
0
    {
152
      /* memaddr is in an instruction block, go no further than the end.  */
153
0
      max_size = insn_block->address + insn_block->size - memaddr;
154
0
    }
155
156
  /* Crossing a boundary, doesn't "fit".  */
157
0
  if ((unsigned)size > max_size)
158
0
    return 0;
159
0
  return 1;
160
0
}
161
162
static int
163
fetch_data (struct disassemble_info *info, bfd_vma memaddr)
164
0
{
165
0
  int length, status = 0;
166
0
  struct dis_private *priv = (struct dis_private *) info->private_data;
167
0
  int insn_size = xtensa_isa_maxlength (xtensa_default_isa);
168
169
0
  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
0
  memset (priv->byte_buf, 0, insn_size);
176
0
  for (length = insn_size; length > 0; length--)
177
0
    {
178
0
      status = (*info->read_memory_func) (memaddr, priv->byte_buf, length,
179
0
            info);
180
0
      if (status == 0)
181
0
  return length;
182
0
    }
183
0
  (*info->memory_error_func) (status, memaddr, info);
184
0
  OPCODES_SIGLONGJMP (priv->bailout, 1);
185
  /*NOTREACHED*/
186
0
}
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
0
{
196
0
  xtensa_isa isa = xtensa_default_isa;
197
0
  int signed_operand_val, status;
198
0
  bfd_byte litbuf[4];
199
200
0
  if (show_raw_fields)
201
0
    {
202
0
      if (operand_val < 0xa)
203
0
  (*info->fprintf_func) (info->stream, "%u", operand_val);
204
0
      else
205
0
  (*info->fprintf_func) (info->stream, "0x%x", operand_val);
206
0
      return;
207
0
    }
208
209
0
  (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
210
0
  signed_operand_val = (int) operand_val;
211
212
0
  if (xtensa_operand_is_register (isa, opc, opnd) == 0)
213
0
    {
214
0
      if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
215
0
  {
216
0
    (void) xtensa_operand_undo_reloc (isa, opc, opnd,
217
0
              &operand_val, memaddr);
218
0
    info->target = operand_val;
219
0
    (*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
0
    if ((info->flags & INSN_HAS_RELOC) == 0
223
0
        && !strcmp ("l32r", xtensa_opcode_name (isa, opc)))
224
0
      status = (*info->read_memory_func) (operand_val, litbuf, 4, info);
225
0
    else
226
0
      status = -1;
227
228
0
    if (status == 0)
229
0
      {
230
0
        unsigned literal = bfd_get_bits (litbuf, 32,
231
0
                 info->endian == BFD_ENDIAN_BIG);
232
233
0
        (*info->fprintf_func) (info->stream, " (");
234
0
        (*info->print_address_func) (literal, info);
235
0
        (*info->fprintf_func) (info->stream, ")");
236
0
      }
237
0
  }
238
0
      else
239
0
  {
240
0
    if ((signed_operand_val > -256) && (signed_operand_val < 256))
241
0
      (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
242
0
            "%d", signed_operand_val);
243
0
    else
244
0
      (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
245
0
            "0x%x", signed_operand_val);
246
0
  }
247
0
    }
248
0
  else
249
0
    {
250
0
      int i = 1;
251
0
      xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
252
0
      (*info->fprintf_styled_func) (info->stream, dis_style_register,
253
0
            "%s%u",
254
0
            xtensa_regfile_shortname (isa, opnd_rf),
255
0
            operand_val);
256
0
      while (i < xtensa_operand_num_regs (isa, opc, opnd))
257
0
  {
258
0
    operand_val++;
259
0
    (*info->fprintf_styled_func) (info->stream, dis_style_register,
260
0
          ":%s%u",
261
0
          xtensa_regfile_shortname (isa, opnd_rf),
262
0
          operand_val);
263
0
    i++;
264
0
  }
265
0
    }
266
0
}
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
0
{
275
0
  unsigned operand_val;
276
0
  int bytes_fetched, size, maxsize, i, n, noperands, nslots;
277
0
  xtensa_isa isa;
278
0
  xtensa_opcode opc;
279
0
  xtensa_format fmt;
280
0
  static struct dis_private priv;
281
0
  static bfd_byte *byte_buf = NULL;
282
0
  static xtensa_insnbuf insn_buffer = NULL;
283
0
  static xtensa_insnbuf slot_buffer = NULL;
284
0
  int first, first_slot, valid_insn;
285
0
  property_table_entry *insn_block;
286
0
  enum dis_insn_type insn_type;
287
0
  bfd_vma target;
288
289
0
  if (!xtensa_default_isa)
290
0
    xtensa_default_isa = xtensa_isa_init (0, 0);
291
292
0
  info->target = 0;
293
0
  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
0
  info->bytes_per_line = MAX (maxsize, 4);
306
307
  /* Allocate buffers the first time through.  */
308
0
  if (!insn_buffer)
309
0
    {
310
0
      insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
311
0
      slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
312
0
      byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
313
0
    }
314
315
0
  priv.byte_buf = byte_buf;
316
317
0
  info->private_data = (void *) &priv;
318
319
  /* Prepare instruction tables.  */
320
321
0
  if (info->section != NULL)
322
0
    {
323
0
      asection *section = info->section;
324
325
0
      if (priv.last_section != section)
326
0
  {
327
0
    bfd *abfd = section->owner;
328
329
0
    if (priv.last_section != NULL)
330
0
      {
331
        /* Reset insn_table_entries.  */
332
0
        priv.insn_table_entry_count = 0;
333
0
        free (priv.insn_table_entries);
334
0
        priv.insn_table_entries = NULL;
335
0
      }
336
0
    priv.last_section = section;
337
338
    /* Read insn_table_entries.  */
339
0
    priv.insn_table_entry_count =
340
0
      xtensa_read_table_entries (abfd, section,
341
0
               &priv.insn_table_entries,
342
0
               XTENSA_PROP_SEC_NAME, false);
343
0
    if (priv.insn_table_entry_count == 0)
344
0
      {
345
0
        free (priv.insn_table_entries);
346
0
        priv.insn_table_entries = NULL;
347
        /* Backwards compatibility support.  */
348
0
        priv.insn_table_entry_count =
349
0
    xtensa_read_table_entries (abfd, section,
350
0
             &priv.insn_table_entries,
351
0
             XTENSA_INSN_SEC_NAME, false);
352
0
      }
353
0
    priv.insn_table_cur_idx = 0;
354
0
    xtensa_coalesce_insn_tables (&priv);
355
0
  }
356
      /* Else nothing to do, same section as last time.  */
357
0
    }
358
359
0
  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
360
      /* Error return.  */
361
0
      return -1;
362
363
  /* Fetch the maximum size instruction.  */
364
0
  bytes_fetched = fetch_data (info, memaddr);
365
366
0
  insn_block = xtensa_find_table_entry (memaddr, info);
367
368
  /* Don't set "isa" before the setjmp to keep the compiler from griping.  */
369
0
  isa = xtensa_default_isa;
370
0
  size = 0;
371
0
  nslots = 0;
372
0
  valid_insn = 0;
373
0
  fmt = 0;
374
0
  if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
375
0
    {
376
      /* Copy the bytes into the decode buffer.  */
377
0
      memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
378
0
             sizeof (xtensa_insnbuf_word)));
379
0
      xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf,
380
0
         bytes_fetched);
381
382
0
      fmt = xtensa_format_decode (isa, insn_buffer);
383
0
      if (fmt != XTENSA_UNDEFINED
384
0
    && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched)
385
0
    && xtensa_instruction_fits (memaddr, size, insn_block))
386
0
  {
387
    /* Make sure all the opcodes are valid.  */
388
0
    valid_insn = 1;
389
0
    nslots = xtensa_format_num_slots (isa, fmt);
390
0
    for (n = 0; n < nslots; n++)
391
0
      {
392
0
        xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
393
0
        if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
394
0
      == XTENSA_UNDEFINED)
395
0
    {
396
0
      valid_insn = 0;
397
0
      break;
398
0
    }
399
0
      }
400
0
  }
401
0
    }
402
403
0
  if (!valid_insn)
404
0
    {
405
0
      if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
406
0
    && (memaddr & 3) == 0 && bytes_fetched >= 4)
407
0
  {
408
0
    info->bytes_per_chunk = 4;
409
0
    return 4;
410
0
  }
411
0
      else
412
0
  {
413
0
    (*info->fprintf_styled_func) (info->stream,
414
0
          dis_style_assembler_directive,
415
0
          ".byte");
416
0
    (*info->fprintf_func) (info->stream, "\t");
417
0
    (*info->fprintf_styled_func) (info->stream,
418
0
          dis_style_immediate,
419
0
          "%#02x", priv.byte_buf[0]);
420
0
    return 1;
421
0
  }
422
0
    }
423
424
0
  if (nslots > 1)
425
0
    (*info->fprintf_func) (info->stream, "{ ");
426
427
0
  insn_type = dis_nonbranch;
428
0
  target = 0;
429
0
  first_slot = 1;
430
0
  for (n = 0; n < nslots; n++)
431
0
    {
432
0
      int imm_pcrel = 0;
433
434
0
      if (first_slot)
435
0
  first_slot = 0;
436
0
      else
437
0
  (*info->fprintf_func) (info->stream, "; ");
438
439
0
      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
440
0
      opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
441
0
      (*info->fprintf_styled_func) (info->stream,
442
0
            dis_style_mnemonic, "%s",
443
0
            xtensa_opcode_name (isa, opc));
444
445
0
      if (xtensa_opcode_is_branch (isa, opc))
446
0
  info->insn_type = dis_condbranch;
447
0
      else if (xtensa_opcode_is_jump (isa, opc))
448
0
  info->insn_type = dis_branch;
449
0
      else if (xtensa_opcode_is_call (isa, opc))
450
0
  info->insn_type = dis_jsr;
451
0
      else
452
0
  info->insn_type = dis_nonbranch;
453
454
      /* Print the operands (if any).  */
455
0
      noperands = xtensa_opcode_num_operands (isa, opc);
456
0
      first = 1;
457
0
      for (i = 0; i < noperands; i++)
458
0
  {
459
0
    if (xtensa_operand_is_visible (isa, opc, i) == 0)
460
0
      continue;
461
0
    if (first)
462
0
      {
463
0
        (*info->fprintf_func) (info->stream, "\t");
464
0
        first = 0;
465
0
      }
466
0
    else
467
0
      (*info->fprintf_func) (info->stream, ", ");
468
0
    (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
469
0
             slot_buffer, &operand_val);
470
471
0
    print_xtensa_operand (memaddr, info, opc, i, operand_val);
472
0
    if (xtensa_operand_is_PCrelative (isa, opc, i))
473
0
      ++imm_pcrel;
474
0
  }
475
0
      if (!imm_pcrel)
476
0
  info->insn_type = dis_nonbranch;
477
0
      if (info->insn_type != dis_nonbranch)
478
0
  {
479
0
    insn_type = info->insn_type;
480
0
    target = info->target;
481
0
  }
482
0
    }
483
0
  info->insn_type = insn_type;
484
0
  info->target = target;
485
0
  info->insn_info_valid = 1;
486
487
0
  if (nslots > 1)
488
0
    (*info->fprintf_func) (info->stream, " }");
489
490
0
  info->bytes_per_chunk = size;
491
0
  info->display_endian = info->endian;
492
493
0
  return size;
494
0
}
495