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