cgen-dis.in revision 91041
185815Sobrien/* Disassembler interface for targets using CGEN. -*- C -*- 285815Sobrien CGEN: Cpu tools GENerator 385815Sobrien 485815SobrienTHIS FILE IS MACHINE GENERATED WITH CGEN. 585815Sobrien- the resultant file is machine generated, cgen-dis.in isn't 685815Sobrien 785815SobrienCopyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 885815Sobrien 985815SobrienThis file is part of the GNU Binutils and GDB, the GNU debugger. 1085815Sobrien 1185815SobrienThis program is free software; you can redistribute it and/or modify 1285815Sobrienit under the terms of the GNU General Public License as published by 1385815Sobrienthe Free Software Foundation; either version 2, or (at your option) 1485815Sobrienany later version. 1585815Sobrien 1685815SobrienThis program is distributed in the hope that it will be useful, 1785815Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1885815SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1985815SobrienGNU General Public License for more details. 2085815Sobrien 2185815SobrienYou should have received a copy of the GNU General Public License 2285815Sobrienalong with this program; if not, write to the Free Software Foundation, Inc., 2385815Sobrien59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2485815Sobrien 2585815Sobrien/* ??? Eventually more and more of this stuff can go to cpu-independent files. 2685815Sobrien Keep that in mind. */ 2785815Sobrien 2885815Sobrien#include "sysdep.h" 2985815Sobrien#include <stdio.h> 3085815Sobrien#include "ansidecl.h" 3185815Sobrien#include "dis-asm.h" 3285815Sobrien#include "bfd.h" 3385815Sobrien#include "symcat.h" 3485815Sobrien#include "@prefix@-desc.h" 3585815Sobrien#include "@prefix@-opc.h" 3685815Sobrien#include "opintl.h" 3785815Sobrien 3885815Sobrien/* Default text to print if an instruction isn't recognized. */ 3985815Sobrien#define UNKNOWN_INSN_MSG _("*unknown*") 4085815Sobrien 4185815Sobrienstatic void print_normal 4285815Sobrien PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int)); 4385815Sobrienstatic void print_address 4485815Sobrien PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int)); 4585815Sobrienstatic void print_keyword 4685815Sobrien PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int)); 4785815Sobrienstatic void print_insn_normal 4885815Sobrien PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *, 4985815Sobrien bfd_vma, int)); 5089857Sobrienstatic int print_insn 5189857Sobrien PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, unsigned)); 5285815Sobrienstatic int default_print_insn 5385815Sobrien PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *)); 5489857Sobrienstatic int read_insn 5589857Sobrien PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, 5689857Sobrien CGEN_EXTRACT_INFO *, unsigned long *)); 5785815Sobrien 5885815Sobrien/* -- disassembler routines inserted here */ 5985815Sobrien 6085815Sobrien/* Default print handler. */ 6185815Sobrien 6285815Sobrienstatic void 6385815Sobrienprint_normal (cd, dis_info, value, attrs, pc, length) 6485815Sobrien CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 6585815Sobrien PTR dis_info; 6685815Sobrien long value; 6785815Sobrien unsigned int attrs; 6885815Sobrien bfd_vma pc ATTRIBUTE_UNUSED; 6985815Sobrien int length ATTRIBUTE_UNUSED; 7085815Sobrien{ 7185815Sobrien disassemble_info *info = (disassemble_info *) dis_info; 7285815Sobrien 7385815Sobrien#ifdef CGEN_PRINT_NORMAL 7485815Sobrien CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length); 7585815Sobrien#endif 7685815Sobrien 7785815Sobrien /* Print the operand as directed by the attributes. */ 7885815Sobrien if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 7985815Sobrien ; /* nothing to do */ 8085815Sobrien else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 8185815Sobrien (*info->fprintf_func) (info->stream, "%ld", value); 8285815Sobrien else 8385815Sobrien (*info->fprintf_func) (info->stream, "0x%lx", value); 8485815Sobrien} 8585815Sobrien 8685815Sobrien/* Default address handler. */ 8785815Sobrien 8885815Sobrienstatic void 8985815Sobrienprint_address (cd, dis_info, value, attrs, pc, length) 9085815Sobrien CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 9185815Sobrien PTR dis_info; 9285815Sobrien bfd_vma value; 9385815Sobrien unsigned int attrs; 9485815Sobrien bfd_vma pc ATTRIBUTE_UNUSED; 9585815Sobrien int length ATTRIBUTE_UNUSED; 9685815Sobrien{ 9785815Sobrien disassemble_info *info = (disassemble_info *) dis_info; 9885815Sobrien 9985815Sobrien#ifdef CGEN_PRINT_ADDRESS 10085815Sobrien CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length); 10185815Sobrien#endif 10285815Sobrien 10385815Sobrien /* Print the operand as directed by the attributes. */ 10485815Sobrien if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 10585815Sobrien ; /* nothing to do */ 10685815Sobrien else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) 10785815Sobrien (*info->print_address_func) (value, info); 10885815Sobrien else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) 10985815Sobrien (*info->print_address_func) (value, info); 11085815Sobrien else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 11185815Sobrien (*info->fprintf_func) (info->stream, "%ld", (long) value); 11285815Sobrien else 11385815Sobrien (*info->fprintf_func) (info->stream, "0x%lx", (long) value); 11485815Sobrien} 11585815Sobrien 11685815Sobrien/* Keyword print handler. */ 11785815Sobrien 11885815Sobrienstatic void 11985815Sobrienprint_keyword (cd, dis_info, keyword_table, value, attrs) 12085815Sobrien CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 12185815Sobrien PTR dis_info; 12285815Sobrien CGEN_KEYWORD *keyword_table; 12385815Sobrien long value; 12485815Sobrien unsigned int attrs ATTRIBUTE_UNUSED; 12585815Sobrien{ 12685815Sobrien disassemble_info *info = (disassemble_info *) dis_info; 12785815Sobrien const CGEN_KEYWORD_ENTRY *ke; 12885815Sobrien 12985815Sobrien ke = cgen_keyword_lookup_value (keyword_table, value); 13085815Sobrien if (ke != NULL) 13185815Sobrien (*info->fprintf_func) (info->stream, "%s", ke->name); 13285815Sobrien else 13385815Sobrien (*info->fprintf_func) (info->stream, "???"); 13485815Sobrien} 13585815Sobrien 13685815Sobrien/* Default insn printer. 13785815Sobrien 13885815Sobrien DIS_INFO is defined as `PTR' so the disassembler needn't know anything 13985815Sobrien about disassemble_info. */ 14085815Sobrien 14185815Sobrienstatic void 14285815Sobrienprint_insn_normal (cd, dis_info, insn, fields, pc, length) 14385815Sobrien CGEN_CPU_DESC cd; 14485815Sobrien PTR dis_info; 14585815Sobrien const CGEN_INSN *insn; 14685815Sobrien CGEN_FIELDS *fields; 14785815Sobrien bfd_vma pc; 14885815Sobrien int length; 14985815Sobrien{ 15085815Sobrien const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 15185815Sobrien disassemble_info *info = (disassemble_info *) dis_info; 15285815Sobrien const CGEN_SYNTAX_CHAR_TYPE *syn; 15385815Sobrien 15485815Sobrien CGEN_INIT_PRINT (cd); 15585815Sobrien 15685815Sobrien for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) 15785815Sobrien { 15885815Sobrien if (CGEN_SYNTAX_MNEMONIC_P (*syn)) 15985815Sobrien { 16085815Sobrien (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn)); 16185815Sobrien continue; 16285815Sobrien } 16385815Sobrien if (CGEN_SYNTAX_CHAR_P (*syn)) 16485815Sobrien { 16585815Sobrien (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn)); 16685815Sobrien continue; 16785815Sobrien } 16885815Sobrien 16985815Sobrien /* We have an operand. */ 17085815Sobrien @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info, 17185815Sobrien fields, CGEN_INSN_ATTRS (insn), pc, length); 17285815Sobrien } 17385815Sobrien} 17485815Sobrien 17585815Sobrien/* Subroutine of print_insn. Reads an insn into the given buffers and updates 17685815Sobrien the extract info. 17785815Sobrien Returns 0 if all is well, non-zero otherwise. */ 17889857Sobrien 17985815Sobrienstatic int 18085815Sobrienread_insn (cd, pc, info, buf, buflen, ex_info, insn_value) 18189857Sobrien CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 18285815Sobrien bfd_vma pc; 18385815Sobrien disassemble_info *info; 18485815Sobrien char *buf; 18585815Sobrien int buflen; 18685815Sobrien CGEN_EXTRACT_INFO *ex_info; 18785815Sobrien unsigned long *insn_value; 18885815Sobrien{ 18985815Sobrien int status = (*info->read_memory_func) (pc, buf, buflen, info); 19085815Sobrien if (status != 0) 19185815Sobrien { 19285815Sobrien (*info->memory_error_func) (status, pc, info); 19385815Sobrien return -1; 19485815Sobrien } 19585815Sobrien 19685815Sobrien ex_info->dis_info = info; 19785815Sobrien ex_info->valid = (1 << buflen) - 1; 19885815Sobrien ex_info->insn_bytes = buf; 19985815Sobrien 20085815Sobrien *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG); 20185815Sobrien return 0; 20285815Sobrien} 20385815Sobrien 20485815Sobrien/* Utility to print an insn. 20585815Sobrien BUF is the base part of the insn, target byte order, BUFLEN bytes long. 20685815Sobrien The result is the size of the insn in bytes or zero for an unknown insn 20785815Sobrien or -1 if an error occurs fetching data (memory_error_func will have 20885815Sobrien been called). */ 20985815Sobrien 21085815Sobrienstatic int 21185815Sobrienprint_insn (cd, pc, info, buf, buflen) 21285815Sobrien CGEN_CPU_DESC cd; 21385815Sobrien bfd_vma pc; 21485815Sobrien disassemble_info *info; 21585815Sobrien char *buf; 21689857Sobrien unsigned int buflen; 21785815Sobrien{ 21889857Sobrien CGEN_INSN_INT insn_value; 21985815Sobrien const CGEN_INSN_LIST *insn_list; 22085815Sobrien CGEN_EXTRACT_INFO ex_info; 22189857Sobrien int basesize; 22285815Sobrien 22389857Sobrien /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */ 22489857Sobrien basesize = cd->base_insn_bitsize < buflen * 8 ? 22589857Sobrien cd->base_insn_bitsize : buflen * 8; 22689857Sobrien insn_value = cgen_get_insn_value (cd, buf, basesize); 22785815Sobrien 22889857Sobrien 22989857Sobrien /* Fill in ex_info fields like read_insn would. Don't actually call 23089857Sobrien read_insn, since the incoming buffer is already read (and possibly 23189857Sobrien modified a la m32r). */ 23289857Sobrien ex_info.valid = (1 << buflen) - 1; 23389857Sobrien ex_info.dis_info = info; 23489857Sobrien ex_info.insn_bytes = buf; 23589857Sobrien 23685815Sobrien /* The instructions are stored in hash lists. 23785815Sobrien Pick the first one and keep trying until we find the right one. */ 23885815Sobrien 23985815Sobrien insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value); 24085815Sobrien while (insn_list != NULL) 24185815Sobrien { 24285815Sobrien const CGEN_INSN *insn = insn_list->insn; 24385815Sobrien CGEN_FIELDS fields; 24485815Sobrien int length; 24589857Sobrien unsigned long insn_value_cropped; 24685815Sobrien 24785815Sobrien#ifdef CGEN_VALIDATE_INSN_SUPPORTED 24889857Sobrien /* Not needed as insn shouldn't be in hash lists if not supported. */ 24985815Sobrien /* Supported by this cpu? */ 25085815Sobrien if (! @arch@_cgen_insn_supported (cd, insn)) 25185815Sobrien { 25285815Sobrien insn_list = CGEN_DIS_NEXT_INSN (insn_list); 25385815Sobrien continue; 25485815Sobrien } 25585815Sobrien#endif 25685815Sobrien 25785815Sobrien /* Basic bit mask must be correct. */ 25885815Sobrien /* ??? May wish to allow target to defer this check until the extract 25985815Sobrien handler. */ 26089857Sobrien 26189857Sobrien /* Base size may exceed this instruction's size. Extract the 26289857Sobrien relevant part from the buffer. */ 26389857Sobrien if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen && 26489857Sobrien (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 26589857Sobrien insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 26689857Sobrien info->endian == BFD_ENDIAN_BIG); 26789857Sobrien else 26889857Sobrien insn_value_cropped = insn_value; 26989857Sobrien 27089857Sobrien if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn)) 27185815Sobrien == CGEN_INSN_BASE_VALUE (insn)) 27285815Sobrien { 27385815Sobrien /* Printing is handled in two passes. The first pass parses the 27485815Sobrien machine insn and extracts the fields. The second pass prints 27585815Sobrien them. */ 27685815Sobrien 27785815Sobrien /* Make sure the entire insn is loaded into insn_value, if it 27885815Sobrien can fit. */ 27989857Sobrien if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) && 28089857Sobrien (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 28185815Sobrien { 28285815Sobrien unsigned long full_insn_value; 28385815Sobrien int rc = read_insn (cd, pc, info, buf, 28485815Sobrien CGEN_INSN_BITSIZE (insn) / 8, 28585815Sobrien & ex_info, & full_insn_value); 28685815Sobrien if (rc != 0) 28785815Sobrien return rc; 28885815Sobrien length = CGEN_EXTRACT_FN (cd, insn) 28985815Sobrien (cd, insn, &ex_info, full_insn_value, &fields, pc); 29085815Sobrien } 29185815Sobrien else 29285815Sobrien length = CGEN_EXTRACT_FN (cd, insn) 29389857Sobrien (cd, insn, &ex_info, insn_value_cropped, &fields, pc); 29485815Sobrien 29585815Sobrien /* length < 0 -> error */ 29685815Sobrien if (length < 0) 29785815Sobrien return length; 29885815Sobrien if (length > 0) 29985815Sobrien { 30085815Sobrien CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); 30185815Sobrien /* length is in bits, result is in bytes */ 30285815Sobrien return length / 8; 30385815Sobrien } 30485815Sobrien } 30585815Sobrien 30685815Sobrien insn_list = CGEN_DIS_NEXT_INSN (insn_list); 30785815Sobrien } 30885815Sobrien 30985815Sobrien return 0; 31085815Sobrien} 31185815Sobrien 31285815Sobrien/* Default value for CGEN_PRINT_INSN. 31385815Sobrien The result is the size of the insn in bytes or zero for an unknown insn 31485815Sobrien or -1 if an error occured fetching bytes. */ 31585815Sobrien 31685815Sobrien#ifndef CGEN_PRINT_INSN 31785815Sobrien#define CGEN_PRINT_INSN default_print_insn 31885815Sobrien#endif 31985815Sobrien 32085815Sobrienstatic int 32185815Sobriendefault_print_insn (cd, pc, info) 32285815Sobrien CGEN_CPU_DESC cd; 32385815Sobrien bfd_vma pc; 32485815Sobrien disassemble_info *info; 32585815Sobrien{ 32685815Sobrien char buf[CGEN_MAX_INSN_SIZE]; 32789857Sobrien int buflen; 32885815Sobrien int status; 32985815Sobrien 33089857Sobrien /* Attempt to read the base part of the insn. */ 33189857Sobrien buflen = cd->base_insn_bitsize / 8; 33289857Sobrien status = (*info->read_memory_func) (pc, buf, buflen, info); 33385815Sobrien 33489857Sobrien /* Try again with the minimum part, if min < base. */ 33589857Sobrien if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 33689857Sobrien { 33789857Sobrien buflen = cd->min_insn_bitsize / 8; 33889857Sobrien status = (*info->read_memory_func) (pc, buf, buflen, info); 33989857Sobrien } 34089857Sobrien 34185815Sobrien if (status != 0) 34285815Sobrien { 34385815Sobrien (*info->memory_error_func) (status, pc, info); 34485815Sobrien return -1; 34585815Sobrien } 34685815Sobrien 34789857Sobrien return print_insn (cd, pc, info, buf, buflen); 34885815Sobrien} 34985815Sobrien 35085815Sobrien/* Main entry point. 35185815Sobrien Print one instruction from PC on INFO->STREAM. 35285815Sobrien Return the size of the instruction (in bytes). */ 35385815Sobrien 35485815Sobrienint 35585815Sobrienprint_insn_@arch@ (pc, info) 35685815Sobrien bfd_vma pc; 35785815Sobrien disassemble_info *info; 35885815Sobrien{ 35985815Sobrien static CGEN_CPU_DESC cd = 0; 36085815Sobrien static int prev_isa; 36185815Sobrien static int prev_mach; 36285815Sobrien static int prev_endian; 36385815Sobrien int length; 36485815Sobrien int isa,mach; 36585815Sobrien int endian = (info->endian == BFD_ENDIAN_BIG 36685815Sobrien ? CGEN_ENDIAN_BIG 36785815Sobrien : CGEN_ENDIAN_LITTLE); 36885815Sobrien enum bfd_architecture arch; 36985815Sobrien 37085815Sobrien /* ??? gdb will set mach but leave the architecture as "unknown" */ 37185815Sobrien#ifndef CGEN_BFD_ARCH 37285815Sobrien#define CGEN_BFD_ARCH bfd_arch_@arch@ 37385815Sobrien#endif 37485815Sobrien arch = info->arch; 37585815Sobrien if (arch == bfd_arch_unknown) 37685815Sobrien arch = CGEN_BFD_ARCH; 37789857Sobrien 37889857Sobrien /* There's no standard way to compute the machine or isa number 37985815Sobrien so we leave it to the target. */ 38089857Sobrien#ifdef CGEN_COMPUTE_MACH 38189857Sobrien mach = CGEN_COMPUTE_MACH (info); 38289857Sobrien#else 38389857Sobrien mach = info->mach; 38489857Sobrien#endif 38589857Sobrien 38685815Sobrien#ifdef CGEN_COMPUTE_ISA 38785815Sobrien isa = CGEN_COMPUTE_ISA (info); 38885815Sobrien#else 38991041Sobrien isa = info->insn_sets; 39085815Sobrien#endif 39185815Sobrien 39285815Sobrien /* If we've switched cpu's, close the current table and open a new one. */ 39385815Sobrien if (cd 39485815Sobrien && (isa != prev_isa 39585815Sobrien || mach != prev_mach 39685815Sobrien || endian != prev_endian)) 39785815Sobrien { 39885815Sobrien @arch@_cgen_cpu_close (cd); 39985815Sobrien cd = 0; 40085815Sobrien } 40185815Sobrien 40285815Sobrien /* If we haven't initialized yet, initialize the opcode table. */ 40385815Sobrien if (! cd) 40485815Sobrien { 40585815Sobrien const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach); 40685815Sobrien const char *mach_name; 40785815Sobrien 40885815Sobrien if (!arch_type) 40985815Sobrien abort (); 41085815Sobrien mach_name = arch_type->printable_name; 41185815Sobrien 41285815Sobrien prev_isa = isa; 41385815Sobrien prev_mach = mach; 41485815Sobrien prev_endian = endian; 41585815Sobrien cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa, 41685815Sobrien CGEN_CPU_OPEN_BFDMACH, mach_name, 41785815Sobrien CGEN_CPU_OPEN_ENDIAN, prev_endian, 41885815Sobrien CGEN_CPU_OPEN_END); 41985815Sobrien if (!cd) 42085815Sobrien abort (); 42185815Sobrien @arch@_cgen_init_dis (cd); 42285815Sobrien } 42385815Sobrien 42485815Sobrien /* We try to have as much common code as possible. 42585815Sobrien But at this point some targets need to take over. */ 42685815Sobrien /* ??? Some targets may need a hook elsewhere. Try to avoid this, 42785815Sobrien but if not possible try to move this hook elsewhere rather than 42885815Sobrien have two hooks. */ 42985815Sobrien length = CGEN_PRINT_INSN (cd, pc, info); 43085815Sobrien if (length > 0) 43185815Sobrien return length; 43285815Sobrien if (length < 0) 43385815Sobrien return -1; 43485815Sobrien 43585815Sobrien (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 43685815Sobrien return cd->default_insn_bitsize / 8; 43785815Sobrien} 438