1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 6 static int debug = 0; 7 8 #define BITS(a, b) ((1<<(b+1))-(1<<a)) 9 10 #define LSR(v, s) ((ulong)(v) >> (s)) 11 #define ASR(v, s) ((long)(v) >> (s)) 12 #define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) 13 14 15 16 typedef struct Instr Instr; 17 struct Instr 18 { 19 Map *map; 20 ulong w; 21 uvlong addr; 22 uchar op; /* super opcode */ 23 24 uchar cond; /* bits 28-31 */ 25 uchar store; /* bit 20 */ 26 27 uchar rd; /* bits 12-15 */ 28 uchar rn; /* bits 16-19 */ 29 uchar rs; /* bits 0-11 (shifter operand) */ 30 31 long imm; /* rotated imm */ 32 char* curr; /* fill point in buffer */ 33 char* end; /* end of buffer */ 34 char* err; /* error message */ 35 }; 36 37 typedef struct Opcode Opcode; 38 struct Opcode 39 { 40 char* o; 41 void (*fmt)(Opcode*, Instr*); 42 uvlong (*foll)(Map*, Rgetter, Instr*, uvlong); 43 char* a; 44 }; 45 46 static void format(char*, Instr*, char*); 47 static char FRAMENAME[] = ".frame"; 48 49 /* 50 * Arm-specific debugger interface 51 */ 52 53 static char *armexcep(Map*, Rgetter); 54 static int armfoll(Map*, uvlong, Rgetter, uvlong*); 55 static int arminst(Map*, uvlong, char, char*, int); 56 static int armdas(Map*, uvlong, char*, int); 57 static int arminstlen(Map*, uvlong); 58 59 /* 60 * Debugger interface 61 */ 62 Machdata armmach = 63 { 64 {0x70, 0x00, 0x20, 0xD1}, /* break point */ /* D1200070 */ 65 4, /* break point size */ 66 67 leswab, /* short to local byte order */ 68 leswal, /* long to local byte order */ 69 leswav, /* long to local byte order */ 70 risctrace, /* C traceback */ 71 riscframe, /* Frame finder */ 72 armexcep, /* print exception */ 73 0, /* breakpoint fixup */ 74 0, /* single precision float printer */ 75 0, /* double precision float printer */ 76 armfoll, /* following addresses */ 77 arminst, /* print instruction */ 78 armdas, /* dissembler */ 79 arminstlen, /* instruction size */ 80 }; 81 82 static char* 83 armexcep(Map *map, Rgetter rget) 84 { 85 uvlong c; 86 87 c = (*rget)(map, "TYPE"); 88 switch ((int)c&0x1f) { 89 case 0x11: 90 return "Fiq interrupt"; 91 case 0x12: 92 return "Mirq interrupt"; 93 case 0x13: 94 return "SVC/SWI Exception"; 95 case 0x17: 96 return "Prefetch Abort/Data Abort"; 97 case 0x18: 98 return "Data Abort"; 99 case 0x1b: 100 return "Undefined instruction/Breakpoint"; 101 case 0x1f: 102 return "Sys trap"; 103 default: 104 return "Undefined trap"; 105 } 106 } 107 108 static 109 char* cond[16] = 110 { 111 "EQ", "NE", "CS", "CC", 112 "MI", "PL", "VS", "VC", 113 "HI", "LS", "GE", "LT", 114 "GT", "LE", 0, "NV" 115 }; 116 117 static 118 char* shtype[4] = 119 { 120 "<<", ">>", "->", "@>" 121 }; 122 123 static 124 char *hb[4] = 125 { 126 "???", "HU", "B", "H" 127 }; 128 129 static 130 char* addsub[2] = 131 { 132 "-", "+", 133 }; 134 135 int 136 armclass(long w) 137 { 138 int op, done, cp; 139 140 op = (w >> 25) & 0x7; 141 switch(op) { 142 case 0: /* data processing r,r,r */ 143 op = ((w >> 4) & 0xf); 144 if(op == 0x9) { 145 op = 48+16; /* mul, swp or *rex */ 146 if((w & 0x0ff00fff) == 0x01900f9f) { 147 op = 93; /* ldrex */ 148 break; 149 } 150 if((w & 0x0ff00ff0) == 0x01800f90) { 151 op = 94; /* strex */ 152 break; 153 } 154 if(w & (1<<24)) { 155 op += 2; 156 if(w & (1<<22)) 157 op++; /* swpb */ 158 break; 159 } 160 if(w & (1<<23)) { /* mullu */ 161 op = (48+24+4+4+2+2+4); 162 if(w & (1<<22)) /* mull */ 163 op += 2; 164 } 165 if(w & (1<<21)) 166 op++; /* mla */ 167 break; 168 } 169 if((op & 0x9) == 0x9) /* ld/st byte/half s/u */ 170 { 171 op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); 172 break; 173 } 174 op = (w >> 21) & 0xf; 175 if(w & (1<<4)) 176 op += 32; 177 else 178 if((w & (31<<7)) || (w & (1<<5))) 179 op += 16; 180 break; 181 case 1: /* data processing i,r,r */ 182 op = (48) + ((w >> 21) & 0xf); 183 break; 184 case 2: /* load/store byte/word i(r) */ 185 if ((w & 0xffffff8f) == 0xf57ff00f) { /* barriers, clrex */ 186 done = 1; 187 switch ((w >> 4) & 7) { 188 case 1: 189 op = 95; /* clrex */ 190 break; 191 case 4: 192 op = 96; /* dsb */ 193 break; 194 case 5: 195 op = 97; /* dmb */ 196 break; 197 case 6: 198 op = 98; /* isb */ 199 break; 200 default: 201 done = 0; 202 break; 203 } 204 if (done) 205 break; 206 } 207 op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); 208 break; 209 case 3: /* load/store byte/word (r)(r) */ 210 op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); 211 break; 212 case 4: /* block data transfer (r)(r) */ 213 if ((w & 0xfe50ffff) == 0xf8100a00) { /* v7 RFE */ 214 op = 99; 215 break; 216 } 217 op = (48+24+4+4) + ((w >> 20) & 0x1); 218 break; 219 case 5: /* branch / branch link */ 220 op = (48+24+4+4+2) + ((w >> 24) & 0x1); 221 break; 222 case 7: /* coprocessor crap */ 223 cp = (w >> 8) & 0xF; 224 if(cp == 10 || cp == 11){ /* vfp */ 225 if((w >> 4) & 0x1){ 226 /* vfp register transfer */ 227 switch((w >> 21) & 0x7){ 228 case 0: 229 op = 118 + ((w >> 20) & 0x1); 230 break; 231 case 7: 232 op = 118+2 + ((w >> 20) & 0x1); 233 break; 234 default: 235 op = (48+24+4+4+2+2+4+4); 236 break; 237 } 238 break; 239 } 240 /* vfp data processing */ 241 if(((w >> 23) & 0x1) == 0){ 242 op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1); 243 break; 244 } 245 switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){ 246 case 0: 247 op = 108; 248 break; 249 case 7: 250 if(((w >> 19) & 0x1) == 0) 251 if(((w >> 17) & 0x1) == 0) 252 op = 109 + ((w >> 16) & 0x4) + 253 ((w >> 15) & 0x2) + 254 ((w >> 7) & 0x1); 255 else if(((w >> 16) & 0x7) == 0x7) 256 op = 117; 257 else 258 switch((w >> 16) & 0x7){ 259 case 0: 260 case 4: 261 case 5: 262 op = 117; 263 break; 264 } 265 break; 266 } 267 if(op == 7) 268 op = (48+24+4+4+2+2+4+4); 269 break; 270 } 271 op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1); 272 break; 273 case 6: /* vfp load / store */ 274 if(((w >> 21) &0x9) == 0x8){ 275 op = 122 + ((w >> 20) & 0x1); 276 break; 277 } 278 /* fall through */ 279 default: 280 op = (48+24+4+4+2+2+4+4); 281 break; 282 } 283 return op; 284 } 285 286 static int 287 decode(Map *map, uvlong pc, Instr *i) 288 { 289 ulong w; 290 291 if(get4(map, pc, &w) < 0) { 292 werrstr("can't read instruction: %r"); 293 return -1; 294 } 295 i->w = w; 296 i->addr = pc; 297 i->cond = (w >> 28) & 0xF; 298 i->op = armclass(w); 299 i->map = map; 300 return 1; 301 } 302 303 #pragma varargck argpos bprint 2 304 305 static void 306 bprint(Instr *i, char *fmt, ...) 307 { 308 va_list arg; 309 310 va_start(arg, fmt); 311 i->curr = vseprint(i->curr, i->end, fmt, arg); 312 va_end(arg); 313 } 314 315 static int 316 plocal(Instr *i) 317 { 318 char *reg; 319 Symbol s; 320 char *fn; 321 int class; 322 int offset; 323 324 if(!findsym(i->addr, CTEXT, &s)) { 325 if(debug)fprint(2,"fn not found @%llux: %r\n", i->addr); 326 return 0; 327 } 328 fn = s.name; 329 if (!findlocal(&s, FRAMENAME, &s)) { 330 if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name); 331 return 0; 332 } 333 if(s.value > i->imm) { 334 class = CAUTO; 335 offset = s.value-i->imm; 336 reg = "(SP)"; 337 } else { 338 class = CPARAM; 339 offset = i->imm-s.value-4; 340 reg = "(FP)"; 341 } 342 if(!getauto(&s, offset, class, &s)) { 343 if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn, 344 class == CAUTO ? " auto" : "param", offset); 345 return 0; 346 } 347 bprint(i, "%s%c%lld%s", s.name, class == CPARAM ? '+' : '-', s.value, reg); 348 return 1; 349 } 350 351 /* 352 * Print value v as name[+offset] 353 */ 354 static int 355 gsymoff(char *buf, int n, ulong v, int space) 356 { 357 Symbol s; 358 int r; 359 long delta; 360 361 r = delta = 0; /* to shut compiler up */ 362 if (v) { 363 r = findsym(v, space, &s); 364 if (r) 365 delta = v-s.value; 366 if (delta < 0) 367 delta = -delta; 368 } 369 if (v == 0 || r == 0 || delta >= 4096) 370 return snprint(buf, n, "#%lux", v); 371 if (strcmp(s.name, ".string") == 0) 372 return snprint(buf, n, "#%lux", v); 373 if (!delta) 374 return snprint(buf, n, "%s", s.name); 375 if (s.type != 't' && s.type != 'T') 376 return snprint(buf, n, "%s+%llux", s.name, v-s.value); 377 else 378 return snprint(buf, n, "#%lux", v); 379 } 380 381 static void 382 armdps(Opcode *o, Instr *i) 383 { 384 i->store = (i->w >> 20) & 1; 385 i->rn = (i->w >> 16) & 0xf; 386 i->rd = (i->w >> 12) & 0xf; 387 i->rs = (i->w >> 0) & 0xf; 388 if(i->rn == 15 && i->rs == 0) { 389 if(i->op == 8) { 390 format("MOVW", i,"CPSR, R%d"); 391 return; 392 } else 393 if(i->op == 10) { 394 format("MOVW", i,"SPSR, R%d"); 395 return; 396 } 397 } else 398 if(i->rn == 9 && i->rd == 15) { 399 if(i->op == 9) { 400 format("MOVW", i, "R%s, CPSR"); 401 return; 402 } else 403 if(i->op == 11) { 404 format("MOVW", i, "R%s, SPSR"); 405 return; 406 } 407 } 408 format(o->o, i, o->a); 409 } 410 411 static void 412 armdpi(Opcode *o, Instr *i) 413 { 414 ulong v; 415 int c; 416 417 v = (i->w >> 0) & 0xff; 418 c = (i->w >> 8) & 0xf; 419 while(c) { 420 v = (v<<30) | (v>>2); 421 c--; 422 } 423 i->imm = v; 424 i->store = (i->w >> 20) & 1; 425 i->rn = (i->w >> 16) & 0xf; 426 i->rd = (i->w >> 12) & 0xf; 427 i->rs = i->w&0x0f; 428 429 /* RET is encoded as ADD #0,R14,R15 */ 430 if((i->w & 0x0fffffff) == 0x028ef000){ 431 format("RET%C", i, ""); 432 return; 433 } 434 if((i->w & 0x0ff0ffff) == 0x0280f000){ 435 format("B%C", i, "0(R%n)"); 436 return; 437 } 438 format(o->o, i, o->a); 439 } 440 441 static void 442 armsdti(Opcode *o, Instr *i) 443 { 444 ulong v; 445 446 v = i->w & 0xfff; 447 if(!(i->w & (1<<23))) 448 v = -v; 449 i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); 450 i->imm = v; 451 i->rn = (i->w >> 16) & 0xf; 452 i->rd = (i->w >> 12) & 0xf; 453 /* RET is encoded as LW.P x,R13,R15 */ 454 if ((i->w & 0x0ffff000) == 0x049df000) 455 { 456 format("RET%C%p", i, "%I"); 457 return; 458 } 459 format(o->o, i, o->a); 460 } 461 462 static void 463 armvstdi(Opcode *o, Instr *i) 464 { 465 ulong v; 466 467 v = (i->w & 0xff) << 2; 468 if(!(i->w & (1<<23))) 469 v = -v; 470 i->imm = v; 471 i->rn = (i->w >> 16) & 0xf; 472 i->rd = (i->w >> 12) & 0xf; 473 format(o->o, i, o->a); 474 } 475 476 /* arm V4 ld/st halfword, signed byte */ 477 static void 478 armhwby(Opcode *o, Instr *i) 479 { 480 i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); 481 i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf); 482 if (!(i->w & (1 << 23))) 483 i->imm = - i->imm; 484 i->rn = (i->w >> 16) & 0xf; 485 i->rd = (i->w >> 12) & 0xf; 486 i->rs = (i->w >> 0) & 0xf; 487 format(o->o, i, o->a); 488 } 489 490 static void 491 armsdts(Opcode *o, Instr *i) 492 { 493 i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); 494 i->rs = (i->w >> 0) & 0xf; 495 i->rn = (i->w >> 16) & 0xf; 496 i->rd = (i->w >> 12) & 0xf; 497 format(o->o, i, o->a); 498 } 499 500 static void 501 armbdt(Opcode *o, Instr *i) 502 { 503 i->store = (i->w >> 21) & 0x3; /* S & W bits */ 504 i->rn = (i->w >> 16) & 0xf; 505 i->imm = i->w & 0xffff; 506 if(i->w == 0xe8fd8000) 507 format("RFE", i, ""); 508 else 509 format(o->o, i, o->a); 510 } 511 512 static void 513 armund(Opcode *o, Instr *i) 514 { 515 format(o->o, i, o->a); 516 } 517 518 static void 519 armcdt(Opcode *o, Instr *i) 520 { 521 format(o->o, i, o->a); 522 } 523 524 static void 525 armunk(Opcode *o, Instr *i) 526 { 527 format(o->o, i, o->a); 528 } 529 530 static void 531 armb(Opcode *o, Instr *i) 532 { 533 ulong v; 534 535 v = i->w & 0xffffff; 536 if(v & 0x800000) 537 v |= ~0xffffff; 538 i->imm = (v<<2) + i->addr + 8; 539 format(o->o, i, o->a); 540 } 541 542 static void 543 armco(Opcode *o, Instr *i) /* coprocessor instructions */ 544 { 545 int op, p, cp; 546 547 char buf[1024]; 548 549 i->rn = (i->w >> 16) & 0xf; 550 i->rd = (i->w >> 12) & 0xf; 551 i->rs = i->w&0xf; 552 cp = (i->w >> 8) & 0xf; 553 p = (i->w >> 5) & 0x7; 554 if(i->w&(1<<4)) { 555 op = (i->w >> 21) & 0x07; 556 snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p); 557 } else { 558 op = (i->w >> 20) & 0x0f; 559 snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p); 560 } 561 format(o->o, i, buf); 562 } 563 564 static int 565 armcondpass(Map *map, Rgetter rget, uchar cond) 566 { 567 uvlong psr; 568 uchar n; 569 uchar z; 570 uchar c; 571 uchar v; 572 573 psr = rget(map, "PSR"); 574 n = (psr >> 31) & 1; 575 z = (psr >> 30) & 1; 576 c = (psr >> 29) & 1; 577 v = (psr >> 28) & 1; 578 579 switch(cond) { 580 default: 581 case 0: return z; 582 case 1: return !z; 583 case 2: return c; 584 case 3: return !c; 585 case 4: return n; 586 case 5: return !n; 587 case 6: return v; 588 case 7: return !v; 589 case 8: return c && !z; 590 case 9: return !c || z; 591 case 10: return n == v; 592 case 11: return n != v; 593 case 12: return !z && (n == v); 594 case 13: return z && (n != v); 595 case 14: return 1; 596 case 15: return 0; 597 } 598 } 599 600 static ulong 601 armshiftval(Map *map, Rgetter rget, Instr *i) 602 { 603 if(i->w & (1 << 25)) { /* immediate */ 604 ulong imm = i->w & BITS(0, 7); 605 ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */ 606 return ROR(imm, s); 607 } else { 608 char buf[8]; 609 ulong v; 610 ulong s = (i->w & BITS(7,11)) >> 7; 611 612 sprint(buf, "R%ld", i->w & 0xf); 613 v = rget(map, buf); 614 615 switch((i->w & BITS(4, 6)) >> 4) { 616 default: 617 case 0: /* LSLIMM */ 618 return v << s; 619 case 1: /* LSLREG */ 620 sprint(buf, "R%lud", s >> 1); 621 s = rget(map, buf) & 0xFF; 622 if(s >= 32) return 0; 623 return v << s; 624 case 2: /* LSRIMM */ 625 return LSR(v, s); 626 case 3: /* LSRREG */ 627 sprint(buf, "R%ld", s >> 1); 628 s = rget(map, buf) & 0xFF; 629 if(s >= 32) return 0; 630 return LSR(v, s); 631 case 4: /* ASRIMM */ 632 if(s == 0) { 633 if((v & (1U<<31)) == 0) 634 return 0; 635 return 0xFFFFFFFF; 636 } 637 return ASR(v, s); 638 case 5: /* ASRREG */ 639 sprint(buf, "R%ld", s >> 1); 640 s = rget(map, buf) & 0xFF; 641 if(s >= 32) { 642 if((v & (1U<<31)) == 0) 643 return 0; 644 return 0xFFFFFFFF; 645 } 646 return ASR(v, s); 647 case 6: /* RORIMM */ 648 if(s == 0) { 649 ulong c = (rget(map, "PSR") >> 29) & 1; 650 651 return (c << 31) | LSR(v, 1); 652 } 653 return ROR(v, s); 654 case 7: /* RORREG */ 655 sprint(buf, "R%ld", (s>>1)&0xF); 656 s = rget(map, buf); 657 if(s == 0 || (s & 0xF) == 0) 658 return v; 659 return ROR(v, s & 0xF); 660 } 661 } 662 } 663 664 static int 665 nbits(ulong v) 666 { 667 int n = 0; 668 int i; 669 670 for(i=0; i < 32 ; i++) { 671 if(v & 1) ++n; 672 v >>= 1; 673 } 674 675 return n; 676 } 677 678 static ulong 679 armmaddr(Map *map, Rgetter rget, Instr *i) 680 { 681 ulong v; 682 ulong nb; 683 char buf[8]; 684 ulong rn; 685 686 rn = (i->w >> 16) & 0xf; 687 sprint(buf,"R%ld", rn); 688 689 v = rget(map, buf); 690 nb = nbits(i->w & ((1 << 15) - 1)); 691 692 switch((i->w >> 23) & 3) { 693 default: 694 case 0: return (v - (nb*4)) + 4; 695 case 1: return v; 696 case 2: return v - (nb*4); 697 case 3: return v + 4; 698 } 699 } 700 701 static uvlong 702 armaddr(Map *map, Rgetter rget, Instr *i) 703 { 704 char buf[8]; 705 ulong rn; 706 707 snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf); 708 rn = rget(map, buf); 709 710 if((i->w & (1<<24)) == 0) /* POSTIDX */ 711 return rn; 712 713 if((i->w & (1<<25)) == 0) { /* OFFSET */ 714 if(i->w & (1U<<23)) 715 return rn + (i->w & BITS(0,11)); 716 return rn - (i->w & BITS(0,11)); 717 } else { /* REGOFF */ 718 ulong index = 0; 719 uchar c; 720 uchar rm; 721 722 sprint(buf, "R%ld", i->w & 0xf); 723 rm = rget(map, buf); 724 725 switch((i->w & BITS(5,6)) >> 5) { 726 case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break; 727 case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break; 728 case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break; 729 case 3: 730 if((i->w & BITS(7,11)) == 0) { 731 c = (rget(map, "PSR") >> 29) & 1; 732 index = c << 31 | LSR(rm, 1); 733 } else { 734 index = ROR(rm, ((i->w & BITS(7,11)) >> 7)); 735 } 736 break; 737 } 738 if(i->w & (1<<23)) 739 return rn + index; 740 return rn - index; 741 } 742 } 743 744 static uvlong 745 armfadd(Map *map, Rgetter rget, Instr *i, uvlong pc) 746 { 747 char buf[8]; 748 int r; 749 750 r = (i->w >> 12) & 0xf; 751 if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf)) 752 return pc+4; 753 754 r = (i->w >> 16) & 0xf; 755 sprint(buf, "R%d", r); 756 757 return rget(map, buf) + armshiftval(map, rget, i); 758 } 759 760 static uvlong 761 armfmovm(Map *map, Rgetter rget, Instr *i, uvlong pc) 762 { 763 ulong v; 764 ulong addr; 765 766 v = i->w & 1<<15; 767 if(!v || !armcondpass(map, rget, (i->w>>28)&0xf)) 768 return pc+4; 769 770 addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15)); 771 if(get4(map, addr, &v) < 0) { 772 werrstr("can't read addr: %r"); 773 return -1; 774 } 775 return v; 776 } 777 778 static uvlong 779 armfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc) 780 { 781 if(!armcondpass(map, rget, (i->w >> 28) & 0xf)) 782 return pc+4; 783 784 return pc + (((signed long)i->w << 8) >> 6) + 8; 785 } 786 787 static uvlong 788 armfmov(Map *map, Rgetter rget, Instr *i, uvlong pc) 789 { 790 ulong rd, v; 791 792 rd = (i->w >> 12) & 0xf; 793 if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf)) 794 return pc+4; 795 796 /* LDR */ 797 /* BUG: Needs LDH/B, too */ 798 if(((i->w>>26)&0x3) == 1) { 799 if(get4(map, armaddr(map, rget, i), &v) < 0) { 800 werrstr("can't read instruction: %r"); 801 return pc+4; 802 } 803 return v; 804 } 805 806 /* MOV */ 807 v = armshiftval(map, rget, i); 808 809 return v; 810 } 811 812 static Opcode opcodes[] = 813 { 814 "AND%C%S", armdps, 0, "R%s,R%n,R%d", 815 "EOR%C%S", armdps, 0, "R%s,R%n,R%d", 816 "SUB%C%S", armdps, 0, "R%s,R%n,R%d", 817 "RSB%C%S", armdps, 0, "R%s,R%n,R%d", 818 "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d", 819 "ADC%C%S", armdps, 0, "R%s,R%n,R%d", 820 "SBC%C%S", armdps, 0, "R%s,R%n,R%d", 821 "RSC%C%S", armdps, 0, "R%s,R%n,R%d", 822 "TST%C%S", armdps, 0, "R%s,R%n", 823 "TEQ%C%S", armdps, 0, "R%s,R%n", 824 "CMP%C%S", armdps, 0, "R%s,R%n", 825 "CMN%C%S", armdps, 0, "R%s,R%n", 826 "ORR%C%S", armdps, 0, "R%s,R%n,R%d", 827 "MOVW%C%S", armdps, armfmov, "R%s,R%d", 828 "BIC%C%S", armdps, 0, "R%s,R%n,R%d", 829 "MVN%C%S", armdps, 0, "R%s,R%d", 830 831 /* 16 */ 832 "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 833 "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 834 "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 835 "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 836 "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d", 837 "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 838 "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 839 "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 840 "TST%C%S", armdps, 0, "(R%s%h%m),R%n", 841 "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n", 842 "CMP%C%S", armdps, 0, "(R%s%h%m),R%n", 843 "CMN%C%S", armdps, 0, "(R%s%h%m),R%n", 844 "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 845 "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d", 846 "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", 847 "MVN%C%S", armdps, 0, "(R%s%h%m),R%d", 848 849 /* 32 */ 850 "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 851 "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 852 "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 853 "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 854 "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d", 855 "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 856 "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 857 "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 858 "TST%C%S", armdps, 0, "(R%s%hR%M),R%n", 859 "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n", 860 "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n", 861 "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n", 862 "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 863 "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d", 864 "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", 865 "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d", 866 867 /* 48 */ 868 "AND%C%S", armdpi, 0, "$#%i,R%n,R%d", 869 "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d", 870 "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d", 871 "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d", 872 "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d", 873 "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d", 874 "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d", 875 "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d", 876 "TST%C%S", armdpi, 0, "$#%i,R%n", 877 "TEQ%C%S", armdpi, 0, "$#%i,R%n", 878 "CMP%C%S", armdpi, 0, "$#%i,R%n", 879 "CMN%C%S", armdpi, 0, "$#%i,R%n", 880 "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d", 881 "MOVW%C%S", armdpi, armfmov, "$#%i,R%d", 882 "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d", 883 "MVN%C%S", armdpi, 0, "$#%i,R%d", 884 885 /* 48+16 */ 886 "MUL%C%S", armdpi, 0, "R%M,R%s,R%n", 887 "MULA%C%S", armdpi, 0, "R%M,R%s,R%n,R%d", 888 "SWPW", armdpi, 0, "R%s,(R%n),R%d", 889 "SWPB", armdpi, 0, "R%s,(R%n),R%d", 890 891 /* 48+16+4 */ 892 "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)", 893 "MOV%u%C%p", armhwby, 0, "R%d,%I", 894 "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d", 895 "MOV%u%C%p", armhwby, armfmov, "%I,R%d", 896 897 /* 48+24 */ 898 "MOVW%C%p", armsdti, 0, "R%d,%I", 899 "MOVB%C%p", armsdti, 0, "R%d,%I", 900 "MOVW%C%p", armsdti, armfmov, "%I,R%d", 901 "MOVBU%C%p", armsdti, armfmov, "%I,R%d", 902 903 "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", 904 "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", 905 "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", 906 "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", 907 908 "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)", 909 "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]", 910 911 "B%C", armb, armfbranch, "%b", 912 "BL%C", armb, armfbranch, "%b", 913 914 "CDP%C", armco, 0, "", 915 "CDP%C", armco, 0, "", 916 "MCR%C", armco, 0, "", 917 "MRC%C", armco, 0, "", 918 919 /* 48+24+4+4+2+2+4 */ 920 "MULLU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", 921 "MULALU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", 922 "MULL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", 923 "MULAL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", 924 925 /* 48+24+4+4+2+2+4+4 = 92 */ 926 "UNK", armunk, 0, "", 927 928 /* new v7 arch instructions */ 929 /* 93 */ 930 "LDREX", armdpi, 0, "(R%n),R%d", 931 "STREX", armdpi, 0, "R%s,(R%n),R%d", 932 "CLREX", armunk, 0, "", 933 934 /* 96 */ 935 "DSB", armunk, 0, "", 936 "DMB", armunk, 0, "", 937 "ISB", armunk, 0, "", 938 939 /* 99 */ 940 "RFEV7%P%a", armbdt, 0, "(R%n)", 941 942 /* 100 */ 943 "MLA%f%C", armdps, 0, "F%s,F%n,F%d", 944 "MLS%f%C", armdps, 0, "F%s,F%n,F%d", 945 "NMLS%f%C", armdps, 0, "F%s,F%n,F%d", 946 "NMLA%f%C", armdps, 0, "F%s,F%n,F%d", 947 "MUL%f%C", armdps, 0, "F%s,F%n,F%d", 948 "NMUL%f%C", armdps, 0, "F%s,F%n,F%d", 949 "ADD%f%C", armdps, 0, "F%s,F%n,F%d", 950 "SUB%f%C", armdps, 0, "F%s,F%n,F%d", 951 "DIV%f%C", armdps, 0, "F%s,F%n,F%d", 952 953 /* 109 */ 954 "MOV%f%C", armdps, 0, "F%s,F%d", 955 "ABS%f%C", armdps, 0, "F%s,F%d", 956 "NEG%f%C", armdps, 0, "F%s,F%d", 957 "SQRT%f%C", armdps, 0, "F%s,F%d", 958 "CMP%f%C", armdps, 0, "F%s,F%d", 959 "CMPE%f%C", armdps, 0, "F%s,F%d", 960 "CMP%f%C", armdps, 0, "$0.0,F%d", 961 "CMPE%f%C", armdps, 0, "$0.0,F%d", 962 963 /* 117 */ 964 "MOV%F%R%C", armdps, 0, "F%s,F%d", 965 966 /* 118 */ 967 "MOVW%C", armdps, 0, "R%d,F%n", 968 "MOVW%C", armdps, 0, "F%n,R%d", 969 "MOVW%C", armdps, 0, "R%d,%x", 970 "MOVW%C", armdps, 0, "%x,R%d", 971 972 /* 122 */ 973 "MOV%f%C", armvstdi, 0, "F%d,%I", 974 "MOV%f%C", armvstdi, 0, "%I,F%d", 975 }; 976 977 static void 978 gaddr(Instr *i) 979 { 980 *i->curr++ = '$'; 981 i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY); 982 } 983 984 static char *mode[] = { 0, "IA", "DB", "IB" }; 985 static char *pw[] = { "P", "PW", 0, "W" }; 986 static char *sw[] = { 0, "W", "S", "SW" }; 987 988 static void 989 format(char *mnemonic, Instr *i, char *f) 990 { 991 int j, k, m, n; 992 int g; 993 char *fmt; 994 995 if(mnemonic) 996 format(0, i, mnemonic); 997 if(f == 0) 998 return; 999 if(mnemonic) 1000 if(i->curr < i->end) 1001 *i->curr++ = '\t'; 1002 for ( ; *f && i->curr < i->end; f++) { 1003 if(*f != '%') { 1004 *i->curr++ = *f; 1005 continue; 1006 } 1007 switch (*++f) { 1008 1009 case 'C': /* .CONDITION */ 1010 if(cond[i->cond]) 1011 bprint(i, ".%s", cond[i->cond]); 1012 break; 1013 1014 case 'S': /* .STORE */ 1015 if(i->store) 1016 bprint(i, ".S"); 1017 break; 1018 1019 case 'P': /* P & U bits for block move */ 1020 n = (i->w >>23) & 0x3; 1021 if (mode[n]) 1022 bprint(i, ".%s", mode[n]); 1023 break; 1024 1025 case 'p': /* P & W bits for single data xfer*/ 1026 if (pw[i->store]) 1027 bprint(i, ".%s", pw[i->store]); 1028 break; 1029 1030 case 'a': /* S & W bits for single data xfer*/ 1031 if (sw[i->store]) 1032 bprint(i, ".%s", sw[i->store]); 1033 break; 1034 1035 case 's': 1036 bprint(i, "%d", i->rs & 0xf); 1037 break; 1038 1039 case 'M': 1040 bprint(i, "%lud", (i->w>>8) & 0xf); 1041 break; 1042 1043 case 'm': 1044 bprint(i, "%lud", (i->w>>7) & 0x1f); 1045 break; 1046 1047 case 'h': 1048 bprint(i, shtype[(i->w>>5) & 0x3]); 1049 break; 1050 1051 case 'u': /* Signed/unsigned Byte/Halfword */ 1052 bprint(i, hb[(i->w>>5) & 0x3]); 1053 break; 1054 1055 case 'I': 1056 if (i->rn == 13) { 1057 if (plocal(i)) 1058 break; 1059 } 1060 g = 0; 1061 fmt = "#%lx(R%d)"; 1062 if (i->rn == 15) { 1063 /* convert load of offset(PC) to a load immediate */ 1064 if (get4(i->map, i->addr+i->imm+8, (ulong*)&i->imm) > 0) 1065 { 1066 g = 1; 1067 fmt = ""; 1068 } 1069 } 1070 if (mach->sb) 1071 { 1072 if (i->rd == 11) { 1073 ulong nxti; 1074 1075 if (get4(i->map, i->addr+4, &nxti) > 0) { 1076 if ((nxti & 0x0e0f0fff) == 0x060c000b) { 1077 i->imm += mach->sb; 1078 g = 1; 1079 fmt = "-SB"; 1080 } 1081 } 1082 } 1083 if (i->rn == 12) 1084 { 1085 i->imm += mach->sb; 1086 g = 1; 1087 fmt = "-SB(SB)"; 1088 } 1089 } 1090 if (g) 1091 { 1092 gaddr(i); 1093 bprint(i, fmt, i->rn); 1094 } 1095 else 1096 bprint(i, fmt, i->imm, i->rn); 1097 break; 1098 case 'U': /* Add/subtract from base */ 1099 bprint(i, addsub[(i->w >> 23) & 1]); 1100 break; 1101 1102 case 'n': 1103 bprint(i, "%d", i->rn); 1104 break; 1105 1106 case 'd': 1107 bprint(i, "%d", i->rd); 1108 break; 1109 1110 case 'i': 1111 bprint(i, "%lux", i->imm); 1112 break; 1113 1114 case 'b': 1115 i->curr += symoff(i->curr, i->end-i->curr, 1116 (ulong)i->imm, CTEXT); 1117 break; 1118 1119 case 'g': 1120 i->curr += gsymoff(i->curr, i->end-i->curr, 1121 i->imm, CANY); 1122 break; 1123 1124 case 'f': 1125 switch((i->w >> 8) & 0xF){ 1126 case 10: 1127 bprint(i, "F"); 1128 break; 1129 case 11: 1130 bprint(i, "D"); 1131 break; 1132 } 1133 break; 1134 1135 case 'F': 1136 switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){ 1137 case 0x0: 1138 bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U"); 1139 break; 1140 case 0x1: 1141 bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U"); 1142 break; 1143 case 0x8: 1144 bprint(i, "FW.U"); 1145 break; 1146 case 0x9: 1147 bprint(i, "DW.U"); 1148 break; 1149 case 0xA: 1150 bprint(i, "FW"); 1151 break; 1152 case 0xB: 1153 bprint(i, "DW"); 1154 break; 1155 case 0xE: 1156 bprint(i, "FD"); 1157 break; 1158 case 0xF: 1159 bprint(i, "DF"); 1160 break; 1161 } 1162 break; 1163 1164 case 'R': 1165 if(((i->w >> 7) & 0x1) == 0) 1166 bprint(i, "R"); 1167 break; 1168 1169 case 'x': 1170 switch(i->rn){ 1171 case 0: 1172 bprint(i, "FPSID"); 1173 break; 1174 case 1: 1175 bprint(i, "FPSCR"); 1176 break; 1177 case 2: 1178 bprint(i, "FPEXC"); 1179 break; 1180 default: 1181 bprint(i, "FPS(%d)", i->rn); 1182 break; 1183 } 1184 break; 1185 1186 case 'r': 1187 n = i->imm&0xffff; 1188 j = 0; 1189 k = 0; 1190 while(n) { 1191 m = j; 1192 while(n&0x1) { 1193 j++; 1194 n >>= 1; 1195 } 1196 if(j != m) { 1197 if(k) 1198 bprint(i, ","); 1199 if(j == m+1) 1200 bprint(i, "R%d", m); 1201 else 1202 bprint(i, "R%d-R%d", m, j-1); 1203 k = 1; 1204 } 1205 j++; 1206 n >>= 1; 1207 } 1208 break; 1209 1210 case '\0': 1211 *i->curr++ = '%'; 1212 return; 1213 1214 default: 1215 bprint(i, "%%%c", *f); 1216 break; 1217 } 1218 } 1219 *i->curr = 0; 1220 } 1221 1222 static int 1223 printins(Map *map, uvlong pc, char *buf, int n) 1224 { 1225 Instr i; 1226 1227 i.curr = buf; 1228 i.end = buf+n-1; 1229 if(decode(map, pc, &i) < 0) 1230 return -1; 1231 1232 (*opcodes[i.op].fmt)(&opcodes[i.op], &i); 1233 return 4; 1234 } 1235 1236 static int 1237 arminst(Map *map, uvlong pc, char modifier, char *buf, int n) 1238 { 1239 USED(modifier); 1240 return printins(map, pc, buf, n); 1241 } 1242 1243 static int 1244 armdas(Map *map, uvlong pc, char *buf, int n) 1245 { 1246 Instr i; 1247 1248 i.curr = buf; 1249 i.end = buf+n; 1250 if(decode(map, pc, &i) < 0) 1251 return -1; 1252 if(i.end-i.curr > 8) 1253 i.curr = _hexify(buf, i.w, 7); 1254 *i.curr = 0; 1255 return 4; 1256 } 1257 1258 static int 1259 arminstlen(Map *map, uvlong pc) 1260 { 1261 Instr i; 1262 1263 if(decode(map, pc, &i) < 0) 1264 return -1; 1265 return 4; 1266 } 1267 1268 static int 1269 armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) 1270 { 1271 uvlong d; 1272 Instr i; 1273 1274 if(decode(map, pc, &i) < 0) 1275 return -1; 1276 1277 if(opcodes[i.op].foll) { 1278 d = (*opcodes[i.op].foll)(map, rget, &i, pc); 1279 if(d == -1) 1280 return -1; 1281 } else 1282 d = pc+4; 1283 1284 foll[0] = d; 1285 return 1; 1286 } 1287