(root)/
binutils-2.41/
opcodes/
xtensa-dis.c
       1  /* xtensa-dis.c.  Disassembly functions for Xtensa.
       2     Copyright (C) 2003-2023 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, 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_styled_func) (info->stream, dis_style_immediate,
     242  					  "%d", signed_operand_val);
     243  	  else
     244  	    (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
     245  					  "0x%x", signed_operand_val);
     246  	}
     247      }
     248    else
     249      {
     250        int i = 1;
     251        xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
     252        (*info->fprintf_styled_func) (info->stream, dis_style_register,
     253  				    "%s%u",
     254  				    xtensa_regfile_shortname (isa, opnd_rf),
     255  				    operand_val);
     256        while (i < xtensa_operand_num_regs (isa, opc, opnd))
     257  	{
     258  	  operand_val++;
     259  	  (*info->fprintf_styled_func) (info->stream, dis_style_register,
     260  					":%s%u",
     261  					xtensa_regfile_shortname (isa, opnd_rf),
     262  					operand_val);
     263  	  i++;
     264  	}
     265      }
     266  }
     267  
     268  
     269  /* Print the Xtensa instruction at address MEMADDR on info->stream.
     270     Returns length of the instruction in bytes.  */
     271  
     272  int
     273  print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
     274  {
     275    unsigned operand_val;
     276    int bytes_fetched, size, maxsize, i, n, noperands, nslots;
     277    xtensa_isa isa;
     278    xtensa_opcode opc;
     279    xtensa_format fmt;
     280    static struct dis_private priv;
     281    static bfd_byte *byte_buf = NULL;
     282    static xtensa_insnbuf insn_buffer = NULL;
     283    static xtensa_insnbuf slot_buffer = NULL;
     284    int first, first_slot, valid_insn;
     285    property_table_entry *insn_block;
     286    enum dis_insn_type insn_type;
     287    bfd_vma target;
     288  
     289    if (!xtensa_default_isa)
     290      xtensa_default_isa = xtensa_isa_init (0, 0);
     291  
     292    info->target = 0;
     293    maxsize = xtensa_isa_maxlength (xtensa_default_isa);
     294  
     295    /* Set bytes_per_line to control the amount of whitespace between the hex
     296       values and the opcode.  For Xtensa, we always print one "chunk" and we
     297       vary bytes_per_chunk to determine how many bytes to print.  (objdump
     298       would apparently prefer that we set bytes_per_chunk to 1 and vary
     299       bytes_per_line but that makes it hard to fit 64-bit instructions on
     300       an 80-column screen.)  The value of bytes_per_line here is not exactly
     301       right, because objdump adds an extra space for each chunk so that the
     302       amount of whitespace depends on the chunk size.  Oh well, it's good
     303       enough....  Note that we set the minimum size to 4 to accomodate
     304       literal pools.  */
     305    info->bytes_per_line = MAX (maxsize, 4);
     306  
     307    /* Allocate buffers the first time through.  */
     308    if (!insn_buffer)
     309      {
     310        insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
     311        slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
     312        byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
     313      }
     314  
     315    priv.byte_buf = byte_buf;
     316  
     317    info->private_data = (void *) &priv;
     318  
     319    /* Prepare instruction tables.  */
     320  
     321    if (info->section != NULL)
     322      {
     323        asection *section = info->section;
     324  
     325        if (priv.last_section != section)
     326  	{
     327  	  bfd *abfd = section->owner;
     328  
     329  	  if (priv.last_section != NULL)
     330  	    {
     331  	      /* Reset insn_table_entries.  */
     332  	      priv.insn_table_entry_count = 0;
     333  	      free (priv.insn_table_entries);
     334  	      priv.insn_table_entries = NULL;
     335  	    }
     336  	  priv.last_section = section;
     337  
     338  	  /* Read insn_table_entries.  */
     339  	  priv.insn_table_entry_count =
     340  	    xtensa_read_table_entries (abfd, section,
     341  				       &priv.insn_table_entries,
     342  				       XTENSA_PROP_SEC_NAME, false);
     343  	  if (priv.insn_table_entry_count == 0)
     344  	    {
     345  	      free (priv.insn_table_entries);
     346  	      priv.insn_table_entries = NULL;
     347  	      /* Backwards compatibility support.  */
     348  	      priv.insn_table_entry_count =
     349  		xtensa_read_table_entries (abfd, section,
     350  					   &priv.insn_table_entries,
     351  					   XTENSA_INSN_SEC_NAME, false);
     352  	    }
     353  	  priv.insn_table_cur_idx = 0;
     354  	  xtensa_coalesce_insn_tables (&priv);
     355  	}
     356        /* Else nothing to do, same section as last time.  */
     357      }
     358  
     359    if (OPCODES_SIGSETJMP (priv.bailout) != 0)
     360        /* Error return.  */
     361        return -1;
     362  
     363    /* Fetch the maximum size instruction.  */
     364    bytes_fetched = fetch_data (info, memaddr);
     365  
     366    insn_block = xtensa_find_table_entry (memaddr, info);
     367  
     368    /* Don't set "isa" before the setjmp to keep the compiler from griping.  */
     369    isa = xtensa_default_isa;
     370    size = 0;
     371    nslots = 0;
     372    valid_insn = 0;
     373    fmt = 0;
     374    if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
     375      {
     376        /* Copy the bytes into the decode buffer.  */
     377        memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
     378  			       sizeof (xtensa_insnbuf_word)));
     379        xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf,
     380  				 bytes_fetched);
     381  
     382        fmt = xtensa_format_decode (isa, insn_buffer);
     383        if (fmt != XTENSA_UNDEFINED
     384  	  && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched)
     385  	  && xtensa_instruction_fits (memaddr, size, insn_block))
     386  	{
     387  	  /* Make sure all the opcodes are valid.  */
     388  	  valid_insn = 1;
     389  	  nslots = xtensa_format_num_slots (isa, fmt);
     390  	  for (n = 0; n < nslots; n++)
     391  	    {
     392  	      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
     393  	      if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
     394  		  == XTENSA_UNDEFINED)
     395  		{
     396  		  valid_insn = 0;
     397  		  break;
     398  		}
     399  	    }
     400  	}
     401      }
     402  
     403    if (!valid_insn)
     404      {
     405        if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
     406  	  && (memaddr & 3) == 0 && bytes_fetched >= 4)
     407  	{
     408  	  info->bytes_per_chunk = 4;
     409  	  return 4;
     410  	}
     411        else
     412  	{
     413  	  (*info->fprintf_styled_func) (info->stream,
     414  					dis_style_assembler_directive,
     415  					".byte");
     416  	  (*info->fprintf_func) (info->stream, "\t");
     417  	  (*info->fprintf_styled_func) (info->stream,
     418  					dis_style_immediate,
     419  					"%#02x", priv.byte_buf[0]);
     420  	  return 1;
     421  	}
     422      }
     423  
     424    if (nslots > 1)
     425      (*info->fprintf_func) (info->stream, "{ ");
     426  
     427    insn_type = dis_nonbranch;
     428    target = 0;
     429    first_slot = 1;
     430    for (n = 0; n < nslots; n++)
     431      {
     432        int imm_pcrel = 0;
     433  
     434        if (first_slot)
     435  	first_slot = 0;
     436        else
     437  	(*info->fprintf_func) (info->stream, "; ");
     438  
     439        xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
     440        opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
     441        (*info->fprintf_styled_func) (info->stream,
     442  				    dis_style_mnemonic, "%s",
     443  				    xtensa_opcode_name (isa, opc));
     444  
     445        if (xtensa_opcode_is_branch (isa, opc))
     446  	info->insn_type = dis_condbranch;
     447        else if (xtensa_opcode_is_jump (isa, opc))
     448  	info->insn_type = dis_branch;
     449        else if (xtensa_opcode_is_call (isa, opc))
     450  	info->insn_type = dis_jsr;
     451        else
     452  	info->insn_type = dis_nonbranch;
     453  
     454        /* Print the operands (if any).  */
     455        noperands = xtensa_opcode_num_operands (isa, opc);
     456        first = 1;
     457        for (i = 0; i < noperands; i++)
     458  	{
     459  	  if (xtensa_operand_is_visible (isa, opc, i) == 0)
     460  	    continue;
     461  	  if (first)
     462  	    {
     463  	      (*info->fprintf_func) (info->stream, "\t");
     464  	      first = 0;
     465  	    }
     466  	  else
     467  	    (*info->fprintf_func) (info->stream, ", ");
     468  	  (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
     469  					   slot_buffer, &operand_val);
     470  
     471  	  print_xtensa_operand (memaddr, info, opc, i, operand_val);
     472  	  if (xtensa_operand_is_PCrelative (isa, opc, i))
     473  	    ++imm_pcrel;
     474  	}
     475        if (!imm_pcrel)
     476  	info->insn_type = dis_nonbranch;
     477        if (info->insn_type != dis_nonbranch)
     478  	{
     479  	  insn_type = info->insn_type;
     480  	  target = info->target;
     481  	}
     482      }
     483    info->insn_type = insn_type;
     484    info->target = target;
     485    info->insn_info_valid = 1;
     486  
     487    if (nslots > 1)
     488      (*info->fprintf_func) (info->stream, " }");
     489  
     490    info->bytes_per_chunk = size;
     491    info->display_endian = info->endian;
     492  
     493    return size;
     494  }
     495