(linenum→info "unix/slp.c:2238")

binutils/2.18/opcodes/cgen-dis.in

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