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