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