xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/xtensa-dis.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* xtensa-dis.c.  Disassembly functions for Xtensa.
2    Copyright (C) 2003-2020 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 #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 {
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 
98 static property_table_entry *
99 xtensa_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 
134 static int
135 xtensa_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 
162 static int
163 fetch_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 
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 {
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 
250 int
251 print_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