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