X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Fcgen-dis.in;h=aa6278c3b957b5a805fd62a4097da3b5b4b8ac72;hb=9f93bca5c70ce8deb596c3478be4335225d8c563;hp=06e22eb72f69782594d2b48b416e6a06f78eb585;hpb=833d2990732cdaa8b2eb90707d79be8410ec6320;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/cgen-dis.in b/opcodes/cgen-dis.in index 06e22eb72f..aa6278c3b9 100644 --- a/opcodes/cgen-dis.in +++ b/opcodes/cgen-dis.in @@ -1,9 +1,10 @@ /* Disassembler interface for targets using CGEN. -*- C -*- CGEN: Cpu tools GENerator -This file is used to generate @arch@-dis.c. +THIS FILE IS MACHINE GENERATED WITH CGEN. +- the resultant file is machine generated, cgen-dis.in isn't -Copyright (C) 1996, 1997 Free Software Foundation, Inc. +Copyright (C) 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc. This file is part of the GNU Binutils and GDB, the GNU debugger. @@ -18,8 +19,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ??? Eventually more and more of this stuff can go to cpu-independent files. + Keep that in mind. */ #include "sysdep.h" #include @@ -27,109 +31,114 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "dis-asm.h" #include "bfd.h" #include "symcat.h" -#include "@arch@-opc.h" - -/* ??? The layout of this stuff is still work in progress. - For speed in assembly/disassembly, we use inline functions. That of course - will only work for GCC. When this stuff is finished, we can decide whether - to keep the inline functions (and only get the performance increase when - compiled with GCC), or switch to macros, or use something else. -*/ +#include "@prefix@-desc.h" +#include "@prefix@-opc.h" +#include "opintl.h" /* Default text to print if an instruction isn't recognized. */ -#define UNKNOWN_INSN_MSG "*unknown*" - -/* FIXME: Machine generate. */ -#ifndef CGEN_PCREL_OFFSET -#define CGEN_PCREL_OFFSET 0 -#endif - -static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int)); - -static int extract_insn_normal - PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *)); +#define UNKNOWN_INSN_MSG _("*unknown*") + +static void print_normal + PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int)); +static void print_address + PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int)); +static void print_keyword + PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int)); static void print_insn_normal - PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int)); + PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *, + bfd_vma, int)); +static int print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, + disassemble_info *, char *, int)); +static int default_print_insn + PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *)); -/* Default extraction routine. - - ATTRS is a mask of the boolean attributes. We only need `unsigned', - but for generality we take a bitmask of all of them. */ - -static int -extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep) - PTR buf_ctrl; - cgen_insn_t insn_value; - unsigned int attrs; - int start, length, shift, total_length; - long *valuep; -{ - long value; +/* -- disassembler routines inserted here */ + +/* Default print handler. */ -#ifdef CGEN_INT_INSN -#if 0 - value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length))) - & ((1 << length) - 1)); +static void +print_normal (cd, dis_info, value, attrs, pc, length) +#ifdef CGEN_PRINT_NORMAL + CGEN_CPU_DESC cd; #else - value = ((insn_value >> (total_length - (start + length))) - & ((1 << length) - 1)); + CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; #endif - if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) - && (value & (1 << (length - 1)))) - value -= 1 << length; + PTR dis_info; + long value; + unsigned int attrs; +#ifdef CGEN_PRINT_NORMAL + bfd_vma pc; + int length; #else - /* FIXME: unfinished */ + bfd_vma pc ATTRIBUTE_UNUSED; + int length ATTRIBUTE_UNUSED; #endif +{ + disassemble_info *info = (disassemble_info *) dis_info; - /* This is backwards as we undo the effects of insert_normal. */ - if (shift < 0) - value >>= -shift; - else - value <<= shift; - - *valuep = value; +#ifdef CGEN_PRINT_NORMAL + CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length); +#endif - /* FIXME: for now */ - return 1; + /* Print the operand as directed by the attributes. */ + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* nothing to do */ + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) + (*info->fprintf_func) (info->stream, "%ld", value); + else + (*info->fprintf_func) (info->stream, "0x%lx", value); } -/* Default print handler. */ +/* Default address handler. */ static void -print_normal (dis_info, value, attrs, pc, length) +print_address (cd, dis_info, value, attrs, pc, length) +#ifdef CGEN_PRINT_NORMAL + CGEN_CPU_DESC cd; +#else + CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; +#endif PTR dis_info; - long value; + bfd_vma value; unsigned int attrs; - unsigned long pc; /* FIXME: should be bfd_vma */ +#ifdef CGEN_PRINT_NORMAL + bfd_vma pc; int length; +#else + bfd_vma pc ATTRIBUTE_UNUSED; + int length ATTRIBUTE_UNUSED; +#endif { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; + +#ifdef CGEN_PRINT_ADDRESS + CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length); +#endif /* Print the operand as directed by the attributes. */ - if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE)) - ; /* nothing to do (??? at least not yet) */ - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR)) - (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info); - /* ??? Not all cases of this are currently caught. */ - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR)) - /* FIXME: Why & 0xffffffff? */ - (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) - (*info->fprintf_func) (info->stream, "0x%lx", value); + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* nothing to do */ + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) + (*info->print_address_func) (value, info); + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) + (*info->print_address_func) (value, info); + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) + (*info->fprintf_func) (info->stream, "%ld", (long) value); else - (*info->fprintf_func) (info->stream, "%ld", value); + (*info->fprintf_func) (info->stream, "0x%lx", (long) value); } /* Keyword print handler. */ static void -print_keyword (dis_info, keyword_table, value, attrs) +print_keyword (cd, dis_info, keyword_table, value, attrs) + CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; PTR dis_info; CGEN_KEYWORD *keyword_table; long value; - CGEN_ATTR *attrs; + unsigned int attrs ATTRIBUTE_UNUSED; { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; const CGEN_KEYWORD_ENTRY *ke; ke = cgen_keyword_lookup_value (keyword_table, value); @@ -139,53 +148,14 @@ print_keyword (dis_info, keyword_table, value, attrs) (*info->fprintf_func) (info->stream, "???"); } -/* -- disassembler routines inserted here */ - -/* Default insn extractor. - - The extracted fields are stored in DIS_FLDS. - BUF_CTRL is used to handle reading variable length insns (FIXME: not done). - Return the length of the insn in bits, or 0 if no match. */ - -static int -extract_insn_normal (insn, buf_ctrl, insn_value, fields) - const CGEN_INSN *insn; - PTR buf_ctrl; - cgen_insn_t insn_value; - CGEN_FIELDS *fields; -{ - const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - const unsigned char *syn; - - CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); - - CGEN_INIT_EXTRACT (); - - for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) - { - int length; - - if (CGEN_SYNTAX_CHAR_P (*syn)) - continue; - - length = @arch@_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn), - buf_ctrl, insn_value, fields); - if (length == 0) - return 0; - } - - /* We recognized and successfully extracted this insn. */ - return CGEN_INSN_BITSIZE (insn); -} - /* Default insn printer. DIS_INFO is defined as `PTR' so the disassembler needn't know anything - about disassemble_info. -*/ + about disassemble_info. */ static void -print_insn_normal (dis_info, insn, fields, pc, length) +print_insn_normal (cd, dis_info, insn, fields, pc, length) + CGEN_CPU_DESC cd; PTR dis_info; const CGEN_INSN *insn; CGEN_FIELDS *fields; @@ -193,10 +163,10 @@ print_insn_normal (dis_info, insn, fields, pc, length) int length; { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - disassemble_info *info = dis_info; - const unsigned char *syn; + disassemble_info *info = (disassemble_info *) dis_info; + const CGEN_SYNTAX_CHAR_TYPE *syn; - CGEN_INIT_PRINT (); + CGEN_INIT_PRINT (cd); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -212,23 +182,48 @@ print_insn_normal (dis_info, insn, fields, pc, length) } /* We have an operand. */ - @arch@_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info, - fields, CGEN_INSN_ATTRS (insn), pc, length); + @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info, + fields, CGEN_INSN_ATTRS (insn), pc, length); } } -/* Default value for CGEN_PRINT_INSN. - Given BUFLEN bits (target byte order) read into BUF, look up the - insn in the instruction table and disassemble it. +/* Subroutine of print_insn. Reads an insn into the given buffers and updates + the extract info. + Returns 0 if all is well, non-zero otherwise. */ +static int +read_insn (cd, pc, info, buf, buflen, ex_info, insn_value) + CGEN_CPU_DESC cd; + bfd_vma pc; + disassemble_info *info; + char *buf; + int buflen; + CGEN_EXTRACT_INFO *ex_info; + unsigned long *insn_value; +{ + int status = (*info->read_memory_func) (pc, buf, buflen, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } - The result is the size of the insn in bytes. */ + ex_info->dis_info = info; + ex_info->valid = (1 << buflen) - 1; + ex_info->insn_bytes = buf; -#ifndef CGEN_PRINT_INSN -#define CGEN_PRINT_INSN print_insn -#endif + *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG); + return 0; +} + +/* Utility to print an insn. + BUF is the base part of the insn, target byte order, BUFLEN bytes long. + The result is the size of the insn in bytes or zero for an unknown insn + or -1 if an error occurs fetching data (memory_error_func will have + been called). */ static int -print_insn (pc, info, buf, buflen) +print_insn (cd, pc, info, buf, buflen) + CGEN_CPU_DESC cd; bfd_vma pc; disassemble_info *info; char *buf; @@ -236,51 +231,66 @@ print_insn (pc, info, buf, buflen) { unsigned long insn_value; const CGEN_INSN_LIST *insn_list; + CGEN_EXTRACT_INFO ex_info; - switch (buflen) - { - case 8: - insn_value = buf[0]; - break; - case 16: - insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf); - break; - case 32: - insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf); - break; - default: - abort (); - } + int rc = read_insn (cd, pc, info, buf, buflen, & ex_info, & insn_value); + if (rc != 0) + return rc; /* The instructions are stored in hash lists. Pick the first one and keep trying until we find the right one. */ - insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value); + insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value); while (insn_list != NULL) { const CGEN_INSN *insn = insn_list->insn; CGEN_FIELDS fields; int length; -#if 0 /* not needed as insn shouldn't be in hash lists if not supported */ +#ifdef CGEN_VALIDATE_INSN_SUPPORTED + /* not needed as insn shouldn't be in hash lists if not supported */ /* Supported by this cpu? */ - if (! @arch@_cgen_insn_supported (insn)) - continue; + if (! @arch@_cgen_insn_supported (cd, insn)) + { + insn_list = CGEN_DIS_NEXT_INSN (insn_list); + continue; + } #endif /* Basic bit mask must be correct. */ /* ??? May wish to allow target to defer this check until the extract handler. */ - if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn)) + if ((insn_value & CGEN_INSN_BASE_MASK (insn)) + == CGEN_INSN_BASE_VALUE (insn)) { /* Printing is handled in two passes. The first pass parses the machine insn and extracts the fields. The second pass prints them. */ - length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields); + /* Make sure the entire insn is loaded into insn_value, if it + can fit. */ + if (CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize && + (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) + { + unsigned long full_insn_value; + int rc = read_insn (cd, pc, info, buf, + CGEN_INSN_BITSIZE (insn) / 8, + & ex_info, & full_insn_value); + if (rc != 0) + return rc; + length = CGEN_EXTRACT_FN (cd, insn) + (cd, insn, &ex_info, full_insn_value, &fields, pc); + } + else + length = CGEN_EXTRACT_FN (cd, insn) + (cd, insn, &ex_info, insn_value, &fields, pc); + + /* length < 0 -> error */ + if (length < 0) + return length; if (length > 0) { - (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length); + CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); /* length is in bits, result is in bytes */ return length / 8; } @@ -292,6 +302,35 @@ print_insn (pc, info, buf, buflen) return 0; } +/* Default value for CGEN_PRINT_INSN. + The result is the size of the insn in bytes or zero for an unknown insn + or -1 if an error occured fetching bytes. */ + +#ifndef CGEN_PRINT_INSN +#define CGEN_PRINT_INSN default_print_insn +#endif + +static int +default_print_insn (cd, pc, info) + CGEN_CPU_DESC cd; + bfd_vma pc; + disassemble_info *info; +{ + char buf[CGEN_MAX_INSN_SIZE]; + int status; + + /* Read the base part of the insn. */ + + status = (*info->read_memory_func) (pc, buf, cd->base_insn_bitsize / 8, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + return print_insn (cd, pc, info, buf, cd->base_insn_bitsize / 8); +} + /* Main entry point. Print one instruction from PC on INFO->STREAM. Return the size of the instruction (in bytes). */ @@ -301,30 +340,65 @@ print_insn_@arch@ (pc, info) bfd_vma pc; disassemble_info *info; { - char buffer[CGEN_MAX_INSN_SIZE]; - int status, length; - static int initialized = 0; - static int current_mach = 0; - static int current_big_p = 0; - int mach = info->mach; - int big_p = info->endian == BFD_ENDIAN_BIG; - - /* If we haven't initialized yet, or if we've switched cpu's, initialize. */ - if (!initialized || mach != current_mach || big_p != current_big_p) + static CGEN_CPU_DESC cd = 0; + static int prev_isa; + static int prev_mach; + static int prev_endian; + int length; + int isa,mach; + int endian = (info->endian == BFD_ENDIAN_BIG + ? CGEN_ENDIAN_BIG + : CGEN_ENDIAN_LITTLE); + enum bfd_architecture arch; + + /* ??? gdb will set mach but leave the architecture as "unknown" */ +#ifndef CGEN_BFD_ARCH +#define CGEN_BFD_ARCH bfd_arch_@arch@ +#endif + arch = info->arch; + if (arch == bfd_arch_unknown) + arch = CGEN_BFD_ARCH; + + /* There's no standard way to compute the isa number (e.g. for arm thumb) + so we leave it to the target. */ +#ifdef CGEN_COMPUTE_ISA + isa = CGEN_COMPUTE_ISA (info); +#else + isa = 0; +#endif + + mach = info->mach; + + /* If we've switched cpu's, close the current table and open a new one. */ + if (cd + && (isa != prev_isa + || mach != prev_mach + || endian != prev_endian)) { - initialized = 1; - current_mach = mach; - current_big_p = big_p; - @arch@_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); + @arch@_cgen_cpu_close (cd); + cd = 0; } - /* Read enough of the insn so we can look it up in the hash lists. */ - - status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info); - if (status != 0) + /* If we haven't initialized yet, initialize the opcode table. */ + if (! cd) { - (*info->memory_error_func) (status, pc, info); - return -1; + const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach); + const char *mach_name; + + if (!arch_type) + abort (); + mach_name = arch_type->printable_name; + + prev_isa = isa; + prev_mach = mach; + prev_endian = endian; + cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa, + CGEN_CPU_OPEN_BFDMACH, mach_name, + CGEN_CPU_OPEN_ENDIAN, prev_endian, + CGEN_CPU_OPEN_END); + if (!cd) + abort (); + @arch@_cgen_init_dis (cd); } /* We try to have as much common code as possible. @@ -332,10 +406,12 @@ print_insn_@arch@ (pc, info) /* ??? Some targets may need a hook elsewhere. Try to avoid this, but if not possible try to move this hook elsewhere rather than have two hooks. */ - length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE); - if (length) + length = CGEN_PRINT_INSN (cd, pc, info); + if (length > 0) return length; + if (length < 0) + return -1; (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); - return CGEN_DEFAULT_INSN_SIZE; + return cd->default_insn_bitsize / 8; }