xtensa-dis.c revision 1.6
1/* xtensa-dis.c.  Disassembly functions for Xtensa.
2   Copyright (C) 2003-2018 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;
198
199  if (show_raw_fields)
200    {
201      if (operand_val < 0xa)
202	(*info->fprintf_func) (info->stream, "%u", operand_val);
203      else
204	(*info->fprintf_func) (info->stream, "0x%x", operand_val);
205      return;
206    }
207
208  (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
209  signed_operand_val = (int) operand_val;
210
211  if (xtensa_operand_is_register (isa, opc, opnd) == 0)
212    {
213      if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
214	{
215	  (void) xtensa_operand_undo_reloc (isa, opc, opnd,
216					    &operand_val, memaddr);
217	  info->target = operand_val;
218	  (*info->print_address_func) (info->target, info);
219	}
220      else
221	{
222	  if ((signed_operand_val > -256) && (signed_operand_val < 256))
223	    (*info->fprintf_func) (info->stream, "%d", signed_operand_val);
224	  else
225	    (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val);
226	}
227    }
228  else
229    {
230      int i = 1;
231      xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
232      (*info->fprintf_func) (info->stream, "%s%u",
233			     xtensa_regfile_shortname (isa, opnd_rf),
234			     operand_val);
235      while (i < xtensa_operand_num_regs (isa, opc, opnd))
236	{
237	  operand_val++;
238	  (*info->fprintf_func) (info->stream, ":%s%u",
239				 xtensa_regfile_shortname (isa, opnd_rf),
240				 operand_val);
241	  i++;
242	}
243    }
244}
245
246
247/* Print the Xtensa instruction at address MEMADDR on info->stream.
248   Returns length of the instruction in bytes.  */
249
250int
251print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
252{
253  unsigned operand_val;
254  int bytes_fetched, size, maxsize, i, n, noperands, nslots;
255  xtensa_isa isa;
256  xtensa_opcode opc;
257  xtensa_format fmt;
258  static struct dis_private priv;
259  static bfd_byte *byte_buf = NULL;
260  static xtensa_insnbuf insn_buffer = NULL;
261  static xtensa_insnbuf slot_buffer = NULL;
262  int first, first_slot, valid_insn;
263  property_table_entry *insn_block;
264
265  if (!xtensa_default_isa)
266    xtensa_default_isa = xtensa_isa_init (0, 0);
267
268  info->target = 0;
269  maxsize = xtensa_isa_maxlength (xtensa_default_isa);
270
271  /* Set bytes_per_line to control the amount of whitespace between the hex
272     values and the opcode.  For Xtensa, we always print one "chunk" and we
273     vary bytes_per_chunk to determine how many bytes to print.  (objdump
274     would apparently prefer that we set bytes_per_chunk to 1 and vary
275     bytes_per_line but that makes it hard to fit 64-bit instructions on
276     an 80-column screen.)  The value of bytes_per_line here is not exactly
277     right, because objdump adds an extra space for each chunk so that the
278     amount of whitespace depends on the chunk size.  Oh well, it's good
279     enough....  Note that we set the minimum size to 4 to accomodate
280     literal pools.  */
281  info->bytes_per_line = MAX (maxsize, 4);
282
283  /* Allocate buffers the first time through.  */
284  if (!insn_buffer)
285    {
286      insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
287      slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
288      byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
289    }
290
291  priv.byte_buf = byte_buf;
292
293  info->private_data = (void *) &priv;
294
295  /* Prepare instruction tables.  */
296
297  if (info->section != NULL)
298    {
299      asection *section = info->section;
300
301      if (priv.last_section != section)
302	{
303	  bfd *abfd = section->owner;
304
305	  if (priv.last_section != NULL)
306	    {
307	      /* Reset insn_table_entries.  */
308	      priv.insn_table_entry_count = 0;
309	      if (priv.insn_table_entries)
310		free (priv.insn_table_entries);
311	      priv.insn_table_entries = NULL;
312	    }
313	  priv.last_section = section;
314
315	  /* Read insn_table_entries.  */
316	  priv.insn_table_entry_count =
317	    xtensa_read_table_entries (abfd, section,
318				       &priv.insn_table_entries,
319				       XTENSA_PROP_SEC_NAME, FALSE);
320	  if (priv.insn_table_entry_count == 0)
321	    {
322	      if (priv.insn_table_entries)
323		free (priv.insn_table_entries);
324	      priv.insn_table_entries = NULL;
325	      /* Backwards compatibility support.  */
326	      priv.insn_table_entry_count =
327		xtensa_read_table_entries (abfd, section,
328					   &priv.insn_table_entries,
329					   XTENSA_INSN_SEC_NAME, FALSE);
330	    }
331	  priv.insn_table_cur_idx = 0;
332	  xtensa_coalesce_insn_tables (&priv);
333	}
334      /* Else nothing to do, same section as last time.  */
335    }
336
337  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
338      /* Error return.  */
339      return -1;
340
341  /* Fetch the maximum size instruction.  */
342  bytes_fetched = fetch_data (info, memaddr);
343
344  insn_block = xtensa_find_table_entry (memaddr, info);
345
346  /* Don't set "isa" before the setjmp to keep the compiler from griping.  */
347  isa = xtensa_default_isa;
348  size = 0;
349  nslots = 0;
350  valid_insn = 0;
351  fmt = 0;
352  if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
353    {
354      /* Copy the bytes into the decode buffer.  */
355      memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
356			       sizeof (xtensa_insnbuf_word)));
357      xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf,
358				 bytes_fetched);
359
360      fmt = xtensa_format_decode (isa, insn_buffer);
361      if (fmt != XTENSA_UNDEFINED
362	  && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched)
363	  && xtensa_instruction_fits (memaddr, size, insn_block))
364	{
365	  /* Make sure all the opcodes are valid.  */
366	  valid_insn = 1;
367	  nslots = xtensa_format_num_slots (isa, fmt);
368	  for (n = 0; n < nslots; n++)
369	    {
370	      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
371	      if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
372		  == XTENSA_UNDEFINED)
373		{
374		  valid_insn = 0;
375		  break;
376		}
377	    }
378	}
379    }
380
381  if (!valid_insn)
382    {
383      if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
384	  && (memaddr & 3) == 0 && bytes_fetched >= 4)
385	{
386	  return 4;
387	}
388      else
389	{
390	  (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]);
391	  return 1;
392	}
393    }
394
395  if (nslots > 1)
396    (*info->fprintf_func) (info->stream, "{ ");
397
398  first_slot = 1;
399  for (n = 0; n < nslots; n++)
400    {
401      if (first_slot)
402	first_slot = 0;
403      else
404	(*info->fprintf_func) (info->stream, "; ");
405
406      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
407      opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
408      (*info->fprintf_func) (info->stream, "%s",
409			     xtensa_opcode_name (isa, opc));
410
411      /* Print the operands (if any).  */
412      noperands = xtensa_opcode_num_operands (isa, opc);
413      first = 1;
414      for (i = 0; i < noperands; i++)
415	{
416	  if (xtensa_operand_is_visible (isa, opc, i) == 0)
417	    continue;
418	  if (first)
419	    {
420	      (*info->fprintf_func) (info->stream, "\t");
421	      first = 0;
422	    }
423	  else
424	    (*info->fprintf_func) (info->stream, ", ");
425	  (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
426					   slot_buffer, &operand_val);
427
428	  print_xtensa_operand (memaddr, info, opc, i, operand_val);
429	}
430    }
431
432  if (nslots > 1)
433    (*info->fprintf_func) (info->stream, " }");
434
435  info->bytes_per_chunk = size;
436  info->display_endian = info->endian;
437
438  return size;
439}
440
441