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 "or1k-desc.h"
     36 #include "or1k-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 or1k_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 or1k_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 OR1K_OPERAND_DISP26 :
     94       print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
     95       break;
     96     case OR1K_OPERAND_RA :
     97       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r2, 0);
     98       break;
     99     case OR1K_OPERAND_RADF :
    100       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
    101       break;
    102     case OR1K_OPERAND_RASF :
    103       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r2, 0);
    104       break;
    105     case OR1K_OPERAND_RB :
    106       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r3, 0);
    107       break;
    108     case OR1K_OPERAND_RBDF :
    109       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
    110       break;
    111     case OR1K_OPERAND_RBSF :
    112       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r3, 0);
    113       break;
    114     case OR1K_OPERAND_RD :
    115       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r1, 0);
    116       break;
    117     case OR1K_OPERAND_RDDF :
    118       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
    119       break;
    120     case OR1K_OPERAND_RDSF :
    121       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r1, 0);
    122       break;
    123     case OR1K_OPERAND_SIMM16 :
    124       print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
    125       break;
    126     case OR1K_OPERAND_SIMM16_SPLIT :
    127       print_normal (cd, info, fields->f_simm16_split, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
    128       break;
    129     case OR1K_OPERAND_UIMM16 :
    130       print_normal (cd, info, fields->f_uimm16, 0, pc, length);
    131       break;
    132     case OR1K_OPERAND_UIMM16_SPLIT :
    133       print_normal (cd, info, fields->f_uimm16_split, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
    134       break;
    135     case OR1K_OPERAND_UIMM6 :
    136       print_normal (cd, info, fields->f_uimm6, 0, pc, length);
    137       break;
    138 
    139     default :
    140       /* xgettext:c-format */
    141       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
    142 	       opindex);
    143     abort ();
    144   }
    145 }
    146 
    147 cgen_print_fn * const or1k_cgen_print_handlers[] =
    148 {
    149   print_insn_normal,
    150 };
    151 
    152 
    153 void
    154 or1k_cgen_init_dis (CGEN_CPU_DESC cd)
    155 {
    156   or1k_cgen_init_opcode_table (cd);
    157   or1k_cgen_init_ibld_table (cd);
    158   cd->print_handlers = & or1k_cgen_print_handlers[0];
    159   cd->print_operand = or1k_cgen_print_operand;
    160 }
    161 
    162 
    163 /* Default print handler.  */
    165 
    166 static void
    167 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    168 	      void *dis_info,
    169 	      long value,
    170 	      unsigned int attrs,
    171 	      bfd_vma pc ATTRIBUTE_UNUSED,
    172 	      int length ATTRIBUTE_UNUSED)
    173 {
    174   disassemble_info *info = (disassemble_info *) dis_info;
    175 
    176   /* Print the operand as directed by the attributes.  */
    177   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    178     ; /* nothing to do */
    179   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    180     (*info->fprintf_func) (info->stream, "%ld", value);
    181   else
    182     (*info->fprintf_func) (info->stream, "0x%lx", value);
    183 }
    184 
    185 /* Default address handler.  */
    186 
    187 static void
    188 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    189 	       void *dis_info,
    190 	       bfd_vma value,
    191 	       unsigned int attrs,
    192 	       bfd_vma pc ATTRIBUTE_UNUSED,
    193 	       int length ATTRIBUTE_UNUSED)
    194 {
    195   disassemble_info *info = (disassemble_info *) dis_info;
    196 
    197   /* Print the operand as directed by the attributes.  */
    198   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    199     ; /* Nothing to do.  */
    200   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
    201     (*info->print_address_func) (value, info);
    202   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
    203     (*info->print_address_func) (value, info);
    204   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    205     (*info->fprintf_func) (info->stream, "%ld", (long) value);
    206   else
    207     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
    208 }
    209 
    210 /* Keyword print handler.  */
    211 
    212 static void
    213 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    214 	       void *dis_info,
    215 	       CGEN_KEYWORD *keyword_table,
    216 	       long value,
    217 	       unsigned int attrs ATTRIBUTE_UNUSED)
    218 {
    219   disassemble_info *info = (disassemble_info *) dis_info;
    220   const CGEN_KEYWORD_ENTRY *ke;
    221 
    222   ke = cgen_keyword_lookup_value (keyword_table, value);
    223   if (ke != NULL)
    224     (*info->fprintf_func) (info->stream, "%s", ke->name);
    225   else
    226     (*info->fprintf_func) (info->stream, "???");
    227 }
    228 
    229 /* Default insn printer.
    231 
    232    DIS_INFO is defined as `void *' so the disassembler needn't know anything
    233    about disassemble_info.  */
    234 
    235 static void
    236 print_insn_normal (CGEN_CPU_DESC cd,
    237 		   void *dis_info,
    238 		   const CGEN_INSN *insn,
    239 		   CGEN_FIELDS *fields,
    240 		   bfd_vma pc,
    241 		   int length)
    242 {
    243   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    244   disassemble_info *info = (disassemble_info *) dis_info;
    245   const CGEN_SYNTAX_CHAR_TYPE *syn;
    246 
    247   CGEN_INIT_PRINT (cd);
    248 
    249   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
    250     {
    251       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
    252 	{
    253 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
    254 	  continue;
    255 	}
    256       if (CGEN_SYNTAX_CHAR_P (*syn))
    257 	{
    258 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
    259 	  continue;
    260 	}
    261 
    262       /* We have an operand.  */
    263       or1k_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
    264 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
    265     }
    266 }
    267 
    268 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
    270    the extract info.
    271    Returns 0 if all is well, non-zero otherwise.  */
    272 
    273 static int
    274 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    275 	   bfd_vma pc,
    276 	   disassemble_info *info,
    277 	   bfd_byte *buf,
    278 	   int buflen,
    279 	   CGEN_EXTRACT_INFO *ex_info,
    280 	   unsigned long *insn_value)
    281 {
    282   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    283 
    284   if (status != 0)
    285     {
    286       (*info->memory_error_func) (status, pc, info);
    287       return -1;
    288     }
    289 
    290   ex_info->dis_info = info;
    291   ex_info->valid = (1 << buflen) - 1;
    292   ex_info->insn_bytes = buf;
    293 
    294   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    295   return 0;
    296 }
    297 
    298 /* Utility to print an insn.
    299    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    300    The result is the size of the insn in bytes or zero for an unknown insn
    301    or -1 if an error occurs fetching data (memory_error_func will have
    302    been called).  */
    303 
    304 static int
    305 print_insn (CGEN_CPU_DESC cd,
    306 	    bfd_vma pc,
    307 	    disassemble_info *info,
    308 	    bfd_byte *buf,
    309 	    unsigned int buflen)
    310 {
    311   CGEN_INSN_INT insn_value;
    312   const CGEN_INSN_LIST *insn_list;
    313   CGEN_EXTRACT_INFO ex_info;
    314   int basesize;
    315 
    316   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    317   basesize = cd->base_insn_bitsize < buflen * 8 ?
    318                                      cd->base_insn_bitsize : buflen * 8;
    319   insn_value = cgen_get_insn_value (cd, buf, basesize);
    320 
    321 
    322   /* Fill in ex_info fields like read_insn would.  Don't actually call
    323      read_insn, since the incoming buffer is already read (and possibly
    324      modified a la m32r).  */
    325   ex_info.valid = (1 << buflen) - 1;
    326   ex_info.dis_info = info;
    327   ex_info.insn_bytes = buf;
    328 
    329   /* The instructions are stored in hash lists.
    330      Pick the first one and keep trying until we find the right one.  */
    331 
    332   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    333   while (insn_list != NULL)
    334     {
    335       const CGEN_INSN *insn = insn_list->insn;
    336       CGEN_FIELDS fields;
    337       int length;
    338       unsigned long insn_value_cropped;
    339 
    340 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    341       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    342       /* Supported by this cpu?  */
    343       if (! or1k_cgen_insn_supported (cd, insn))
    344         {
    345           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    346 	  continue;
    347         }
    348 #endif
    349 
    350       /* Basic bit mask must be correct.  */
    351       /* ??? May wish to allow target to defer this check until the extract
    352 	 handler.  */
    353 
    354       /* Base size may exceed this instruction's size.  Extract the
    355          relevant part from the buffer. */
    356       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    357 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    358 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    359 					   info->endian == BFD_ENDIAN_BIG);
    360       else
    361 	insn_value_cropped = insn_value;
    362 
    363       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    364 	  == CGEN_INSN_BASE_VALUE (insn))
    365 	{
    366 	  /* Printing is handled in two passes.  The first pass parses the
    367 	     machine insn and extracts the fields.  The second pass prints
    368 	     them.  */
    369 
    370 	  /* Make sure the entire insn is loaded into insn_value, if it
    371 	     can fit.  */
    372 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    373 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    374 	    {
    375 	      unsigned long full_insn_value;
    376 	      int rc = read_insn (cd, pc, info, buf,
    377 				  CGEN_INSN_BITSIZE (insn) / 8,
    378 				  & ex_info, & full_insn_value);
    379 	      if (rc != 0)
    380 		return rc;
    381 	      length = CGEN_EXTRACT_FN (cd, insn)
    382 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    383 	    }
    384 	  else
    385 	    length = CGEN_EXTRACT_FN (cd, insn)
    386 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    387 
    388 	  /* Length < 0 -> error.  */
    389 	  if (length < 0)
    390 	    return length;
    391 	  if (length > 0)
    392 	    {
    393 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    394 	      /* Length is in bits, result is in bytes.  */
    395 	      return length / 8;
    396 	    }
    397 	}
    398 
    399       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    400     }
    401 
    402   return 0;
    403 }
    404 
    405 /* Default value for CGEN_PRINT_INSN.
    406    The result is the size of the insn in bytes or zero for an unknown insn
    407    or -1 if an error occured fetching bytes.  */
    408 
    409 #ifndef CGEN_PRINT_INSN
    410 #define CGEN_PRINT_INSN default_print_insn
    411 #endif
    412 
    413 static int
    414 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    415 {
    416   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    417   int buflen;
    418   int status;
    419 
    420   /* Attempt to read the base part of the insn.  */
    421   buflen = cd->base_insn_bitsize / 8;
    422   status = (*info->read_memory_func) (pc, buf, buflen, info);
    423 
    424   /* Try again with the minimum part, if min < base.  */
    425   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    426     {
    427       buflen = cd->min_insn_bitsize / 8;
    428       status = (*info->read_memory_func) (pc, buf, buflen, info);
    429     }
    430 
    431   if (status != 0)
    432     {
    433       (*info->memory_error_func) (status, pc, info);
    434       return -1;
    435     }
    436 
    437   return print_insn (cd, pc, info, buf, buflen);
    438 }
    439 
    440 /* Main entry point.
    441    Print one instruction from PC on INFO->STREAM.
    442    Return the size of the instruction (in bytes).  */
    443 
    444 typedef struct cpu_desc_list
    445 {
    446   struct cpu_desc_list *next;
    447   CGEN_BITSET *isa;
    448   int mach;
    449   int endian;
    450   CGEN_CPU_DESC cd;
    451 } cpu_desc_list;
    452 
    453 int
    454 print_insn_or1k (bfd_vma pc, disassemble_info *info)
    455 {
    456   static cpu_desc_list *cd_list = 0;
    457   cpu_desc_list *cl = 0;
    458   static CGEN_CPU_DESC cd = 0;
    459   static CGEN_BITSET *prev_isa;
    460   static int prev_mach;
    461   static int prev_endian;
    462   int length;
    463   CGEN_BITSET *isa;
    464   int mach;
    465   int endian = (info->endian == BFD_ENDIAN_BIG
    466 		? CGEN_ENDIAN_BIG
    467 		: CGEN_ENDIAN_LITTLE);
    468   enum bfd_architecture arch;
    469 
    470   /* ??? gdb will set mach but leave the architecture as "unknown" */
    471 #ifndef CGEN_BFD_ARCH
    472 #define CGEN_BFD_ARCH bfd_arch_or1k
    473 #endif
    474   arch = info->arch;
    475   if (arch == bfd_arch_unknown)
    476     arch = CGEN_BFD_ARCH;
    477 
    478   /* There's no standard way to compute the machine or isa number
    479      so we leave it to the target.  */
    480 #ifdef CGEN_COMPUTE_MACH
    481   mach = CGEN_COMPUTE_MACH (info);
    482 #else
    483   mach = info->mach;
    484 #endif
    485 
    486 #ifdef CGEN_COMPUTE_ISA
    487   {
    488     static CGEN_BITSET *permanent_isa;
    489 
    490     if (!permanent_isa)
    491       permanent_isa = cgen_bitset_create (MAX_ISAS);
    492     isa = permanent_isa;
    493     cgen_bitset_clear (isa);
    494     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    495   }
    496 #else
    497   isa = info->insn_sets;
    498 #endif
    499 
    500   /* If we've switched cpu's, try to find a handle we've used before */
    501   if (cd
    502       && (cgen_bitset_compare (isa, prev_isa) != 0
    503 	  || mach != prev_mach
    504 	  || endian != prev_endian))
    505     {
    506       cd = 0;
    507       for (cl = cd_list; cl; cl = cl->next)
    508 	{
    509 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    510 	      cl->mach == mach &&
    511 	      cl->endian == endian)
    512 	    {
    513 	      cd = cl->cd;
    514  	      prev_isa = cd->isas;
    515 	      break;
    516 	    }
    517 	}
    518     }
    519 
    520   /* If we haven't initialized yet, initialize the opcode table.  */
    521   if (! cd)
    522     {
    523       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    524       const char *mach_name;
    525 
    526       if (!arch_type)
    527 	abort ();
    528       mach_name = arch_type->printable_name;
    529 
    530       prev_isa = cgen_bitset_copy (isa);
    531       prev_mach = mach;
    532       prev_endian = endian;
    533       cd = or1k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    534 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    535 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    536 				 CGEN_CPU_OPEN_END);
    537       if (!cd)
    538 	abort ();
    539 
    540       /* Save this away for future reference.  */
    541       cl = xmalloc (sizeof (struct cpu_desc_list));
    542       cl->cd = cd;
    543       cl->isa = prev_isa;
    544       cl->mach = mach;
    545       cl->endian = endian;
    546       cl->next = cd_list;
    547       cd_list = cl;
    548 
    549       or1k_cgen_init_dis (cd);
    550     }
    551 
    552   /* We try to have as much common code as possible.
    553      But at this point some targets need to take over.  */
    554   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    555      but if not possible try to move this hook elsewhere rather than
    556      have two hooks.  */
    557   length = CGEN_PRINT_INSN (cd, pc, info);
    558   if (length > 0)
    559     return length;
    560   if (length < 0)
    561     return -1;
    562 
    563   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    564   return cd->default_insn_bitsize / 8;
    565 }
    566