(root)/
binutils-2.41/
opcodes/
lm32-dis.c
       1  /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
       2  /* Disassembler interface for targets using CGEN. -*- C -*-
       3     CGEN: Cpu tools GENerator
       4  
       5     THIS FILE IS MACHINE GENERATED WITH CGEN.
       6     - the resultant file is machine generated, cgen-dis.in isn't
       7  
       8     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       9  
      10     This file is part of libopcodes.
      11  
      12     This library is free software; you can redistribute it and/or modify
      13     it under the terms of the GNU General Public License as published by
      14     the Free Software Foundation; either version 3, or (at your option)
      15     any later version.
      16  
      17     It is distributed in the hope that it will be useful, but WITHOUT
      18     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      19     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      20     License for more details.
      21  
      22     You should have received a copy of the GNU General Public License
      23     along with this program; if not, write to the Free Software Foundation, Inc.,
      24     51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      25  
      26  /* ??? Eventually more and more of this stuff can go to cpu-independent files.
      27     Keep that in mind.  */
      28  
      29  #include "sysdep.h"
      30  #include <stdio.h>
      31  #include "ansidecl.h"
      32  #include "disassemble.h"
      33  #include "bfd.h"
      34  #include "symcat.h"
      35  #include "libiberty.h"
      36  #include "lm32-desc.h"
      37  #include "lm32-opc.h"
      38  #include "opintl.h"
      39  
      40  /* Default text to print if an instruction isn't recognized.  */
      41  #define UNKNOWN_INSN_MSG _("*unknown*")
      42  
      43  static void print_normal
      44    (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
      45  static void print_address
      46    (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
      47  static void print_keyword
      48    (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
      49  static void print_insn_normal
      50    (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
      51  static int print_insn
      52    (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
      53  static int default_print_insn
      54    (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
      55  static int read_insn
      56    (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
      57     unsigned long *);
      58  
      59  /* -- disassembler routines inserted here.  */
      60  
      61  
      62  void lm32_cgen_print_operand
      63    (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
      64  
      65  /* Main entry point for printing operands.
      66     XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
      67     of dis-asm.h on cgen.h.
      68  
      69     This function is basically just a big switch statement.  Earlier versions
      70     used tables to look up the function to use, but
      71     - if the table contains both assembler and disassembler functions then
      72       the disassembler contains much of the assembler and vice-versa,
      73     - there's a lot of inlining possibilities as things grow,
      74     - using a switch statement avoids the function call overhead.
      75  
      76     This function could be moved into `print_insn_normal', but keeping it
      77     separate makes clear the interface between `print_insn_normal' and each of
      78     the handlers.  */
      79  
      80  void
      81  lm32_cgen_print_operand (CGEN_CPU_DESC cd,
      82  			   int opindex,
      83  			   void * xinfo,
      84  			   CGEN_FIELDS *fields,
      85  			   void const *attrs ATTRIBUTE_UNUSED,
      86  			   bfd_vma pc,
      87  			   int length)
      88  {
      89    disassemble_info *info = (disassemble_info *) xinfo;
      90  
      91    switch (opindex)
      92      {
      93      case LM32_OPERAND_BRANCH :
      94        print_address (cd, info, fields->f_branch, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
      95        break;
      96      case LM32_OPERAND_CALL :
      97        print_address (cd, info, fields->f_call, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
      98        break;
      99      case LM32_OPERAND_CSR :
     100        print_keyword (cd, info, & lm32_cgen_opval_h_csr, fields->f_csr, 0);
     101        break;
     102      case LM32_OPERAND_EXCEPTION :
     103        print_normal (cd, info, fields->f_exception, 0, pc, length);
     104        break;
     105      case LM32_OPERAND_GOT16 :
     106        print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     107        break;
     108      case LM32_OPERAND_GOTOFFHI16 :
     109        print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     110        break;
     111      case LM32_OPERAND_GOTOFFLO16 :
     112        print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     113        break;
     114      case LM32_OPERAND_GP16 :
     115        print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     116        break;
     117      case LM32_OPERAND_HI16 :
     118        print_normal (cd, info, fields->f_uimm, 0, pc, length);
     119        break;
     120      case LM32_OPERAND_IMM :
     121        print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     122        break;
     123      case LM32_OPERAND_LO16 :
     124        print_normal (cd, info, fields->f_uimm, 0, pc, length);
     125        break;
     126      case LM32_OPERAND_R0 :
     127        print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r0, 0);
     128        break;
     129      case LM32_OPERAND_R1 :
     130        print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r1, 0);
     131        break;
     132      case LM32_OPERAND_R2 :
     133        print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r2, 0);
     134        break;
     135      case LM32_OPERAND_SHIFT :
     136        print_normal (cd, info, fields->f_shift, 0, pc, length);
     137        break;
     138      case LM32_OPERAND_UIMM :
     139        print_normal (cd, info, fields->f_uimm, 0, pc, length);
     140        break;
     141      case LM32_OPERAND_USER :
     142        print_normal (cd, info, fields->f_user, 0, pc, length);
     143        break;
     144  
     145      default :
     146        /* xgettext:c-format */
     147        opcodes_error_handler
     148  	(_("internal error: unrecognized field %d while printing insn"),
     149  	 opindex);
     150        abort ();
     151    }
     152  }
     153  
     154  cgen_print_fn * const lm32_cgen_print_handlers[] =
     155  {
     156    print_insn_normal,
     157  };
     158  
     159  
     160  void
     161  lm32_cgen_init_dis (CGEN_CPU_DESC cd)
     162  {
     163    lm32_cgen_init_opcode_table (cd);
     164    lm32_cgen_init_ibld_table (cd);
     165    cd->print_handlers = & lm32_cgen_print_handlers[0];
     166    cd->print_operand = lm32_cgen_print_operand;
     167  }
     168  
     169  
     170  /* Default print handler.  */
     171  
     172  static void
     173  print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     174  	      void *dis_info,
     175  	      long value,
     176  	      unsigned int attrs,
     177  	      bfd_vma pc ATTRIBUTE_UNUSED,
     178  	      int length ATTRIBUTE_UNUSED)
     179  {
     180    disassemble_info *info = (disassemble_info *) dis_info;
     181  
     182    /* Print the operand as directed by the attributes.  */
     183    if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     184      ; /* nothing to do */
     185    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
     186      (*info->fprintf_func) (info->stream, "%ld", value);
     187    else
     188      (*info->fprintf_func) (info->stream, "0x%lx", value);
     189  }
     190  
     191  /* Default address handler.  */
     192  
     193  static void
     194  print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     195  	       void *dis_info,
     196  	       bfd_vma value,
     197  	       unsigned int attrs,
     198  	       bfd_vma pc ATTRIBUTE_UNUSED,
     199  	       int length ATTRIBUTE_UNUSED)
     200  {
     201    disassemble_info *info = (disassemble_info *) dis_info;
     202  
     203    /* Print the operand as directed by the attributes.  */
     204    if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     205      ; /* Nothing to do.  */
     206    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
     207      (*info->print_address_func) (value, info);
     208    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
     209      (*info->print_address_func) (value, info);
     210    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
     211      (*info->fprintf_func) (info->stream, "%ld", (long) value);
     212    else
     213      (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
     214  }
     215  
     216  /* Keyword print handler.  */
     217  
     218  static void
     219  print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     220  	       void *dis_info,
     221  	       CGEN_KEYWORD *keyword_table,
     222  	       long value,
     223  	       unsigned int attrs ATTRIBUTE_UNUSED)
     224  {
     225    disassemble_info *info = (disassemble_info *) dis_info;
     226    const CGEN_KEYWORD_ENTRY *ke;
     227  
     228    ke = cgen_keyword_lookup_value (keyword_table, value);
     229    if (ke != NULL)
     230      (*info->fprintf_func) (info->stream, "%s", ke->name);
     231    else
     232      (*info->fprintf_func) (info->stream, "???");
     233  }
     234  
     235  /* Default insn printer.
     236  
     237     DIS_INFO is defined as `void *' so the disassembler needn't know anything
     238     about disassemble_info.  */
     239  
     240  static void
     241  print_insn_normal (CGEN_CPU_DESC cd,
     242  		   void *dis_info,
     243  		   const CGEN_INSN *insn,
     244  		   CGEN_FIELDS *fields,
     245  		   bfd_vma pc,
     246  		   int length)
     247  {
     248    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     249    disassemble_info *info = (disassemble_info *) dis_info;
     250    const CGEN_SYNTAX_CHAR_TYPE *syn;
     251  
     252    CGEN_INIT_PRINT (cd);
     253  
     254    for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
     255      {
     256        if (CGEN_SYNTAX_MNEMONIC_P (*syn))
     257  	{
     258  	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
     259  	  continue;
     260  	}
     261        if (CGEN_SYNTAX_CHAR_P (*syn))
     262  	{
     263  	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
     264  	  continue;
     265  	}
     266  
     267        /* We have an operand.  */
     268        lm32_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
     269  				 fields, CGEN_INSN_ATTRS (insn), pc, length);
     270      }
     271  }
     272  
     273  /* Subroutine of print_insn. Reads an insn into the given buffers and updates
     274     the extract info.
     275     Returns 0 if all is well, non-zero otherwise.  */
     276  
     277  static int
     278  read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     279  	   bfd_vma pc,
     280  	   disassemble_info *info,
     281  	   bfd_byte *buf,
     282  	   int buflen,
     283  	   CGEN_EXTRACT_INFO *ex_info,
     284  	   unsigned long *insn_value)
     285  {
     286    int status = (*info->read_memory_func) (pc, buf, buflen, info);
     287  
     288    if (status != 0)
     289      {
     290        (*info->memory_error_func) (status, pc, info);
     291        return -1;
     292      }
     293  
     294    ex_info->dis_info = info;
     295    ex_info->valid = (1 << buflen) - 1;
     296    ex_info->insn_bytes = buf;
     297  
     298    *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
     299    return 0;
     300  }
     301  
     302  /* Utility to print an insn.
     303     BUF is the base part of the insn, target byte order, BUFLEN bytes long.
     304     The result is the size of the insn in bytes or zero for an unknown insn
     305     or -1 if an error occurs fetching data (memory_error_func will have
     306     been called).  */
     307  
     308  static int
     309  print_insn (CGEN_CPU_DESC cd,
     310  	    bfd_vma pc,
     311  	    disassemble_info *info,
     312  	    bfd_byte *buf,
     313  	    unsigned int buflen)
     314  {
     315    CGEN_INSN_INT insn_value;
     316    const CGEN_INSN_LIST *insn_list;
     317    CGEN_EXTRACT_INFO ex_info;
     318    int basesize;
     319  
     320    /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
     321    basesize = cd->base_insn_bitsize < buflen * 8 ?
     322                                       cd->base_insn_bitsize : buflen * 8;
     323    insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
     324  
     325  
     326    /* Fill in ex_info fields like read_insn would.  Don't actually call
     327       read_insn, since the incoming buffer is already read (and possibly
     328       modified a la m32r).  */
     329    ex_info.valid = (1 << buflen) - 1;
     330    ex_info.dis_info = info;
     331    ex_info.insn_bytes = buf;
     332  
     333    /* The instructions are stored in hash lists.
     334       Pick the first one and keep trying until we find the right one.  */
     335  
     336    insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
     337    while (insn_list != NULL)
     338      {
     339        const CGEN_INSN *insn = insn_list->insn;
     340        CGEN_FIELDS fields;
     341        int length;
     342        unsigned long insn_value_cropped;
     343  
     344  #ifdef CGEN_VALIDATE_INSN_SUPPORTED
     345        /* Not needed as insn shouldn't be in hash lists if not supported.  */
     346        /* Supported by this cpu?  */
     347        if (! lm32_cgen_insn_supported (cd, insn))
     348          {
     349            insn_list = CGEN_DIS_NEXT_INSN (insn_list);
     350  	  continue;
     351          }
     352  #endif
     353  
     354        /* Basic bit mask must be correct.  */
     355        /* ??? May wish to allow target to defer this check until the extract
     356  	 handler.  */
     357  
     358        /* Base size may exceed this instruction's size.  Extract the
     359           relevant part from the buffer. */
     360        if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
     361  	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
     362  	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
     363  					   info->endian == BFD_ENDIAN_BIG);
     364        else
     365  	insn_value_cropped = insn_value;
     366  
     367        if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
     368  	  == CGEN_INSN_BASE_VALUE (insn))
     369  	{
     370  	  /* Printing is handled in two passes.  The first pass parses the
     371  	     machine insn and extracts the fields.  The second pass prints
     372  	     them.  */
     373  
     374  	  /* Make sure the entire insn is loaded into insn_value, if it
     375  	     can fit.  */
     376  	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
     377  	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
     378  	    {
     379  	      unsigned long full_insn_value;
     380  	      int rc = read_insn (cd, pc, info, buf,
     381  				  CGEN_INSN_BITSIZE (insn) / 8,
     382  				  & ex_info, & full_insn_value);
     383  	      if (rc != 0)
     384  		return rc;
     385  	      length = CGEN_EXTRACT_FN (cd, insn)
     386  		(cd, insn, &ex_info, full_insn_value, &fields, pc);
     387  	    }
     388  	  else
     389  	    length = CGEN_EXTRACT_FN (cd, insn)
     390  	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
     391  
     392  	  /* Length < 0 -> error.  */
     393  	  if (length < 0)
     394  	    return length;
     395  	  if (length > 0)
     396  	    {
     397  	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
     398  	      /* Length is in bits, result is in bytes.  */
     399  	      return length / 8;
     400  	    }
     401  	}
     402  
     403        insn_list = CGEN_DIS_NEXT_INSN (insn_list);
     404      }
     405  
     406    return 0;
     407  }
     408  
     409  /* Default value for CGEN_PRINT_INSN.
     410     The result is the size of the insn in bytes or zero for an unknown insn
     411     or -1 if an error occured fetching bytes.  */
     412  
     413  #ifndef CGEN_PRINT_INSN
     414  #define CGEN_PRINT_INSN default_print_insn
     415  #endif
     416  
     417  static int
     418  default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
     419  {
     420    bfd_byte buf[CGEN_MAX_INSN_SIZE];
     421    int buflen;
     422    int status;
     423  
     424    /* Attempt to read the base part of the insn.  */
     425    buflen = cd->base_insn_bitsize / 8;
     426    status = (*info->read_memory_func) (pc, buf, buflen, info);
     427  
     428    /* Try again with the minimum part, if min < base.  */
     429    if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
     430      {
     431        buflen = cd->min_insn_bitsize / 8;
     432        status = (*info->read_memory_func) (pc, buf, buflen, info);
     433      }
     434  
     435    if (status != 0)
     436      {
     437        (*info->memory_error_func) (status, pc, info);
     438        return -1;
     439      }
     440  
     441    return print_insn (cd, pc, info, buf, buflen);
     442  }
     443  
     444  /* Main entry point.
     445     Print one instruction from PC on INFO->STREAM.
     446     Return the size of the instruction (in bytes).  */
     447  
     448  typedef struct cpu_desc_list
     449  {
     450    struct cpu_desc_list *next;
     451    CGEN_BITSET *isa;
     452    int mach;
     453    int endian;
     454    int insn_endian;
     455    CGEN_CPU_DESC cd;
     456  } cpu_desc_list;
     457  
     458  int
     459  print_insn_lm32 (bfd_vma pc, disassemble_info *info)
     460  {
     461    static cpu_desc_list *cd_list = 0;
     462    cpu_desc_list *cl = 0;
     463    static CGEN_CPU_DESC cd = 0;
     464    static CGEN_BITSET *prev_isa;
     465    static int prev_mach;
     466    static int prev_endian;
     467    static int prev_insn_endian;
     468    int length;
     469    CGEN_BITSET *isa;
     470    int mach;
     471    int endian = (info->endian == BFD_ENDIAN_BIG
     472  		? CGEN_ENDIAN_BIG
     473  		: CGEN_ENDIAN_LITTLE);
     474    int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
     475                       ? CGEN_ENDIAN_BIG
     476                       : CGEN_ENDIAN_LITTLE);
     477    enum bfd_architecture arch;
     478  
     479    /* ??? gdb will set mach but leave the architecture as "unknown" */
     480  #ifndef CGEN_BFD_ARCH
     481  #define CGEN_BFD_ARCH bfd_arch_lm32
     482  #endif
     483    arch = info->arch;
     484    if (arch == bfd_arch_unknown)
     485      arch = CGEN_BFD_ARCH;
     486  
     487    /* There's no standard way to compute the machine or isa number
     488       so we leave it to the target.  */
     489  #ifdef CGEN_COMPUTE_MACH
     490    mach = CGEN_COMPUTE_MACH (info);
     491  #else
     492    mach = info->mach;
     493  #endif
     494  
     495  #ifdef CGEN_COMPUTE_ISA
     496    {
     497      static CGEN_BITSET *permanent_isa;
     498  
     499      if (!permanent_isa)
     500        permanent_isa = cgen_bitset_create (MAX_ISAS);
     501      isa = permanent_isa;
     502      cgen_bitset_clear (isa);
     503      cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
     504    }
     505  #else
     506    isa = info->private_data;
     507  #endif
     508  
     509    /* If we've switched cpu's, try to find a handle we've used before */
     510    if (cd
     511        && (cgen_bitset_compare (isa, prev_isa) != 0
     512  	  || mach != prev_mach
     513  	  || endian != prev_endian))
     514      {
     515        cd = 0;
     516        for (cl = cd_list; cl; cl = cl->next)
     517  	{
     518  	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
     519  	      cl->mach == mach &&
     520  	      cl->endian == endian)
     521  	    {
     522  	      cd = cl->cd;
     523   	      prev_isa = cd->isas;
     524  	      break;
     525  	    }
     526  	}
     527      }
     528  
     529    /* If we haven't initialized yet, initialize the opcode table.  */
     530    if (! cd)
     531      {
     532        const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
     533        const char *mach_name;
     534  
     535        if (!arch_type)
     536  	abort ();
     537        mach_name = arch_type->printable_name;
     538  
     539        prev_isa = cgen_bitset_copy (isa);
     540        prev_mach = mach;
     541        prev_endian = endian;
     542        prev_insn_endian = insn_endian;
     543        cd = lm32_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
     544  				 CGEN_CPU_OPEN_BFDMACH, mach_name,
     545  				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
     546                                   CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
     547  				 CGEN_CPU_OPEN_END);
     548        if (!cd)
     549  	abort ();
     550  
     551        /* Save this away for future reference.  */
     552        cl = xmalloc (sizeof (struct cpu_desc_list));
     553        cl->cd = cd;
     554        cl->isa = prev_isa;
     555        cl->mach = mach;
     556        cl->endian = endian;
     557        cl->next = cd_list;
     558        cd_list = cl;
     559  
     560        lm32_cgen_init_dis (cd);
     561      }
     562  
     563    /* We try to have as much common code as possible.
     564       But at this point some targets need to take over.  */
     565    /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
     566       but if not possible try to move this hook elsewhere rather than
     567       have two hooks.  */
     568    length = CGEN_PRINT_INSN (cd, pc, info);
     569    if (length > 0)
     570      return length;
     571    if (length < 0)
     572      return -1;
     573  
     574    (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
     575    return cd->default_insn_bitsize / 8;
     576  }