cgen-dis.in revision 218822
1204431Sraj/* Disassembler interface for targets using CGEN. -*- C -*- 2204431Sraj CGEN: Cpu tools GENerator 3204431Sraj 4204431Sraj THIS FILE IS MACHINE GENERATED WITH CGEN. 5204431Sraj - the resultant file is machine generated, cgen-dis.in isn't 6204431Sraj 7204431Sraj Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 8204431Sraj Free Software Foundation, Inc. 9204431Sraj 10204431Sraj This file is part of the GNU Binutils and GDB, the GNU debugger. 11204431Sraj 12204431Sraj This program is free software; you can redistribute it and/or modify 13204431Sraj it under the terms of the GNU General Public License as published by 14204431Sraj the Free Software Foundation; either version 2, or (at your option) 15204431Sraj any later version. 16204431Sraj 17204431Sraj This program is distributed in the hope that it will be useful, 18204431Sraj but WITHOUT ANY WARRANTY; without even the implied warranty of 19204431Sraj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20204431Sraj GNU General Public License for more details. 21204431Sraj 22204431Sraj You should have received a copy of the GNU General Public License 23204431Sraj along with this program; if not, write to the Free Software Foundation, Inc., 24204431Sraj 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 25204431Sraj 26204431Sraj/* ??? Eventually more and more of this stuff can go to cpu-independent files. 27238742Simp Keep that in mind. */ 28204431Sraj 29238742Simp#include "sysdep.h" 30238742Simp#include <stdio.h> 31238742Simp#include "ansidecl.h" 32266130Sian#include "dis-asm.h" 33266130Sian#include "bfd.h" 34266130Sian#include "symcat.h" 35238742Simp#include "libiberty.h" 36266130Sian#include "@prefix@-desc.h" 37238742Simp#include "@prefix@-opc.h" 38238742Simp#include "opintl.h" 39266130Sian 40238742Simp/* Default text to print if an instruction isn't recognized. */ 41238742Simp#define UNKNOWN_INSN_MSG _("*unknown*") 42238742Simp 43238742Simpstatic void print_normal 44238742Simp (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int); 45266130Sianstatic void print_address 46266130Sian (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED; 47266130Sianstatic void print_keyword 48266130Sian (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED; 49266130Sianstatic void print_insn_normal 50266130Sian (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int); 51266130Sianstatic int print_insn 52266130Sian (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned); 53238742Simpstatic int default_print_insn 54238742Simp (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED; 55204431Srajstatic int read_insn 56204431Sraj (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *, 57238742Simp unsigned long *); 58238742Simp 59204431Sraj/* -- disassembler routines inserted here. */ 60204431Sraj 61204431Sraj/* Default print handler. */ 62204431Sraj 63204431Srajstatic void 64204431Srajprint_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 65266130Sian void *dis_info, 66266130Sian long value, 67266130Sian unsigned int attrs, 68266130Sian bfd_vma pc ATTRIBUTE_UNUSED, 69266130Sian int length ATTRIBUTE_UNUSED) 70266130Sian{ 71266130Sian disassemble_info *info = (disassemble_info *) dis_info; 72266130Sian 73266130Sian#ifdef CGEN_PRINT_NORMAL 74266130Sian CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length); 75266130Sian#endif 76266130Sian 77204431Sraj /* Print the operand as directed by the attributes. */ 78204431Sraj if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 79204431Sraj ; /* nothing to do */ 80204431Sraj else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 81204431Sraj (*info->fprintf_func) (info->stream, "%ld", value); 82204431Sraj else 83204431Sraj (*info->fprintf_func) (info->stream, "0x%lx", value); 84204431Sraj} 85204431Sraj 86204431Sraj/* Default address handler. */ 87204431Sraj 88204431Srajstatic void 89204431Srajprint_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 90204431Sraj void *dis_info, 91204431Sraj bfd_vma value, 92204431Sraj unsigned int attrs, 93204431Sraj bfd_vma pc ATTRIBUTE_UNUSED, 94204431Sraj int length ATTRIBUTE_UNUSED) 95204431Sraj{ 96204431Sraj disassemble_info *info = (disassemble_info *) dis_info; 97204431Sraj 98204431Sraj#ifdef CGEN_PRINT_ADDRESS 99204431Sraj CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length); 100204431Sraj#endif 101204431Sraj 102204431Sraj /* Print the operand as directed by the attributes. */ 103204431Sraj if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 104204431Sraj ; /* Nothing to do. */ 105204431Sraj else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) 106204431Sraj (*info->print_address_func) (value, info); 107204431Sraj else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) 108204431Sraj (*info->print_address_func) (value, info); 109204431Sraj else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 110204431Sraj (*info->fprintf_func) (info->stream, "%ld", (long) value); 111204431Sraj else 112204431Sraj (*info->fprintf_func) (info->stream, "0x%lx", (long) value); 113204431Sraj} 114204431Sraj 115204431Sraj/* Keyword print handler. */ 116204431Sraj 117266130Sianstatic void 118266130Sianprint_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 119266130Sian void *dis_info, 120266130Sian CGEN_KEYWORD *keyword_table, 121266130Sian long value, 122266130Sian unsigned int attrs ATTRIBUTE_UNUSED) 123266130Sian{ 124266130Sian disassemble_info *info = (disassemble_info *) dis_info; 125266130Sian const CGEN_KEYWORD_ENTRY *ke; 126266130Sian 127266130Sian ke = cgen_keyword_lookup_value (keyword_table, value); 128238742Simp if (ke != NULL) 129204431Sraj (*info->fprintf_func) (info->stream, "%s", ke->name); 130204431Sraj else 131204431Sraj (*info->fprintf_func) (info->stream, "???"); 132204431Sraj} 133204431Sraj 134204431Sraj/* Default insn printer. 135204431Sraj 136204431Sraj DIS_INFO is defined as `void *' so the disassembler needn't know anything 137238742Simp about disassemble_info. */ 138238742Simp 139238742Simpstatic void 140238742Simpprint_insn_normal (CGEN_CPU_DESC cd, 141238742Simp void *dis_info, 142238742Simp const CGEN_INSN *insn, 143266130Sian CGEN_FIELDS *fields, 144266130Sian bfd_vma pc, 145238742Simp int length) 146266130Sian{ 147238742Simp const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 148238742Simp disassemble_info *info = (disassemble_info *) dis_info; 149238742Simp const CGEN_SYNTAX_CHAR_TYPE *syn; 150238742Simp 151238742Simp CGEN_INIT_PRINT (cd); 152238742Simp 153238742Simp for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) 154238742Simp { 155238742Simp if (CGEN_SYNTAX_MNEMONIC_P (*syn)) 156238742Simp { 157266130Sian (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn)); 158266130Sian continue; 159266130Sian } 160266130Sian if (CGEN_SYNTAX_CHAR_P (*syn)) 161266130Sian { 162266130Sian (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn)); 163238742Simp continue; 164266130Sian } 165238742Simp 166238742Simp /* We have an operand. */ 167266130Sian @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info, 168238742Simp fields, CGEN_INSN_ATTRS (insn), pc, length); 169238742Simp } 170238742Simp} 171266130Sian 172238742Simp/* Subroutine of print_insn. Reads an insn into the given buffers and updates 173238742Simp the extract info. 174238742Simp Returns 0 if all is well, non-zero otherwise. */ 175238742Simp 176238742Simpstatic int 177238742Simpread_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 178238742Simp bfd_vma pc, 179238742Simp disassemble_info *info, 180238742Simp bfd_byte *buf, 181238742Simp int buflen, 182238742Simp CGEN_EXTRACT_INFO *ex_info, 183238742Simp unsigned long *insn_value) 184238742Simp{ 185238742Simp int status = (*info->read_memory_func) (pc, buf, buflen, info); 186238742Simp 187238742Simp if (status != 0) 188238742Simp { 189238742Simp (*info->memory_error_func) (status, pc, info); 190238742Simp return -1; 191238742Simp } 192266130Sian 193266130Sian ex_info->dis_info = info; 194266130Sian ex_info->valid = (1 << buflen) - 1; 195266130Sian ex_info->insn_bytes = buf; 196266130Sian 197266130Sian *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG); 198238742Simp return 0; 199266130Sian} 200238742Simp 201238742Simp/* Utility to print an insn. 202238742Simp BUF is the base part of the insn, target byte order, BUFLEN bytes long. 203238742Simp The result is the size of the insn in bytes or zero for an unknown insn 204238742Simp or -1 if an error occurs fetching data (memory_error_func will have 205238742Simp been called). */ 206238742Simp 207238742Simpstatic int 208238742Simpprint_insn (CGEN_CPU_DESC cd, 209238742Simp bfd_vma pc, 210238742Simp disassemble_info *info, 211238742Simp bfd_byte *buf, 212238742Simp unsigned int buflen) 213238742Simp{ 214238742Simp CGEN_INSN_INT insn_value; 215238742Simp const CGEN_INSN_LIST *insn_list; 216238742Simp CGEN_EXTRACT_INFO ex_info; 217238742Simp int basesize; 218238742Simp 219204431Sraj /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */ 220204431Sraj basesize = cd->base_insn_bitsize < buflen * 8 ? 221204431Sraj cd->base_insn_bitsize : buflen * 8; 222204431Sraj insn_value = cgen_get_insn_value (cd, buf, basesize); 223204431Sraj 224204431Sraj 225204431Sraj /* Fill in ex_info fields like read_insn would. Don't actually call 226204431Sraj read_insn, since the incoming buffer is already read (and possibly 227204431Sraj modified a la m32r). */ 228204431Sraj ex_info.valid = (1 << buflen) - 1; 229204431Sraj ex_info.dis_info = info; 230204431Sraj ex_info.insn_bytes = buf; 231204431Sraj 232204431Sraj /* The instructions are stored in hash lists. 233204431Sraj Pick the first one and keep trying until we find the right one. */ 234204431Sraj 235204431Sraj insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value); 236204431Sraj while (insn_list != NULL) 237204431Sraj { 238204431Sraj const CGEN_INSN *insn = insn_list->insn; 239204431Sraj CGEN_FIELDS fields; 240266130Sian int length; 241266130Sian unsigned long insn_value_cropped; 242266130Sian 243266130Sian#ifdef CGEN_VALIDATE_INSN_SUPPORTED 244266130Sian /* Not needed as insn shouldn't be in hash lists if not supported. */ 245266130Sian /* Supported by this cpu? */ 246266130Sian if (! @arch@_cgen_insn_supported (cd, insn)) 247266130Sian { 248266130Sian insn_list = CGEN_DIS_NEXT_INSN (insn_list); 249266130Sian continue; 250266130Sian } 251266130Sian#endif 252266130Sian 253266130Sian /* Basic bit mask must be correct. */ 254266130Sian /* ??? May wish to allow target to defer this check until the extract 255266130Sian handler. */ 256266130Sian 257266130Sian /* Base size may exceed this instruction's size. Extract the 258266130Sian relevant part from the buffer. */ 259204431Sraj if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen && 260204431Sraj (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 261204431Sraj insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 262204431Sraj info->endian == BFD_ENDIAN_BIG); 263204431Sraj else 264204431Sraj insn_value_cropped = insn_value; 265204431Sraj 266204431Sraj if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn)) 267204431Sraj == CGEN_INSN_BASE_VALUE (insn)) 268204431Sraj { 269204431Sraj /* Printing is handled in two passes. The first pass parses the 270204431Sraj machine insn and extracts the fields. The second pass prints 271204431Sraj them. */ 272204431Sraj 273266130Sian /* Make sure the entire insn is loaded into insn_value, if it 274266130Sian can fit. */ 275266130Sian if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) && 276266130Sian (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 277266130Sian { 278266130Sian unsigned long full_insn_value; 279266130Sian int rc = read_insn (cd, pc, info, buf, 280266130Sian CGEN_INSN_BITSIZE (insn) / 8, 281266130Sian & ex_info, & full_insn_value); 282266130Sian if (rc != 0) 283266130Sian return rc; 284266130Sian length = CGEN_EXTRACT_FN (cd, insn) 285266130Sian (cd, insn, &ex_info, full_insn_value, &fields, pc); 286266130Sian } 287266130Sian else 288266130Sian length = CGEN_EXTRACT_FN (cd, insn) 289266130Sian (cd, insn, &ex_info, insn_value_cropped, &fields, pc); 290266130Sian 291266130Sian /* Length < 0 -> error. */ 292266130Sian if (length < 0) 293266130Sian return length; 294266130Sian if (length > 0) 295266130Sian { 296266130Sian CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); 297266130Sian /* Length is in bits, result is in bytes. */ 298266130Sian return length / 8; 299238742Simp } 300204431Sraj } 301204431Sraj 302204431Sraj insn_list = CGEN_DIS_NEXT_INSN (insn_list); 303238742Simp } 304238742Simp 305204431Sraj return 0; 306204431Sraj} 307204431Sraj 308204431Sraj/* Default value for CGEN_PRINT_INSN. 309204431Sraj The result is the size of the insn in bytes or zero for an unknown insn 310204431Sraj or -1 if an error occured fetching bytes. */ 311204431Sraj 312204431Sraj#ifndef CGEN_PRINT_INSN 313204431Sraj#define CGEN_PRINT_INSN default_print_insn 314204431Sraj#endif 315204431Sraj 316204431Srajstatic int 317204431Srajdefault_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 318204431Sraj{ 319204431Sraj bfd_byte buf[CGEN_MAX_INSN_SIZE]; 320204431Sraj int buflen; 321204431Sraj int status; 322204431Sraj 323204431Sraj /* Attempt to read the base part of the insn. */ 324204431Sraj buflen = cd->base_insn_bitsize / 8; 325204431Sraj status = (*info->read_memory_func) (pc, buf, buflen, info); 326204431Sraj 327204431Sraj /* Try again with the minimum part, if min < base. */ 328204431Sraj if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 329204431Sraj { 330204431Sraj buflen = cd->min_insn_bitsize / 8; 331204431Sraj status = (*info->read_memory_func) (pc, buf, buflen, info); 332204431Sraj } 333204431Sraj 334204431Sraj if (status != 0) 335204431Sraj { 336204431Sraj (*info->memory_error_func) (status, pc, info); 337204431Sraj return -1; 338204431Sraj } 339204431Sraj 340204431Sraj return print_insn (cd, pc, info, buf, buflen); 341204431Sraj} 342204431Sraj 343204431Sraj/* Main entry point. 344204431Sraj Print one instruction from PC on INFO->STREAM. 345204431Sraj Return the size of the instruction (in bytes). */ 346204431Sraj 347204431Srajtypedef struct cpu_desc_list 348204431Sraj{ 349204431Sraj struct cpu_desc_list *next; 350204431Sraj CGEN_BITSET *isa; 351204431Sraj int mach; 352204431Sraj int endian; 353204431Sraj CGEN_CPU_DESC cd; 354204431Sraj} cpu_desc_list; 355204431Sraj 356204431Srajint 357204431Srajprint_insn_@arch@ (bfd_vma pc, disassemble_info *info) 358204431Sraj{ 359204431Sraj static cpu_desc_list *cd_list = 0; 360204431Sraj cpu_desc_list *cl = 0; 361204431Sraj static CGEN_CPU_DESC cd = 0; 362204431Sraj static CGEN_BITSET *prev_isa; 363204431Sraj static int prev_mach; 364204431Sraj static int prev_endian; 365204431Sraj int length; 366204431Sraj CGEN_BITSET *isa; 367204431Sraj int mach; 368204431Sraj int endian = (info->endian == BFD_ENDIAN_BIG 369204431Sraj ? CGEN_ENDIAN_BIG 370204431Sraj : CGEN_ENDIAN_LITTLE); 371204431Sraj enum bfd_architecture arch; 372204431Sraj 373204431Sraj /* ??? gdb will set mach but leave the architecture as "unknown" */ 374204431Sraj#ifndef CGEN_BFD_ARCH 375204431Sraj#define CGEN_BFD_ARCH bfd_arch_@arch@ 376204431Sraj#endif 377204431Sraj arch = info->arch; 378204431Sraj if (arch == bfd_arch_unknown) 379204431Sraj arch = CGEN_BFD_ARCH; 380238742Simp 381238742Simp /* There's no standard way to compute the machine or isa number 382238742Simp so we leave it to the target. */ 383238742Simp#ifdef CGEN_COMPUTE_MACH 384238742Simp mach = CGEN_COMPUTE_MACH (info); 385238742Simp#else 386238742Simp mach = info->mach; 387238742Simp#endif 388238742Simp 389238742Simp#ifdef CGEN_COMPUTE_ISA 390238742Simp { 391238742Simp static CGEN_BITSET *permanent_isa; 392238742Simp 393238742Simp if (!permanent_isa) 394238742Simp permanent_isa = cgen_bitset_create (MAX_ISAS); 395238742Simp isa = permanent_isa; 396238742Simp cgen_bitset_clear (isa); 397238742Simp cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info)); 398238742Simp } 399238742Simp#else 400238742Simp isa = info->insn_sets; 401238742Simp#endif 402238742Simp 403238742Simp /* If we've switched cpu's, try to find a handle we've used before */ 404238742Simp if (cd 405238742Simp && (cgen_bitset_compare (isa, prev_isa) != 0 406238742Simp || mach != prev_mach 407238742Simp || endian != prev_endian)) 408238742Simp { 409238742Simp cd = 0; 410238742Simp for (cl = cd_list; cl; cl = cl->next) 411238742Simp { 412238742Simp if (cgen_bitset_compare (cl->isa, isa) == 0 && 413238742Simp cl->mach == mach && 414238742Simp cl->endian == endian) 415238742Simp { 416238742Simp cd = cl->cd; 417238742Simp prev_isa = cd->isas; 418238742Simp break; 419238742Simp } 420238742Simp } 421238742Simp } 422238742Simp 423238742Simp /* If we haven't initialized yet, initialize the opcode table. */ 424238742Simp if (! cd) 425238742Simp { 426238742Simp const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach); 427238742Simp const char *mach_name; 428238742Simp 429238742Simp if (!arch_type) 430238742Simp abort (); 431238742Simp mach_name = arch_type->printable_name; 432238742Simp 433238742Simp prev_isa = cgen_bitset_copy (isa); 434204431Sraj prev_mach = mach; 435204431Sraj prev_endian = endian; 436204431Sraj cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa, 437204431Sraj CGEN_CPU_OPEN_BFDMACH, mach_name, 438204431Sraj CGEN_CPU_OPEN_ENDIAN, prev_endian, 439204431Sraj CGEN_CPU_OPEN_END); 440204431Sraj if (!cd) 441204431Sraj abort (); 442204431Sraj 443204431Sraj /* Save this away for future reference. */ 444204431Sraj cl = xmalloc (sizeof (struct cpu_desc_list)); 445204431Sraj cl->cd = cd; 446204431Sraj cl->isa = prev_isa; 447204431Sraj cl->mach = mach; 448204431Sraj cl->endian = endian; 449204431Sraj cl->next = cd_list; 450266130Sian cd_list = cl; 451266130Sian 452266130Sian @arch@_cgen_init_dis (cd); 453204431Sraj } 454266130Sian 455204431Sraj /* We try to have as much common code as possible. 456204431Sraj But at this point some targets need to take over. */ 457204431Sraj /* ??? Some targets may need a hook elsewhere. Try to avoid this, 458204431Sraj but if not possible try to move this hook elsewhere rather than 459204431Sraj have two hooks. */ 460204431Sraj length = CGEN_PRINT_INSN (cd, pc, info); 461204431Sraj if (length > 0) 462204431Sraj return length; 463204431Sraj if (length < 0) 464204431Sraj return -1; 465204431Sraj 466204431Sraj (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 467204431Sraj return cd->default_insn_bitsize / 8; 468204431Sraj} 469204431Sraj