1 /* xtensa-dis.c.  Disassembly functions for Xtensa.
2    Copyright (C) 2003-2021 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
xtensa_coalesce_insn_tables(struct dis_private * priv)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 *
xtensa_find_table_entry(bfd_vma memaddr,struct disassemble_info * info)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
xtensa_instruction_fits(bfd_vma memaddr,int size,property_table_entry * insn_block)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
fetch_data(struct disassemble_info * info,bfd_vma memaddr)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
print_xtensa_operand(bfd_vma memaddr,struct disassemble_info * info,xtensa_opcode opc,int opnd,unsigned operand_val)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, 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 
268 int
print_insn_xtensa(bfd_vma memaddr,struct disassemble_info * info)269 print_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