1/* 2 * Copyright © 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * @APPLE_LICENSE_HEADER_END@ 30 */ 31#include <stdio.h> 32#include <string.h> 33#include <mach-o/loader.h> 34#include <mach-o/nlist.h> 35#include <mach-o/reloc.h> 36#include <mach-o/i860/reloc.h> 37#include "stuff/symbol.h" 38#include "stuff/bytesex.h" 39#include "otool.h" 40#include "../as/i860-opcode.h" 41 42static void i860_dump_operands( 43 uint32_t opcode, 44 char *format, 45 uint32_t addr, 46 uint32_t sect_addr, 47 struct relocation_info *relocs, 48 uint32_t nrelocs, 49 struct nlist *symbols, 50 uint32_t nsymbols, 51 struct symbol *sorted_symbols, 52 uint32_t nsorted_symbols, 53 char *strings, 54 uint32_t strings_size, 55 enum bool verbose); 56 57static void i860_dump_addr( 58 uint32_t addr_field, 59 int format, 60 int32_t addr, 61 uint32_t sect_addr, 62 struct relocation_info *relocs, 63 uint32_t nrelocs, 64 struct nlist *symbols, 65 uint32_t nsymbols, 66 struct symbol *sorted_symbols, 67 uint32_t nsorted_symbols, 68 char *strings, 69 uint32_t strings_size, 70 enum bool verbose); 71 72static enum bool i860_print_symbol( 73 uint32_t value, 74 struct relocation_info *rp, 75 struct nlist *symbols, 76 uint32_t nsymbols, 77 struct symbol *sorted_symbols, 78 uint32_t nsorted_symbols, 79 char *strings, 80 uint32_t strings_size, 81 enum bool verbose); 82 83/* 84 * Disassemble 1 instruction and return the length of the disassembled 85 * piece in bytes. 86 */ 87uint32_t 88i860_disassemble( 89char *sect, 90uint32_t left, 91uint32_t addr, 92uint32_t sect_addr, 93enum byte_sex object_byte_sex, 94struct relocation_info *relocs, 95uint32_t nrelocs, 96struct nlist *symbols, 97uint32_t nsymbols, 98struct symbol *sorted_symbols, 99uint32_t nsorted_symbols, 100char *strings, 101uint32_t strings_size, 102enum bool verbose) 103{ 104 enum byte_sex host_byte_sex; 105 enum bool swapped; 106 uint32_t opcode; 107 int isdual; 108 uint32_t i; 109 struct i860_opcode *op; 110 111 host_byte_sex = get_host_byte_sex(); 112 swapped = host_byte_sex != object_byte_sex; 113 114 if(left < sizeof(uint32_t)){ 115 if(left != 0){ 116 memcpy(&opcode, sect, left); 117 if(swapped) 118 opcode = SWAP_INT(opcode); 119 printf(".long\t0x%08x\n", (unsigned int)opcode); 120 } 121 printf("(end of section)\n"); 122 return(left); 123 } 124 125 memcpy(&opcode, sect, sizeof(uint32_t)); 126 if(swapped) 127 opcode = SWAP_INT(opcode); 128 129 /* 130 * The pad opcode, 0, is chosen as an illegal insn to fault if 131 * executed 132 */ 133 if(opcode == 0){ 134 printf("| Padded to i860 section boundary\n"); 135 return(4); 136 } 137 138 isdual = 0; 139 /* 140 * See if this is a dual insn mode opcode. 141 * Turn off the dual mode bit and print a d. if appropriate. 142 */ 143 if((opcode & OP_PREFIX_MASK) == PREFIX_FPU || 144 opcode == (OP_FNOP|DUAL_INSN_MODE_BIT)){ 145 if(opcode & DUAL_INSN_MODE_BIT){ 146 opcode &= ~DUAL_INSN_MODE_BIT; 147 isdual = 1; 148 } 149 } 150 /* 151 * Search the instruction table for a match for this opcode. 152 * We use a linear search because it's easy, uses the 153 * assembler insn tables, and I'm so lazy.... 154 * Feel free to recode with whizzy hashes and such. 155 */ 156 op = (struct i860_opcode *)i860_opcodes; 157 for(i = 0; i < NUMOPCODES; i++, op++){ 158 if((opcode & op->mask) == op->match){ 159 if(isdual) 160 printf("d.%-12s\t", op->name); 161 else 162 printf("%-12s\t", op->name); 163 i860_dump_operands(opcode, (char *)op->args, addr, sect_addr, 164 relocs, nrelocs, symbols, nsymbols, sorted_symbols, 165 nsorted_symbols, strings, strings_size, verbose); 166 return(sizeof(uint32_t)); 167 } 168 } 169 170 /* Didn't find the opcode. Dump it as a .long directive. */ 171 /* Build it as a little-endian insn, in a format to match asm */ 172 printf(".long\t0x%08x\n", (unsigned int)opcode); 173 return(sizeof(uint32_t)); 174} 175 176/* 32 possible valuse, of which 6 are actually used. */ 177static char *i860_controlregs[] = {"fir", "psr", "dirbase", "db", "fsr", "epsr", 178 "?","?","?","?","?","?", 179 "?","?","?","?","?","?", 180 "?","?","?","?","?","?", 181 "?","?","?","?","?","?"}; 182 183static 184void 185i860_dump_operands( 186uint32_t opcode, 187char *format, 188uint32_t addr, 189uint32_t sect_addr, 190struct relocation_info *relocs, 191uint32_t nrelocs, 192struct nlist *symbols, 193uint32_t nsymbols, 194struct symbol *sorted_symbols, 195uint32_t nsorted_symbols, 196char *strings, 197uint32_t strings_size, 198enum bool verbose) 199{ 200 uint32_t addr_field; 201 202 while(*format != '\0'){ 203 switch(*format){ 204 case '1': /* rs1 register, bits 11-15 of insn */ 205 printf("r%u", GET_RS1(opcode)); 206 break; 207 208 case '2': /* rs2 register, bits 21-25 of insn */ 209 printf("r%u", GET_RS2(opcode)); 210 break; 211 212 case 'd': /* rd register, bits 16-20 of insn */ 213 printf("r%u", GET_RD(opcode)); 214 break; 215 216 case 'E': 217 case 'e': /* frs1 floating point register, bits 11-15 of insn */ 218 printf("f%u", GET_RS1(opcode)); 219 break; 220 221 case 'F': 222 case 'f': /* frs2 floating point register, bits 21-25 of insn */ 223 printf("f%u", GET_RS2(opcode)); 224 break; 225 226 case 'H': 227 case 'G': 228 case 'g': /* frsd floating point register, bits 16-20 of insn */ 229 printf("f%u", GET_RD(opcode)); 230 break; 231 232 case 'I': /* 16 bit High portion of address, I860_RELOC_HIGH */ 233 case 'J': /* 16 bit High portion of addr requiring adjustment */ 234 addr_field = opcode & 0xFFFF; 235 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 236 nrelocs, symbols, nsymbols, sorted_symbols, 237 nsorted_symbols, strings, strings_size, verbose); 238 break; 239 240 case 'i': /* 16 bit byte address low half */ 241 addr_field = (opcode & 0xFFFF); 242 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 243 nrelocs, symbols, nsymbols, sorted_symbols, 244 nsorted_symbols, strings, strings_size, verbose); 245 break; 246 247 case 'j': /* 16 bit short address, I860_RELOC_LOW1 */ 248 addr_field = (opcode & 0xFFFE); 249 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 250 nrelocs, symbols, nsymbols, sorted_symbols, 251 nsorted_symbols, strings, strings_size, verbose); 252 break; 253 254 case 'k': /* 16 bit word/int address low half, I860_RELOC_LOW2 */ 255 addr_field = (opcode & 0xFFFC); 256 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 257 nrelocs, symbols, nsymbols, sorted_symbols, 258 nsorted_symbols, strings, strings_size, verbose); 259 break; 260 261 case 'l': /* 16 bit 8-byte address (double) low half */ 262 addr_field = (opcode & 0xFFF8); 263 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 264 nrelocs, symbols, nsymbols, sorted_symbols, 265 nsorted_symbols, strings, strings_size, verbose); 266 break; 267 268 case 'm': /* 16 bit 16-byte address (quad) low half */ 269 addr_field = (opcode & 0xFFF0); 270 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 271 nrelocs, symbols, nsymbols, sorted_symbols, 272 nsorted_symbols, strings, strings_size, verbose); 273 break; 274 275 case 'n': /* 16 bit byte aligned low half, split fields */ 276 addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FF); 277 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 278 nrelocs, symbols, nsymbols, sorted_symbols, 279 nsorted_symbols, strings, strings_size, verbose); 280 break; 281 282 case 'o': /* 16 bit short aligned low half, split fields */ 283 addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FE); 284 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 285 nrelocs, symbols, nsymbols, sorted_symbols, 286 nsorted_symbols, strings, strings_size, verbose); 287 break; 288 289 case 'p': /* 16 bit int/word aligned low half, split fields */ 290 addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FC); 291 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 292 nrelocs, symbols, nsymbols, sorted_symbols, 293 nsorted_symbols, strings, strings_size, verbose); 294 break; 295 296 case 'K': /* 26 bit branch displacement */ 297 addr_field = opcode & 0x3FFFFFF; 298 if(addr_field & 0x02000000) /* MSB set? */ 299 addr_field |= 0xFC000000; /* Sign extend */ 300 addr_field <<= 2; /* Convert to byte addr */ 301 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 302 nrelocs, symbols, nsymbols, sorted_symbols, 303 nsorted_symbols, strings, strings_size, verbose); 304 break; 305 306 case 'L': /* 16 bit split branch displacement */ 307 addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FF); 308 if(addr_field & 0x8000) /* MSB set? */ 309 addr_field |= 0xFFFF0000; /* Sign extend */ 310 addr_field <<= 2; /* Convert to byte addr */ 311 i860_dump_addr(addr_field, *format, addr, sect_addr, relocs, 312 nrelocs, symbols, nsymbols, sorted_symbols, 313 nsorted_symbols, strings, strings_size, verbose); 314 break; 315 316 case 'D': /* constant for shift opcode */ 317 printf("%u", opcode & 0xFFFF); 318 break; 319 320 case 'B': /* 5 bit immediate, for bte and btne insn */ 321 printf("%u", GET_RS1(opcode)); 322 break; 323 324 case 'C': /* Control Register */ 325 printf("%s", i860_controlregs[GET_RS2(opcode)]); 326 break; 327 328 default: 329 printf("%c", *format); 330 break; 331 } 332 ++format; 333 } 334 printf("\n"); 335} 336 337static 338void 339i860_dump_addr( 340uint32_t addr_field, 341int format, 342int32_t addr, 343uint32_t sect_addr, 344struct relocation_info *relocs, 345uint32_t nrelocs, 346struct nlist *symbols, 347uint32_t nsymbols, 348struct symbol *sorted_symbols, 349uint32_t nsorted_symbols, 350char *strings, 351uint32_t strings_size, 352enum bool verbose) 353{ 354 uint32_t i; 355 struct relocation_info *rp, *pairp; 356 struct scattered_relocation_info *sreloc; 357 char *prefix; 358 359 rp = NULL; 360 pairp = NULL; 361 if(nrelocs){ 362 for(i = 0; i < nrelocs; i++){ 363 if(((relocs[i].r_address) & R_SCATTERED) != 0){ 364 sreloc = (struct scattered_relocation_info *)(relocs + i); 365 if(sreloc->r_type == I860_RELOC_PAIR){ 366 fprintf(stderr, "Stray I860_RELOC_PAIR relocation " 367 "entry %u\n", i); 368 continue; 369 } 370 if(sreloc->r_type == I860_RELOC_HIGH || 371 sreloc->r_type == I860_RELOC_HIGHADJ || 372 sreloc->r_type == I860_RELOC_SECTDIFF){ 373 if(i+1 >= nrelocs || 374 relocs[i+1].r_type != I860_RELOC_PAIR){ 375 fprintf(stderr, "No I860_RELOC_PAIR relocation " 376 "entry after entry %u\n", i); 377 } 378 else{ 379 if(((relocs[i+1].r_address) & R_SCATTERED) != 0){ 380 sreloc = (struct scattered_relocation_info *) 381 (relocs + i + 1); 382 if(sreloc->r_type != I860_RELOC_PAIR) 383 fprintf(stderr, "No I860_RELOC_PAIR " 384 "relocation entry after entry " 385 "%u\n", i); 386 } 387 else if(relocs[i+1].r_type != I860_RELOC_PAIR){ 388 fprintf(stderr, "No I860_RELOC_PAIR relocation " 389 "entry after entry %u\n", i); 390 } 391 i++; 392 continue; 393 } 394 } 395 } 396 if(relocs[i].r_type == I860_RELOC_PAIR){ 397 fprintf(stderr, "Stray I860_RELOC_PAIR relocation entry " 398 "%u\n", i); 399 continue; 400 } 401 if((uint32_t)relocs[i].r_address == addr - sect_addr){ 402 rp = &relocs[i]; 403 if(rp->r_type == I860_RELOC_HIGH || 404 rp->r_type == I860_RELOC_HIGHADJ || 405 rp->r_type == I860_RELOC_SECTDIFF){ 406 if(i+1 < nrelocs){ 407 pairp = &rp[1]; 408 if(pairp->r_type != I860_RELOC_PAIR){ 409 fprintf(stderr, "No I860_RELOC_PAIR relocation " 410 "entry after entry %u\n", i); 411 rp = NULL; 412 pairp = NULL; 413 continue; 414 } 415 } 416 } 417 break; 418 } 419 if(relocs[i].r_type == I860_RELOC_HIGH || 420 relocs[i].r_type == I860_RELOC_HIGHADJ || 421 relocs[i].r_type == I860_RELOC_SECTDIFF){ 422 if(i+1 >= nrelocs || 423 relocs[i+1].r_type != I860_RELOC_PAIR){ 424 fprintf(stderr, "No I860_RELOC_PAIR relocation " 425 "entry after entry %u\n", i); 426 } 427 else 428 i++; 429 } 430 } 431 } 432 433 /* Guess a prefix code for the immediate value */ 434 prefix = NULL; 435 if((rp != NULL && rp->r_type == I860_RELOC_HIGH) || format == 'I') 436 prefix = "h%"; 437 else if((rp != NULL && rp->r_type == I860_RELOC_HIGHADJ) || 438 format == 'J' ) 439 prefix = "ha%"; 440 else if(rp != NULL && rp->r_type >= I860_RELOC_LOW0 && 441 rp->r_type <= I860_RELOC_SPLIT2){ 442 if(rp->r_pcrel == 0) /* Don't use for bte insns */ 443 prefix = "l%"; 444 } 445 if(rp != NULL && (rp->r_type == I860_RELOC_HIGH || 446 rp->r_type == I860_RELOC_HIGHADJ)){ 447 if(pairp->r_type == I860_RELOC_PAIR){ 448 if(rp->r_type == I860_RELOC_HIGHADJ) 449 450 if(pairp->r_address & 0x8000) 451 addr_field = (addr_field << 16) + 452 (0xffff0000 | (pairp->r_address & 0xffff)); 453 else 454 addr_field = (addr_field << 16) + 455 (pairp->r_address & 0xffff); 456 else 457 addr_field = (addr_field << 16) | 458 (pairp->r_address & 0xffff); 459 } 460 } 461 if(prefix != NULL) 462 printf("%s", prefix); 463 464 if(format == 'K' || format == 'L'){ /* branch displacement */ 465 if(i860_print_symbol(addr + 4 + ((int32_t)addr_field), rp, 466 symbols, nsymbols, sorted_symbols, nsorted_symbols, 467 strings, strings_size, verbose) == TRUE) 468 return; 469 printf(".%+d", (int32_t)(addr_field + 4)); 470 return; 471 } 472 if(i860_print_symbol(addr_field, rp, symbols, nsymbols, 473 sorted_symbols, nsorted_symbols, strings, 474 strings_size, verbose) == TRUE) 475 return; 476 477 /* we can't find anything else to do with it. */ 478 printf("0x%x", (unsigned int)addr_field); 479} 480 481/* 482 * i860_print_symbol prints a symbol name for the addr and relocation entry 483 * if a symbol exist with the same address. Nothing else is printed, no 484 * whitespace, no newline. If it prints something then it returns TRUE, else 485 * it returns FALSE. 486 */ 487static 488enum bool 489i860_print_symbol( 490uint32_t value, 491struct relocation_info *rp, 492struct nlist *symbols, 493uint32_t nsymbols, 494struct symbol *sorted_symbols, 495uint32_t nsorted_symbols, 496char *strings, 497uint32_t strings_size, 498enum bool verbose) 499{ 500 int32_t high, low, mid; 501 502 if(verbose == FALSE) 503 return(FALSE); 504 505 if(rp != NULL){ 506 if(rp->r_extern && 507 rp->r_symbolnum < nsymbols){ 508 if(value != 0) 509 printf("%s+0x%x", strings + 510 symbols[rp->r_symbolnum].n_un.n_strx, 511 (unsigned int)value); 512 else 513 printf("%s",strings + symbols[rp->r_symbolnum].n_un.n_strx); 514 return(TRUE); 515 } 516 } 517 518 low = 0; 519 high = nsorted_symbols - 1; 520 mid = (high - low) / 2; 521 while(high >= low){ 522 if(sorted_symbols[mid].n_value == value){ 523 printf("%s", sorted_symbols[mid].name); 524 return(TRUE); 525 } 526 if(sorted_symbols[mid].n_value > value){ 527 high = mid - 1; 528 mid = (high + low) / 2; 529 } 530 else{ 531 low = mid + 1; 532 mid = (high + low) / 2; 533 } 534 } 535 return(FALSE); 536} 537