1/* xtensa-dis.c.  Disassembly functions for Xtensa.
2   Copyright (C) 2003-2017 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 "dis-asm.h"
31
32#include <setjmp.h>
33
34extern xtensa_isa xtensa_default_isa;
35
36#ifndef MAX
37#define MAX(a,b) (a > b ? a : b)
38#endif
39
40int show_raw_fields;
41
42struct dis_private
43{
44  bfd_byte *byte_buf;
45  OPCODES_SIGJMP_BUF bailout;
46};
47
48
49static int
50fetch_data (struct disassemble_info *info, bfd_vma memaddr)
51{
52  int length, status = 0;
53  struct dis_private *priv = (struct dis_private *) info->private_data;
54  int insn_size = xtensa_isa_maxlength (xtensa_default_isa);
55
56  /* Read the maximum instruction size, padding with zeros if we go past
57     the end of the text section.  This code will automatically adjust
58     length when we hit the end of the buffer.  */
59
60  memset (priv->byte_buf, 0, insn_size);
61  for (length = insn_size; length > 0; length--)
62    {
63      status = (*info->read_memory_func) (memaddr, priv->byte_buf, length,
64					  info);
65      if (status == 0)
66	return length;
67    }
68  (*info->memory_error_func) (status, memaddr, info);
69  OPCODES_SIGLONGJMP (priv->bailout, 1);
70  /*NOTREACHED*/
71}
72
73
74static void
75print_xtensa_operand (bfd_vma memaddr,
76		      struct disassemble_info *info,
77		      xtensa_opcode opc,
78		      int opnd,
79		      unsigned operand_val)
80{
81  xtensa_isa isa = xtensa_default_isa;
82  int signed_operand_val;
83
84  if (show_raw_fields)
85    {
86      if (operand_val < 0xa)
87	(*info->fprintf_func) (info->stream, "%u", operand_val);
88      else
89	(*info->fprintf_func) (info->stream, "0x%x", operand_val);
90      return;
91    }
92
93  (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
94  signed_operand_val = (int) operand_val;
95
96  if (xtensa_operand_is_register (isa, opc, opnd) == 0)
97    {
98      if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
99	{
100	  (void) xtensa_operand_undo_reloc (isa, opc, opnd,
101					    &operand_val, memaddr);
102	  info->target = operand_val;
103	  (*info->print_address_func) (info->target, info);
104	}
105      else
106	{
107	  if ((signed_operand_val > -256) && (signed_operand_val < 256))
108	    (*info->fprintf_func) (info->stream, "%d", signed_operand_val);
109	  else
110	    (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val);
111	}
112    }
113  else
114    {
115      int i = 1;
116      xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
117      (*info->fprintf_func) (info->stream, "%s%u",
118			     xtensa_regfile_shortname (isa, opnd_rf),
119			     operand_val);
120      while (i < xtensa_operand_num_regs (isa, opc, opnd))
121	{
122	  operand_val++;
123	  (*info->fprintf_func) (info->stream, ":%s%u",
124				 xtensa_regfile_shortname (isa, opnd_rf),
125				 operand_val);
126	  i++;
127	}
128    }
129}
130
131
132/* Print the Xtensa instruction at address MEMADDR on info->stream.
133   Returns length of the instruction in bytes.  */
134
135int
136print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
137{
138  unsigned operand_val;
139  int bytes_fetched, size, maxsize, i, n, noperands, nslots;
140  xtensa_isa isa;
141  xtensa_opcode opc;
142  xtensa_format fmt;
143  struct dis_private priv;
144  static bfd_byte *byte_buf = NULL;
145  static xtensa_insnbuf insn_buffer = NULL;
146  static xtensa_insnbuf slot_buffer = NULL;
147  int first, first_slot, valid_insn;
148
149  if (!xtensa_default_isa)
150    xtensa_default_isa = xtensa_isa_init (0, 0);
151
152  info->target = 0;
153  maxsize = xtensa_isa_maxlength (xtensa_default_isa);
154
155  /* Set bytes_per_line to control the amount of whitespace between the hex
156     values and the opcode.  For Xtensa, we always print one "chunk" and we
157     vary bytes_per_chunk to determine how many bytes to print.  (objdump
158     would apparently prefer that we set bytes_per_chunk to 1 and vary
159     bytes_per_line but that makes it hard to fit 64-bit instructions on
160     an 80-column screen.)  The value of bytes_per_line here is not exactly
161     right, because objdump adds an extra space for each chunk so that the
162     amount of whitespace depends on the chunk size.  Oh well, it's good
163     enough....  Note that we set the minimum size to 4 to accomodate
164     literal pools.  */
165  info->bytes_per_line = MAX (maxsize, 4);
166
167  /* Allocate buffers the first time through.  */
168  if (!insn_buffer)
169    {
170      insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
171      slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
172      byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
173    }
174
175  priv.byte_buf = byte_buf;
176
177  info->private_data = (void *) &priv;
178  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
179      /* Error return.  */
180      return -1;
181
182  /* Don't set "isa" before the setjmp to keep the compiler from griping.  */
183  isa = xtensa_default_isa;
184  size = 0;
185  nslots = 0;
186
187  /* Fetch the maximum size instruction.  */
188  bytes_fetched = fetch_data (info, memaddr);
189
190  /* Copy the bytes into the decode buffer.  */
191  memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
192			   sizeof (xtensa_insnbuf_word)));
193  xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, bytes_fetched);
194
195  fmt = xtensa_format_decode (isa, insn_buffer);
196  if (fmt == XTENSA_UNDEFINED
197      || ((size = xtensa_format_length (isa, fmt)) > bytes_fetched))
198    valid_insn = 0;
199  else
200    {
201      /* Make sure all the opcodes are valid.  */
202      valid_insn = 1;
203      nslots = xtensa_format_num_slots (isa, fmt);
204      for (n = 0; n < nslots; n++)
205	{
206	  xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
207	  if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
208	      == XTENSA_UNDEFINED)
209	    {
210	      valid_insn = 0;
211	      break;
212	    }
213	}
214    }
215
216  if (!valid_insn)
217    {
218      (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]);
219      return 1;
220    }
221
222  if (nslots > 1)
223    (*info->fprintf_func) (info->stream, "{ ");
224
225  first_slot = 1;
226  for (n = 0; n < nslots; n++)
227    {
228      if (first_slot)
229	first_slot = 0;
230      else
231	(*info->fprintf_func) (info->stream, "; ");
232
233      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
234      opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
235      (*info->fprintf_func) (info->stream, "%s",
236			     xtensa_opcode_name (isa, opc));
237
238      /* Print the operands (if any).  */
239      noperands = xtensa_opcode_num_operands (isa, opc);
240      first = 1;
241      for (i = 0; i < noperands; i++)
242	{
243	  if (xtensa_operand_is_visible (isa, opc, i) == 0)
244	    continue;
245	  if (first)
246	    {
247	      (*info->fprintf_func) (info->stream, "\t");
248	      first = 0;
249	    }
250	  else
251	    (*info->fprintf_func) (info->stream, ", ");
252	  (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
253					   slot_buffer, &operand_val);
254
255	  print_xtensa_operand (memaddr, info, opc, i, operand_val);
256	}
257    }
258
259  if (nslots > 1)
260    (*info->fprintf_func) (info->stream, " }");
261
262  info->bytes_per_chunk = size;
263  info->display_endian = info->endian;
264
265  return size;
266}
267
268