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