Home | History | Annotate | Download | only in opcodes
      1 /* Disassembler interface for targets using CGEN. -*- C -*-
      2    CGEN: Cpu tools GENerator
      3 
      4    THIS FILE IS MACHINE GENERATED WITH CGEN.
      5    - the resultant file is machine generated, cgen-dis.in isn't
      6 
      7    Copyright (C) 1996-2016 Free Software Foundation, Inc.
      8 
      9    This file is part of libopcodes.
     10 
     11    This library is free software; you can redistribute it and/or modify
     12    it under the terms of the GNU General Public License as published by
     13    the Free Software Foundation; either version 3, or (at your option)
     14    any later version.
     15 
     16    It is distributed in the hope that it will be useful, but WITHOUT
     17    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     18    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     19    License for more details.
     20 
     21    You should have received a copy of the GNU General Public License
     22    along with this program; if not, write to the Free Software Foundation, Inc.,
     23    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     24 
     25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     26    Keep that in mind.  */
     27 
     28 #include "sysdep.h"
     29 #include <stdio.h>
     30 #include "ansidecl.h"
     31 #include "dis-asm.h"
     32 #include "bfd.h"
     33 #include "symcat.h"
     34 #include "libiberty.h"
     35 #include "lm32-desc.h"
     36 #include "lm32-opc.h"
     37 #include "opintl.h"
     38 
     39 /* Default text to print if an instruction isn't recognized.  */
     40 #define UNKNOWN_INSN_MSG _("*unknown*")
     41 
     42 static void print_normal
     43   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
     44 static void print_address
     45   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
     46 static void print_keyword
     47   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
     48 static void print_insn_normal
     49   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
     50 static int print_insn
     51   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
     52 static int default_print_insn
     53   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
     54 static int read_insn
     55   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
     56    unsigned long *);
     57 
     58 /* -- disassembler routines inserted here.  */
     60 
     61 
     62 void lm32_cgen_print_operand
     63   (CGEN_CPU_DESC, int, PTR, 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       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
    148 	       opindex);
    149     abort ();
    150   }
    151 }
    152 
    153 cgen_print_fn * const lm32_cgen_print_handlers[] =
    154 {
    155   print_insn_normal,
    156 };
    157 
    158 
    159 void
    160 lm32_cgen_init_dis (CGEN_CPU_DESC cd)
    161 {
    162   lm32_cgen_init_opcode_table (cd);
    163   lm32_cgen_init_ibld_table (cd);
    164   cd->print_handlers = & lm32_cgen_print_handlers[0];
    165   cd->print_operand = lm32_cgen_print_operand;
    166 }
    167 
    168 
    169 /* 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.
    237 
    238    DIS_INFO is defined as `void *' so the disassembler needn't know anything
    239    about disassemble_info.  */
    240 
    241 static void
    242 print_insn_normal (CGEN_CPU_DESC cd,
    243 		   void *dis_info,
    244 		   const CGEN_INSN *insn,
    245 		   CGEN_FIELDS *fields,
    246 		   bfd_vma pc,
    247 		   int length)
    248 {
    249   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    250   disassemble_info *info = (disassemble_info *) dis_info;
    251   const CGEN_SYNTAX_CHAR_TYPE *syn;
    252 
    253   CGEN_INIT_PRINT (cd);
    254 
    255   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
    256     {
    257       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
    258 	{
    259 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
    260 	  continue;
    261 	}
    262       if (CGEN_SYNTAX_CHAR_P (*syn))
    263 	{
    264 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
    265 	  continue;
    266 	}
    267 
    268       /* We have an operand.  */
    269       lm32_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
    270 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
    271     }
    272 }
    273 
    274 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
    276    the extract info.
    277    Returns 0 if all is well, non-zero otherwise.  */
    278 
    279 static int
    280 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    281 	   bfd_vma pc,
    282 	   disassemble_info *info,
    283 	   bfd_byte *buf,
    284 	   int buflen,
    285 	   CGEN_EXTRACT_INFO *ex_info,
    286 	   unsigned long *insn_value)
    287 {
    288   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    289 
    290   if (status != 0)
    291     {
    292       (*info->memory_error_func) (status, pc, info);
    293       return -1;
    294     }
    295 
    296   ex_info->dis_info = info;
    297   ex_info->valid = (1 << buflen) - 1;
    298   ex_info->insn_bytes = buf;
    299 
    300   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    301   return 0;
    302 }
    303 
    304 /* Utility to print an insn.
    305    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    306    The result is the size of the insn in bytes or zero for an unknown insn
    307    or -1 if an error occurs fetching data (memory_error_func will have
    308    been called).  */
    309 
    310 static int
    311 print_insn (CGEN_CPU_DESC cd,
    312 	    bfd_vma pc,
    313 	    disassemble_info *info,
    314 	    bfd_byte *buf,
    315 	    unsigned int buflen)
    316 {
    317   CGEN_INSN_INT insn_value;
    318   const CGEN_INSN_LIST *insn_list;
    319   CGEN_EXTRACT_INFO ex_info;
    320   int basesize;
    321 
    322   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    323   basesize = cd->base_insn_bitsize < buflen * 8 ?
    324                                      cd->base_insn_bitsize : buflen * 8;
    325   insn_value = cgen_get_insn_value (cd, buf, basesize);
    326 
    327 
    328   /* Fill in ex_info fields like read_insn would.  Don't actually call
    329      read_insn, since the incoming buffer is already read (and possibly
    330      modified a la m32r).  */
    331   ex_info.valid = (1 << buflen) - 1;
    332   ex_info.dis_info = info;
    333   ex_info.insn_bytes = buf;
    334 
    335   /* The instructions are stored in hash lists.
    336      Pick the first one and keep trying until we find the right one.  */
    337 
    338   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    339   while (insn_list != NULL)
    340     {
    341       const CGEN_INSN *insn = insn_list->insn;
    342       CGEN_FIELDS fields;
    343       int length;
    344       unsigned long insn_value_cropped;
    345 
    346 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    347       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    348       /* Supported by this cpu?  */
    349       if (! lm32_cgen_insn_supported (cd, insn))
    350         {
    351           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    352 	  continue;
    353         }
    354 #endif
    355 
    356       /* Basic bit mask must be correct.  */
    357       /* ??? May wish to allow target to defer this check until the extract
    358 	 handler.  */
    359 
    360       /* Base size may exceed this instruction's size.  Extract the
    361          relevant part from the buffer. */
    362       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    363 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    364 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    365 					   info->endian == BFD_ENDIAN_BIG);
    366       else
    367 	insn_value_cropped = insn_value;
    368 
    369       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    370 	  == CGEN_INSN_BASE_VALUE (insn))
    371 	{
    372 	  /* Printing is handled in two passes.  The first pass parses the
    373 	     machine insn and extracts the fields.  The second pass prints
    374 	     them.  */
    375 
    376 	  /* Make sure the entire insn is loaded into insn_value, if it
    377 	     can fit.  */
    378 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    379 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    380 	    {
    381 	      unsigned long full_insn_value;
    382 	      int rc = read_insn (cd, pc, info, buf,
    383 				  CGEN_INSN_BITSIZE (insn) / 8,
    384 				  & ex_info, & full_insn_value);
    385 	      if (rc != 0)
    386 		return rc;
    387 	      length = CGEN_EXTRACT_FN (cd, insn)
    388 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    389 	    }
    390 	  else
    391 	    length = CGEN_EXTRACT_FN (cd, insn)
    392 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    393 
    394 	  /* Length < 0 -> error.  */
    395 	  if (length < 0)
    396 	    return length;
    397 	  if (length > 0)
    398 	    {
    399 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    400 	      /* Length is in bits, result is in bytes.  */
    401 	      return length / 8;
    402 	    }
    403 	}
    404 
    405       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    406     }
    407 
    408   return 0;
    409 }
    410 
    411 /* Default value for CGEN_PRINT_INSN.
    412    The result is the size of the insn in bytes or zero for an unknown insn
    413    or -1 if an error occured fetching bytes.  */
    414 
    415 #ifndef CGEN_PRINT_INSN
    416 #define CGEN_PRINT_INSN default_print_insn
    417 #endif
    418 
    419 static int
    420 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    421 {
    422   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    423   int buflen;
    424   int status;
    425 
    426   /* Attempt to read the base part of the insn.  */
    427   buflen = cd->base_insn_bitsize / 8;
    428   status = (*info->read_memory_func) (pc, buf, buflen, info);
    429 
    430   /* Try again with the minimum part, if min < base.  */
    431   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    432     {
    433       buflen = cd->min_insn_bitsize / 8;
    434       status = (*info->read_memory_func) (pc, buf, buflen, info);
    435     }
    436 
    437   if (status != 0)
    438     {
    439       (*info->memory_error_func) (status, pc, info);
    440       return -1;
    441     }
    442 
    443   return print_insn (cd, pc, info, buf, buflen);
    444 }
    445 
    446 /* Main entry point.
    447    Print one instruction from PC on INFO->STREAM.
    448    Return the size of the instruction (in bytes).  */
    449 
    450 typedef struct cpu_desc_list
    451 {
    452   struct cpu_desc_list *next;
    453   CGEN_BITSET *isa;
    454   int mach;
    455   int endian;
    456   CGEN_CPU_DESC cd;
    457 } cpu_desc_list;
    458 
    459 int
    460 print_insn_lm32 (bfd_vma pc, disassemble_info *info)
    461 {
    462   static cpu_desc_list *cd_list = 0;
    463   cpu_desc_list *cl = 0;
    464   static CGEN_CPU_DESC cd = 0;
    465   static CGEN_BITSET *prev_isa;
    466   static int prev_mach;
    467   static int prev_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   enum bfd_architecture arch;
    475 
    476   /* ??? gdb will set mach but leave the architecture as "unknown" */
    477 #ifndef CGEN_BFD_ARCH
    478 #define CGEN_BFD_ARCH bfd_arch_lm32
    479 #endif
    480   arch = info->arch;
    481   if (arch == bfd_arch_unknown)
    482     arch = CGEN_BFD_ARCH;
    483 
    484   /* There's no standard way to compute the machine or isa number
    485      so we leave it to the target.  */
    486 #ifdef CGEN_COMPUTE_MACH
    487   mach = CGEN_COMPUTE_MACH (info);
    488 #else
    489   mach = info->mach;
    490 #endif
    491 
    492 #ifdef CGEN_COMPUTE_ISA
    493   {
    494     static CGEN_BITSET *permanent_isa;
    495 
    496     if (!permanent_isa)
    497       permanent_isa = cgen_bitset_create (MAX_ISAS);
    498     isa = permanent_isa;
    499     cgen_bitset_clear (isa);
    500     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    501   }
    502 #else
    503   isa = info->insn_sets;
    504 #endif
    505 
    506   /* If we've switched cpu's, try to find a handle we've used before */
    507   if (cd
    508       && (cgen_bitset_compare (isa, prev_isa) != 0
    509 	  || mach != prev_mach
    510 	  || endian != prev_endian))
    511     {
    512       cd = 0;
    513       for (cl = cd_list; cl; cl = cl->next)
    514 	{
    515 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    516 	      cl->mach == mach &&
    517 	      cl->endian == endian)
    518 	    {
    519 	      cd = cl->cd;
    520  	      prev_isa = cd->isas;
    521 	      break;
    522 	    }
    523 	}
    524     }
    525 
    526   /* If we haven't initialized yet, initialize the opcode table.  */
    527   if (! cd)
    528     {
    529       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    530       const char *mach_name;
    531 
    532       if (!arch_type)
    533 	abort ();
    534       mach_name = arch_type->printable_name;
    535 
    536       prev_isa = cgen_bitset_copy (isa);
    537       prev_mach = mach;
    538       prev_endian = endian;
    539       cd = lm32_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    540 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    541 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    542 				 CGEN_CPU_OPEN_END);
    543       if (!cd)
    544 	abort ();
    545 
    546       /* Save this away for future reference.  */
    547       cl = xmalloc (sizeof (struct cpu_desc_list));
    548       cl->cd = cd;
    549       cl->isa = prev_isa;
    550       cl->mach = mach;
    551       cl->endian = endian;
    552       cl->next = cd_list;
    553       cd_list = cl;
    554 
    555       lm32_cgen_init_dis (cd);
    556     }
    557 
    558   /* We try to have as much common code as possible.
    559      But at this point some targets need to take over.  */
    560   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    561      but if not possible try to move this hook elsewhere rather than
    562      have two hooks.  */
    563   length = CGEN_PRINT_INSN (cd, pc, info);
    564   if (length > 0)
    565     return length;
    566   if (length < 0)
    567     return -1;
    568 
    569   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    570   return cd->default_insn_bitsize / 8;
    571 }
    572