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-2014 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 "@prefix (at) -desc.h"
     36 #include "@prefix (at) -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 /* Default print handler.  */
     63 
     64 static void
     65 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     66 	      void *dis_info,
     67 	      long value,
     68 	      unsigned int attrs,
     69 	      bfd_vma pc ATTRIBUTE_UNUSED,
     70 	      int length ATTRIBUTE_UNUSED)
     71 {
     72   disassemble_info *info = (disassemble_info *) dis_info;
     73 
     74   /* Print the operand as directed by the attributes.  */
     75   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     76     ; /* nothing to do */
     77   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
     78     (*info->fprintf_func) (info->stream, "%ld", value);
     79   else
     80     (*info->fprintf_func) (info->stream, "0x%lx", value);
     81 }
     82 
     83 /* Default address handler.  */
     84 
     85 static void
     86 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     87 	       void *dis_info,
     88 	       bfd_vma value,
     89 	       unsigned int attrs,
     90 	       bfd_vma pc ATTRIBUTE_UNUSED,
     91 	       int length ATTRIBUTE_UNUSED)
     92 {
     93   disassemble_info *info = (disassemble_info *) dis_info;
     94 
     95   /* Print the operand as directed by the attributes.  */
     96   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     97     ; /* Nothing to do.  */
     98   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
     99     (*info->print_address_func) (value, info);
    100   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
    101     (*info->print_address_func) (value, info);
    102   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    103     (*info->fprintf_func) (info->stream, "%ld", (long) value);
    104   else
    105     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
    106 }
    107 
    108 /* Keyword print handler.  */
    109 
    110 static void
    111 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    112 	       void *dis_info,
    113 	       CGEN_KEYWORD *keyword_table,
    114 	       long value,
    115 	       unsigned int attrs ATTRIBUTE_UNUSED)
    116 {
    117   disassemble_info *info = (disassemble_info *) dis_info;
    118   const CGEN_KEYWORD_ENTRY *ke;
    119 
    120   ke = cgen_keyword_lookup_value (keyword_table, value);
    121   if (ke != NULL)
    122     (*info->fprintf_func) (info->stream, "%s", ke->name);
    123   else
    124     (*info->fprintf_func) (info->stream, "???");
    125 }
    126 
    127 /* Default insn printer.
    129 
    130    DIS_INFO is defined as `void *' so the disassembler needn't know anything
    131    about disassemble_info.  */
    132 
    133 static void
    134 print_insn_normal (CGEN_CPU_DESC cd,
    135 		   void *dis_info,
    136 		   const CGEN_INSN *insn,
    137 		   CGEN_FIELDS *fields,
    138 		   bfd_vma pc,
    139 		   int length)
    140 {
    141   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    142   disassemble_info *info = (disassemble_info *) dis_info;
    143   const CGEN_SYNTAX_CHAR_TYPE *syn;
    144 
    145   CGEN_INIT_PRINT (cd);
    146 
    147   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
    148     {
    149       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
    150 	{
    151 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
    152 	  continue;
    153 	}
    154       if (CGEN_SYNTAX_CHAR_P (*syn))
    155 	{
    156 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
    157 	  continue;
    158 	}
    159 
    160       /* We have an operand.  */
    161       @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
    162 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
    163     }
    164 }
    165 
    166 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
    168    the extract info.
    169    Returns 0 if all is well, non-zero otherwise.  */
    170 
    171 static int
    172 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    173 	   bfd_vma pc,
    174 	   disassemble_info *info,
    175 	   bfd_byte *buf,
    176 	   int buflen,
    177 	   CGEN_EXTRACT_INFO *ex_info,
    178 	   unsigned long *insn_value)
    179 {
    180   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    181 
    182   if (status != 0)
    183     {
    184       (*info->memory_error_func) (status, pc, info);
    185       return -1;
    186     }
    187 
    188   ex_info->dis_info = info;
    189   ex_info->valid = (1 << buflen) - 1;
    190   ex_info->insn_bytes = buf;
    191 
    192   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    193   return 0;
    194 }
    195 
    196 /* Utility to print an insn.
    197    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    198    The result is the size of the insn in bytes or zero for an unknown insn
    199    or -1 if an error occurs fetching data (memory_error_func will have
    200    been called).  */
    201 
    202 static int
    203 print_insn (CGEN_CPU_DESC cd,
    204 	    bfd_vma pc,
    205 	    disassemble_info *info,
    206 	    bfd_byte *buf,
    207 	    unsigned int buflen)
    208 {
    209   CGEN_INSN_INT insn_value;
    210   const CGEN_INSN_LIST *insn_list;
    211   CGEN_EXTRACT_INFO ex_info;
    212   int basesize;
    213 
    214   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    215   basesize = cd->base_insn_bitsize < buflen * 8 ?
    216                                      cd->base_insn_bitsize : buflen * 8;
    217   insn_value = cgen_get_insn_value (cd, buf, basesize);
    218 
    219 
    220   /* Fill in ex_info fields like read_insn would.  Don't actually call
    221      read_insn, since the incoming buffer is already read (and possibly
    222      modified a la m32r).  */
    223   ex_info.valid = (1 << buflen) - 1;
    224   ex_info.dis_info = info;
    225   ex_info.insn_bytes = buf;
    226 
    227   /* The instructions are stored in hash lists.
    228      Pick the first one and keep trying until we find the right one.  */
    229 
    230   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    231   while (insn_list != NULL)
    232     {
    233       const CGEN_INSN *insn = insn_list->insn;
    234       CGEN_FIELDS fields;
    235       int length;
    236       unsigned long insn_value_cropped;
    237 
    238 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    239       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    240       /* Supported by this cpu?  */
    241       if (! @arch@_cgen_insn_supported (cd, insn))
    242         {
    243           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    244 	  continue;
    245         }
    246 #endif
    247 
    248       /* Basic bit mask must be correct.  */
    249       /* ??? May wish to allow target to defer this check until the extract
    250 	 handler.  */
    251 
    252       /* Base size may exceed this instruction's size.  Extract the
    253          relevant part from the buffer. */
    254       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    255 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    256 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    257 					   info->endian == BFD_ENDIAN_BIG);
    258       else
    259 	insn_value_cropped = insn_value;
    260 
    261       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    262 	  == CGEN_INSN_BASE_VALUE (insn))
    263 	{
    264 	  /* Printing is handled in two passes.  The first pass parses the
    265 	     machine insn and extracts the fields.  The second pass prints
    266 	     them.  */
    267 
    268 	  /* Make sure the entire insn is loaded into insn_value, if it
    269 	     can fit.  */
    270 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    271 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    272 	    {
    273 	      unsigned long full_insn_value;
    274 	      int rc = read_insn (cd, pc, info, buf,
    275 				  CGEN_INSN_BITSIZE (insn) / 8,
    276 				  & ex_info, & full_insn_value);
    277 	      if (rc != 0)
    278 		return rc;
    279 	      length = CGEN_EXTRACT_FN (cd, insn)
    280 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    281 	    }
    282 	  else
    283 	    length = CGEN_EXTRACT_FN (cd, insn)
    284 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    285 
    286 	  /* Length < 0 -> error.  */
    287 	  if (length < 0)
    288 	    return length;
    289 	  if (length > 0)
    290 	    {
    291 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    292 	      /* Length is in bits, result is in bytes.  */
    293 	      return length / 8;
    294 	    }
    295 	}
    296 
    297       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    298     }
    299 
    300   return 0;
    301 }
    302 
    303 /* Default value for CGEN_PRINT_INSN.
    304    The result is the size of the insn in bytes or zero for an unknown insn
    305    or -1 if an error occured fetching bytes.  */
    306 
    307 #ifndef CGEN_PRINT_INSN
    308 #define CGEN_PRINT_INSN default_print_insn
    309 #endif
    310 
    311 static int
    312 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    313 {
    314   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    315   int buflen;
    316   int status;
    317 
    318   /* Attempt to read the base part of the insn.  */
    319   buflen = cd->base_insn_bitsize / 8;
    320   status = (*info->read_memory_func) (pc, buf, buflen, info);
    321 
    322   /* Try again with the minimum part, if min < base.  */
    323   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    324     {
    325       buflen = cd->min_insn_bitsize / 8;
    326       status = (*info->read_memory_func) (pc, buf, buflen, info);
    327     }
    328 
    329   if (status != 0)
    330     {
    331       (*info->memory_error_func) (status, pc, info);
    332       return -1;
    333     }
    334 
    335   return print_insn (cd, pc, info, buf, buflen);
    336 }
    337 
    338 /* Main entry point.
    339    Print one instruction from PC on INFO->STREAM.
    340    Return the size of the instruction (in bytes).  */
    341 
    342 typedef struct cpu_desc_list
    343 {
    344   struct cpu_desc_list *next;
    345   CGEN_BITSET *isa;
    346   int mach;
    347   int endian;
    348   CGEN_CPU_DESC cd;
    349 } cpu_desc_list;
    350 
    351 int
    352 print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
    353 {
    354   static cpu_desc_list *cd_list = 0;
    355   cpu_desc_list *cl = 0;
    356   static CGEN_CPU_DESC cd = 0;
    357   static CGEN_BITSET *prev_isa;
    358   static int prev_mach;
    359   static int prev_endian;
    360   int length;
    361   CGEN_BITSET *isa;
    362   int mach;
    363   int endian = (info->endian == BFD_ENDIAN_BIG
    364 		? CGEN_ENDIAN_BIG
    365 		: CGEN_ENDIAN_LITTLE);
    366   enum bfd_architecture arch;
    367 
    368   /* ??? gdb will set mach but leave the architecture as "unknown" */
    369 #ifndef CGEN_BFD_ARCH
    370 #define CGEN_BFD_ARCH bfd_arch_@arch@
    371 #endif
    372   arch = info->arch;
    373   if (arch == bfd_arch_unknown)
    374     arch = CGEN_BFD_ARCH;
    375 
    376   /* There's no standard way to compute the machine or isa number
    377      so we leave it to the target.  */
    378 #ifdef CGEN_COMPUTE_MACH
    379   mach = CGEN_COMPUTE_MACH (info);
    380 #else
    381   mach = info->mach;
    382 #endif
    383 
    384 #ifdef CGEN_COMPUTE_ISA
    385   {
    386     static CGEN_BITSET *permanent_isa;
    387 
    388     if (!permanent_isa)
    389       permanent_isa = cgen_bitset_create (MAX_ISAS);
    390     isa = permanent_isa;
    391     cgen_bitset_clear (isa);
    392     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    393   }
    394 #else
    395   isa = info->insn_sets;
    396 #endif
    397 
    398   /* If we've switched cpu's, try to find a handle we've used before */
    399   if (cd
    400       && (cgen_bitset_compare (isa, prev_isa) != 0
    401 	  || mach != prev_mach
    402 	  || endian != prev_endian))
    403     {
    404       cd = 0;
    405       for (cl = cd_list; cl; cl = cl->next)
    406 	{
    407 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    408 	      cl->mach == mach &&
    409 	      cl->endian == endian)
    410 	    {
    411 	      cd = cl->cd;
    412  	      prev_isa = cd->isas;
    413 	      break;
    414 	    }
    415 	}
    416     }
    417 
    418   /* If we haven't initialized yet, initialize the opcode table.  */
    419   if (! cd)
    420     {
    421       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    422       const char *mach_name;
    423 
    424       if (!arch_type)
    425 	abort ();
    426       mach_name = arch_type->printable_name;
    427 
    428       prev_isa = cgen_bitset_copy (isa);
    429       prev_mach = mach;
    430       prev_endian = endian;
    431       cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    432 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    433 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    434 				 CGEN_CPU_OPEN_END);
    435       if (!cd)
    436 	abort ();
    437 
    438       /* Save this away for future reference.  */
    439       cl = xmalloc (sizeof (struct cpu_desc_list));
    440       cl->cd = cd;
    441       cl->isa = prev_isa;
    442       cl->mach = mach;
    443       cl->endian = endian;
    444       cl->next = cd_list;
    445       cd_list = cl;
    446 
    447       @arch@_cgen_init_dis (cd);
    448     }
    449 
    450   /* We try to have as much common code as possible.
    451      But at this point some targets need to take over.  */
    452   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    453      but if not possible try to move this hook elsewhere rather than
    454      have two hooks.  */
    455   length = CGEN_PRINT_INSN (cd, pc, info);
    456   if (length > 0)
    457     return length;
    458   if (length < 0)
    459     return -1;
    460 
    461   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    462   return cd->default_insn_bitsize / 8;
    463 }
    464