1 #include <lib9.h> 2 #include <bio.h> 3 #include "mach.h" 4 5 /* 6 * PowerPC-specific debugger interface 7 * forsyth@terzarima.net 8 */ 9 10 static char *powerexcep(Map*, Rgetter); 11 static int powerfoll(Map*, ulong, Rgetter, ulong*); 12 static int powerinst(Map*, ulong, char, char*, int); 13 static int powerinstlen(Map*, ulong); 14 static int powerdas(Map*, ulong, char*, int); 15 16 /* 17 * Machine description 18 */ 19 Machdata powermach = 20 { 21 {0x07f, 0xe0, 0x00, 0x08}, /* breakpoint (tw 31,r0,r0) */ 22 4, /* break point size */ 23 24 beswab, /* convert short to local byte order */ 25 beswal, /* convert long to local byte order */ 26 beswav, /* vlong to local byte order */ 27 risctrace, /* print C traceback */ 28 riscframe, /* frame finder */ 29 powerexcep, /* print exception */ 30 0, /* breakpoint fixup */ 31 beieeesftos, /* single precision float printer */ 32 beieeedftos, /* double precisioin float printer */ 33 powerfoll, /* following addresses */ 34 powerinst, /* print instruction */ 35 powerdas, /* dissembler */ 36 powerinstlen, /* instruction size */ 37 }; 38 39 static char *excname[] = 40 { 41 "reserved 0", 42 "system reset", 43 "machine check", 44 "data access", 45 "instruction access", 46 "external interrupt", 47 "alignment", 48 "program exception", 49 "floating-point unavailable", 50 "decrementer", 51 "i/o controller interface error", 52 "reserved B", 53 "system call", 54 "trace trap", 55 "floating point assist", 56 "reserved", 57 "ITLB miss", 58 "DTLB load miss", 59 "DTLB store miss", 60 "instruction address breakpoint" 61 "SMI interrupt" 62 "reserved 15", 63 "reserved 16", 64 "reserved 17", 65 "reserved 18", 66 "reserved 19", 67 "reserved 1A", 68 /* the following are made up on a program exception */ 69 "floating point exception", /* 1B: FPEXC */ 70 "illegal instruction", /* 1C */ 71 "privileged instruction", /* 1D */ 72 "trap", /* 1E */ 73 "illegal operation", /* 1F */ 74 "breakpoint", /* 20 */ 75 }; 76 77 static char* 78 powerexcep(Map *map, Rgetter rget) 79 { 80 long c; 81 static char buf[32]; 82 83 c = (*rget)(map, "CAUSE") >> 8; 84 if(c < nelem(excname)) 85 return excname[c]; 86 sprint(buf, "unknown trap #%lx", c); 87 return buf; 88 } 89 90 /* 91 * disassemble PowerPC opcodes 92 */ 93 94 #define REGSP 1 /* should come from q.out.h, but there's a clash */ 95 #define REGSB 2 96 97 static char FRAMENAME[] = ".frame"; 98 99 static Map *mymap; 100 101 /* 102 * ibm conventions for these: bit 0 is top bit 103 * from table 10-1 104 */ 105 typedef struct { 106 uchar aa; /* bit 30 */ 107 uchar crba; /* bits 11-15 */ 108 uchar crbb; /* bits 16-20 */ 109 long bd; /* bits 16-29 */ 110 uchar crfd; /* bits 6-8 */ 111 uchar crfs; /* bits 11-13 */ 112 uchar bi; /* bits 11-15 */ 113 uchar bo; /* bits 6-10 */ 114 uchar crbd; /* bits 6-10 */ 115 /*union {*/ 116 short d; /* bits 16-31 */ 117 short simm; 118 ushort uimm; 119 /*};*/ 120 uchar fm; /* bits 7-14 */ 121 uchar fra; /* bits 11-15 */ 122 uchar frb; /* bits 16-20 */ 123 uchar frc; /* bits 21-25 */ 124 uchar frs; /* bits 6-10 */ 125 uchar frd; /* bits 6-10 */ 126 uchar crm; /* bits 12-19 */ 127 long li; /* bits 6-29 || b'00' */ 128 uchar lk; /* bit 31 */ 129 uchar mb; /* bits 21-25 */ 130 uchar me; /* bits 26-30 */ 131 uchar nb; /* bits 16-20 */ 132 uchar op; /* bits 0-5 */ 133 uchar oe; /* bit 21 */ 134 uchar ra; /* bits 11-15 */ 135 uchar rb; /* bits 16-20 */ 136 uchar rc; /* bit 31 */ 137 /* union {*/ 138 uchar rs; /* bits 6-10 */ 139 uchar rd; 140 /*};*/ 141 uchar sh; /* bits 16-20 */ 142 ushort spr; /* bits 11-20 */ 143 uchar to; /* bits 6-10 */ 144 uchar imm; /* bits 16-19 */ 145 ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */ 146 long immediate; 147 long w0; 148 long w1; 149 ulong addr; /* pc of instruction */ 150 short target; 151 char *curr; /* current fill level in output buffer */ 152 char *end; /* end of buffer */ 153 int size; /* number of longs in instr */ 154 char *err; /* errmsg */ 155 } Instr; 156 157 #define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1)))) 158 #define IB(v,b) IBF((v),(b),(b)) 159 160 static void 161 bprint(Instr *i, char *fmt, ...) 162 { 163 va_list arg; 164 165 va_start(arg, fmt); 166 i->curr = vseprint(i->curr, i->end, fmt, arg); 167 va_end(arg); 168 } 169 170 static int 171 decode(ulong pc, Instr *i) 172 { 173 long w; 174 175 if (get4(mymap, pc, &w) < 0) { 176 werrstr("can't read instruction: %r"); 177 return -1; 178 } 179 i->aa = IB(w, 30); 180 i->crba = IBF(w, 11, 15); 181 i->crbb = IBF(w, 16, 20); 182 i->bd = IBF(w, 16, 29)<<2; 183 if(i->bd & 0x8000) 184 i->bd |= ~0L<<16; 185 i->crfd = IBF(w, 6, 8); 186 i->crfs = IBF(w, 11, 13); 187 i->bi = IBF(w, 11, 15); 188 i->bo = IBF(w, 6, 10); 189 i->crbd = IBF(w, 6, 10); 190 i->uimm = IBF(w, 16, 31); /* also d, simm */ 191 i->simm = i->uimm; 192 i->d = i->uimm; 193 i->fm = IBF(w, 7, 14); 194 i->fra = IBF(w, 11, 15); 195 i->frb = IBF(w, 16, 20); 196 i->frc = IBF(w, 21, 25); 197 i->frs = IBF(w, 6, 10); 198 i->frd = IBF(w, 6, 10); 199 i->crm = IBF(w, 12, 19); 200 i->li = IBF(w, 6, 29)<<2; 201 if(IB(w, 6)) 202 i->li |= ~0<<25; 203 i->lk = IB(w, 31); 204 i->mb = IBF(w, 21, 25); 205 i->me = IBF(w, 26, 30); 206 i->nb = IBF(w, 16, 20); 207 i->op = IBF(w, 0, 5); 208 i->oe = IB(w, 21); 209 i->ra = IBF(w, 11, 15); 210 i->rb = IBF(w, 16, 20); 211 i->rc = IB(w, 31); 212 i->rs = IBF(w, 6, 10); /* also rd */ 213 i->rd = i->rs; 214 i->sh = IBF(w, 16, 20); 215 i->spr = IBF(w, 11, 20); 216 i->to = IBF(w, 6, 10); 217 i->imm = IBF(w, 16, 19); 218 i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */ 219 i->immediate = i->simm; 220 if(i->op == 15) 221 i->immediate <<= 16; 222 i->w0 = w; 223 i->target = -1; 224 i->addr = pc; 225 i->size = 1; 226 return 1; 227 } 228 229 static int 230 mkinstr(ulong pc, Instr *i) 231 { 232 Instr x; 233 234 if(decode(pc, i) < 0) 235 return -1; 236 /* 237 * combine ADDIS/ORI (CAU/ORIL) into MOVW 238 */ 239 if (i->op == 15 && i->ra==0) { 240 if(decode(pc+4, &x) < 0) 241 return -1; 242 if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) { 243 i->immediate |= (x.immediate & 0xFFFF); 244 i->w1 = x.w0; 245 i->target = x.rd; 246 i->size++; 247 return 1; 248 } 249 } 250 if (i->op == 15 && i->ra==REGSB && mach->sb) { 251 if(decode(pc+4, &x) < 0) 252 return -1; 253 if (x.op >= 32 && x.op < 54 && i->rd == x.ra) { 254 i->op = x.op; 255 i->ra = REGSB; 256 i->rs = i->rd = x.rd; 257 i->immediate += x.simm; 258 i->w1 = x.w0; 259 i->target = x.rd; 260 i->size++; 261 return 1; 262 } 263 } 264 return 1; 265 } 266 267 static int 268 plocal(Instr *i) 269 { 270 int offset; 271 Symbol s; 272 273 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) 274 return -1; 275 offset = s.value - i->immediate; 276 if (offset > 0) { 277 if(getauto(&s, offset, CAUTO, &s)) { 278 bprint(i, "%s+%d(SP)", s.name, s.value); 279 return 1; 280 } 281 } else { 282 if (getauto(&s, -offset-4, CPARAM, &s)) { 283 bprint(i, "%s+%d(FP)", s.name, -offset); 284 return 1; 285 } 286 } 287 return -1; 288 } 289 290 static int 291 pglobal(Instr *i, long off, int anyoff, char *reg) 292 { 293 Symbol s, s2; 294 long off1; 295 296 if(findsym(off, CANY, &s) && 297 strcmp(s.name, ".string") != 0 && 298 (ulong)(off-s.value) < 4096 && 299 (s.class == CDATA || s.class == CTEXT)) { 300 if(off==s.value && s.name[0]=='$'){ 301 off1 = 0; 302 get4(mymap, s.value, &off1); 303 if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ 304 bprint(i, "$%s%s", s2.name, reg); 305 return 1; 306 } 307 } 308 bprint(i, "%s", s.name); 309 if (s.value != off) 310 bprint(i, "+%lux", off-s.value); 311 bprint(i, reg); 312 return 1; 313 } 314 if(!anyoff) 315 return 0; 316 bprint(i, "%lux%s", off, reg); 317 return 1; 318 } 319 320 static void 321 address(Instr *i) 322 { 323 if (i->ra == REGSP && plocal(i) >= 0) 324 return; 325 if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") > 0) 326 return; 327 if(i->immediate < 0) 328 bprint(i, "-%lx", -i->immediate); 329 else 330 bprint(i, "%lux", i->immediate); 331 if (i->ra == REGSB && mach->sb) 332 bprint(i, "(SB)"); 333 else 334 bprint(i, "(R%d)", i->ra); 335 } 336 337 static char *tcrbits[] = {"LT", "GT", "EQ", "VS"}; 338 static char *fcrbits[] = {"GE", "LE", "NE", "VC"}; 339 340 typedef struct Opcode Opcode; 341 342 struct Opcode { 343 uchar op; 344 ushort xo; 345 ushort xomask; 346 char *mnemonic; 347 void (*f)(Opcode *, Instr *); 348 char *ken; 349 int flags; 350 }; 351 352 static void format(char *, Instr *, char *); 353 354 static void 355 branch(Opcode *o, Instr *i) 356 { 357 char buf[8]; 358 int bo, bi; 359 360 bo = i->bo & ~1; /* ignore prediction bit */ 361 if(bo==4 || bo==12 || bo==20) { /* simple forms */ 362 if(bo != 20) { 363 bi = i->bi&3; 364 sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]); 365 format(buf, i, 0); 366 bprint(i, "\t"); 367 if(i->bi > 4) 368 bprint(i, "CR(%d),", i->bi/4); 369 } else 370 format("BR%L\t", i, 0); 371 if(i->op == 16) 372 format(0, i, "%J"); 373 else if(i->op == 19 && i->xo == 528) 374 format(0, i, "(CTR)"); 375 else if(i->op == 19 && i->xo == 16) 376 format(0, i, "(LR)"); 377 } else 378 format(o->mnemonic, i, o->ken); 379 } 380 381 static void 382 addi(Opcode *o, Instr *i) 383 { 384 if (i->op==14 && i->ra == 0) 385 format("MOVW", i, "%i,R%d"); 386 else if (i->ra == REGSP || i->ra == REGSB) { 387 bprint(i, "MOVW\t$"); 388 address(i); 389 bprint(i, ",R%d", i->rd); 390 } else if(i->op==14 && i->simm < 0) { 391 bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra); 392 if(i->rd != i->ra) 393 bprint(i, ",R%d", i->rd); 394 } else if(i->ra == i->rd) { 395 format(o->mnemonic, i, "%i"); 396 bprint(i, ",R%d", i->rd); 397 } else 398 format(o->mnemonic, i, o->ken); 399 } 400 401 static void 402 addis(Opcode *o, Instr *i) 403 { 404 long v; 405 406 v = i->immediate; 407 if (i->op==15 && i->ra == 0) { 408 bprint(i, "MOVW\t$"); 409 pglobal(i, i->immediate, 1, ""); 410 bprint(i, ",R%d", i->rd); 411 } 412 else if (i->op==15 && i->ra == REGSB && mach->sb) { 413 bprint(i, "MOVW\t$"); 414 address(i); 415 bprint(i, ",R%d", i->rd); 416 /* how about auto/param addresses? */ 417 } else if(i->op==15 && v < 0) { 418 bprint(i, "SUB\t$%d,R%d", -v, i->ra); 419 if(i->rd != i->ra) 420 bprint(i, ",R%d", i->rd); 421 } else { 422 format(o->mnemonic, i, 0); 423 bprint(i, "\t$%ld,R%d", v, i->ra); 424 if(i->rd != i->ra) 425 bprint(i, ",R%d", i->rd); 426 } 427 } 428 429 static void 430 andi(Opcode *o, Instr *i) 431 { 432 if (i->ra == i->rs) 433 format(o->mnemonic, i, "%I,R%d"); 434 else 435 format(o->mnemonic, i, o->ken); 436 } 437 438 static void 439 gencc(Opcode *o, Instr *i) 440 { 441 format(o->mnemonic, i, o->ken); 442 } 443 444 static void 445 gen(Opcode *o, Instr *i) 446 { 447 format(o->mnemonic, i, o->ken); 448 if (i->rc) 449 bprint(i, " [illegal Rc]"); 450 } 451 452 static void 453 ldx(Opcode *o, Instr *i) 454 { 455 if(i->ra == 0) 456 format(o->mnemonic, i, "(R%b),R%d"); 457 else 458 format(o->mnemonic, i, "(R%b+R%a),R%d"); 459 if(i->rc) 460 bprint(i, " [illegal Rc]"); 461 } 462 463 static void 464 stx(Opcode *o, Instr *i) 465 { 466 if(i->ra == 0) 467 format(o->mnemonic, i, "R%d,(R%b)"); 468 else 469 format(o->mnemonic, i, "R%d,(R%b+R%a)"); 470 if(i->rc && i->xo != 150) 471 bprint(i, " [illegal Rc]"); 472 } 473 474 static void 475 fldx(Opcode *o, Instr *i) 476 { 477 if(i->ra == 0) 478 format(o->mnemonic, i, "(R%b),F%d"); 479 else 480 format(o->mnemonic, i, "(R%b+R%a),F%d"); 481 if(i->rc) 482 bprint(i, " [illegal Rc]"); 483 } 484 485 static void 486 fstx(Opcode *o, Instr *i) 487 { 488 if(i->ra == 0) 489 format(o->mnemonic, i, "F%d,(R%b)"); 490 else 491 format(o->mnemonic, i, "F%d,(R%b+R%a)"); 492 if(i->rc) 493 bprint(i, " [illegal Rc]"); 494 } 495 496 static void 497 dcb(Opcode *o, Instr *i) 498 { 499 if(i->ra == 0) 500 format(o->mnemonic, i, "(R%b)"); 501 else 502 format(o->mnemonic, i, "(R%b+R%a)"); 503 if(i->rd) 504 bprint(i, " [illegal Rd]"); 505 if(i->rc) 506 bprint(i, " [illegal Rc]"); 507 } 508 509 static void 510 lw(Opcode *o, Instr *i, char r) 511 { 512 bprint(i, "%s\t", o->mnemonic); 513 address(i); 514 bprint(i, ",%c%d", r, i->rd); 515 } 516 517 static void 518 load(Opcode *o, Instr *i) 519 { 520 lw(o, i, 'R'); 521 } 522 523 static void 524 fload(Opcode *o, Instr *i) 525 { 526 lw(o, i, 'F'); 527 } 528 529 static void 530 sw(Opcode *o, Instr *i, char r) 531 { 532 int offset; 533 char *m; 534 Symbol s; 535 536 m = o->mnemonic; 537 if (i->ra == REGSP) { 538 if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) { 539 offset = s.value-i->immediate; 540 if (offset > 0 && getauto(&s, offset, CAUTO, &s)) { 541 bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rs, 542 s.name, offset); 543 return; 544 } 545 } 546 } 547 if (i->ra == REGSP || i->ra == REGSB && mach->sb) { 548 bprint(i, "%s\t%c%d,", m, r, i->rs); 549 address(i); 550 return; 551 } 552 if (r == 'F') 553 format(m, i, "F%d,%l"); 554 else 555 format(m, i, o->ken); 556 } 557 558 static void 559 store(Opcode *o, Instr *i) 560 { 561 sw(o, i, 'R'); 562 } 563 564 static void 565 fstore(Opcode *o, Instr *i) 566 { 567 sw(o, i, 'F'); 568 } 569 570 static void 571 shifti(Opcode *o, Instr *i) 572 { 573 if (i->ra == i->rs) 574 format(o->mnemonic, i, "$%k,R%a"); 575 else 576 format(o->mnemonic, i, o->ken); 577 } 578 579 static void 580 shift(Opcode *o, Instr *i) 581 { 582 if (i->ra == i->rs) 583 format(o->mnemonic, i, "R%b,R%a"); 584 else 585 format(o->mnemonic, i, o->ken); 586 } 587 588 static void 589 add(Opcode *o, Instr *i) 590 { 591 if (i->rd == i->ra) 592 format(o->mnemonic, i, "R%b,R%d"); 593 else if (i->rd == i->rb) 594 format(o->mnemonic, i, "R%a,R%d"); 595 else 596 format(o->mnemonic, i, o->ken); 597 } 598 599 static void 600 sub(Opcode *o, Instr *i) 601 { 602 format(o->mnemonic, i, 0); 603 if(i->op == 31) { 604 bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */ 605 if(i->rd != i->rb) 606 bprint(i, ",R%d", i->rd); 607 } else 608 bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd); 609 } 610 611 static void 612 qmuldiv(Opcode *o, Instr *i) 613 { 614 format(o->mnemonic, i, 0); 615 if(i->op == 31) 616 bprint(i, "\tR%d,R%d", i->rb, i->ra); 617 else 618 bprint(i, "\t$%d,R%d", i->simm, i->ra); 619 if(i->ra != i->rd) 620 bprint(i, ",R%d", i->rd); 621 } 622 623 static void 624 and(Opcode *o, Instr *i) 625 { 626 if (i->op == 31) { 627 /* Rb,Rs,Ra */ 628 if (i->ra == i->rs) 629 format(o->mnemonic, i, "R%b,R%a"); 630 else if (i->ra == i->rb) 631 format(o->mnemonic, i, "R%s,R%a"); 632 else 633 format(o->mnemonic, i, o->ken); 634 } else { 635 /* imm,Rs,Ra */ 636 if (i->ra == i->rs) 637 format(o->mnemonic, i, "%I,R%a"); 638 else 639 format(o->mnemonic, i, o->ken); 640 } 641 } 642 643 static void 644 or(Opcode *o, Instr *i) 645 { 646 if (i->op == 31) { 647 /* Rb,Rs,Ra */ 648 if (i->rs == 0 && i->ra == 0 && i->rb == 0) 649 format("NOP", i, 0); 650 else if (i->rs == i->rb) 651 format("MOVW", i, "R%b,R%a"); 652 else 653 and(o, i); 654 } else 655 and(o, i); 656 } 657 658 static void 659 shifted(Opcode *o, Instr *i) 660 { 661 format(o->mnemonic, i, 0); 662 bprint(i, "\t$%lux,", (ulong)i->uimm<<16); 663 if (i->rs == i->ra) 664 bprint(i, "R%d", i->ra); 665 else 666 bprint(i, "R%d,R%d", i->rs, i->ra); 667 } 668 669 static void 670 neg(Opcode *o, Instr *i) 671 { 672 if (i->rd == i->ra) 673 format(o->mnemonic, i, "R%d"); 674 else 675 format(o->mnemonic, i, o->ken); 676 } 677 678 static char ir2[] = "R%a,R%d"; /* reverse of IBM order */ 679 static char ir3[] = "R%b,R%a,R%d"; 680 static char ir3r[] = "R%a,R%b,R%d"; 681 static char il3[] = "R%b,R%s,R%a"; 682 static char il2u[] = "%I,R%s,R%a"; 683 static char il3s[] = "$%k,R%s,R%a"; 684 static char il2[] = "R%s,R%a"; 685 static char icmp3[] = "R%a,R%b,%D"; 686 static char cr3op[] = "%b,%a,%d"; 687 static char ir2i[] = "%i,R%a,R%d"; 688 static char fp2[] = "F%b,F%d"; 689 static char fp3[] = "F%b,F%a,F%d"; 690 static char fp3c[] = "F%c,F%a,F%d"; 691 static char fp4[] = "F%a,F%c,F%b,F%d"; 692 static char fpcmp[] = "F%a,F%b,%D"; 693 static char ldop[] = "%l,R%d"; 694 static char stop[] = "R%d,%l"; 695 static char fldop[] = "%l,F%d"; 696 static char fstop[] = "F%d,%l"; 697 static char rlim[] = "R%b,R%s,$%z,R%a"; 698 static char rlimi[] = "$%k,R%s,$%z,R%a"; 699 700 #define OEM IBF(~0,22,30) 701 #define FP4 IBF(~0,26,30) 702 #define ALL ((ushort)~0) 703 /* 704 notes: 705 10-26: crfD = rD>>2; rD&3 mbz 706 also, L bit (bit 10) mbz or selects 64-bit operands 707 */ 708 709 static Opcode opcodes[] = { 710 {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */ 711 712 {31, 266, OEM, "ADD%V%C", add, ir3}, 713 {31, 10, OEM, "ADDC%V%C", add, ir3}, 714 {31, 138, OEM, "ADDE%V%C", add, ir3}, 715 {14, 0, 0, "ADD", addi, ir2i}, 716 {12, 0, 0, "ADDC", addi, ir2i}, 717 {13, 0, 0, "ADDCCC", addi, ir2i}, 718 {15, 0, 0, "ADD", addis, 0}, 719 {31, 234, OEM, "ADDME%V%C", gencc, ir2}, 720 {31, 202, OEM, "ADDZE%V%C", gencc, ir2}, 721 722 {31, 28, ALL, "AND%C", and, il3}, 723 {31, 60, ALL, "ANDN%C", and, il3}, 724 {28, 0, 0, "ANDCC", andi, il2u}, 725 {29, 0, 0, "ANDCC", shifted, 0}, 726 727 {18, 0, 0, "B%L", gencc, "%j"}, 728 {16, 0, 0, "BC%L", branch, "%d,%a,%J"}, 729 {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"}, 730 {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"}, 731 732 {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */ 733 734 {31, 0, ALL, "CMP", 0, icmp3}, 735 {11, 0, 0, "CMP", 0, "R%a,%i,%D"}, 736 {31, 32, ALL, "CMPU", 0, icmp3}, 737 {10, 0, 0, "CMPU", 0, "R%a,%I,%D"}, 738 739 {31, 26, ALL, "CNTLZ%C", gencc, ir2}, 740 741 {19, 257, ALL, "CRAND", gen, cr3op}, 742 {19, 129, ALL, "CRANDN", gen, cr3op}, 743 {19, 289, ALL, "CREQV", gen, cr3op}, 744 {19, 225, ALL, "CRNAND", gen, cr3op}, 745 {19, 33, ALL, "CRNOR", gen, cr3op}, 746 {19, 449, ALL, "CROR", gen, cr3op}, 747 {19, 417, ALL, "CRORN", gen, cr3op}, 748 {19, 193, ALL, "CRXOR", gen, cr3op}, 749 750 {31, 86, ALL, "DCBF", dcb, 0}, 751 {31, 470, ALL, "DCBI", dcb, 0}, 752 {31, 54, ALL, "DCBST", dcb, 0}, 753 {31, 278, ALL, "DCBT", dcb, 0}, 754 {31, 246, ALL, "DCBTST", dcb, 0}, 755 {31, 1014, ALL, "DCBZ", dcb, 0}, 756 757 {31, 331, OEM, "DIV%V%C", qmuldiv, ir3}, /* POWER */ 758 {31, 363, OEM, "DIVS%V%C", qmuldiv, ir3}, /* POWER */ 759 {31, 491, OEM, "DIVW%V%C", qmuldiv, ir3}, 760 {31, 459, OEM, "DIVWU%V%C", qmuldiv, ir3}, 761 762 {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */ 763 {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */ 764 765 {31, 310, ALL, "ECIWX", ldx, 0}, 766 {31, 438, ALL, "ECOWX", stx, 0}, 767 {31, 854, ALL, "EIEIO", gen, 0}, 768 769 {31, 284, ALL, "EQV%C", gencc, il3}, 770 771 {31, 954, ALL, "EXTSB%C", gencc, il2}, 772 {31, 922, ALL, "EXTSH%C", gencc, il2}, 773 774 {63, 264, ALL, "FABS%C", gencc, fp2}, 775 {63, 21, ALL, "FADD%C", gencc, fp3}, 776 {59, 21, ALL, "FADDS%C", gencc, fp3}, 777 {63, 32, ALL, "FCMPO", gen, fpcmp}, 778 {63, 0, ALL, "FCMPU", gen, fpcmp}, 779 {63, 14, ALL, "FCTIW%C", gencc, fp2}, 780 {63, 15, ALL, "FCTIWZ%C", gencc, fp2}, 781 {63, 18, ALL, "FDIV%C", gencc, fp3}, 782 {59, 18, ALL, "FDIVS%C", gencc, fp3}, 783 {63, 29, FP4, "FMADD%C", gencc, fp4}, 784 {59, 29, FP4, "FMADDS%C", gencc, fp4}, 785 {63, 72, ALL, "FMOVD%C", gencc, fp2}, 786 {63, 28, FP4, "FMSUB%C", gencc, fp4}, 787 {59, 28, FP4, "FMSUBS%C", gencc, fp4}, 788 {63, 25, FP4, "FMUL%C", gencc, fp3c}, 789 {59, 25, FP4, "FMULS%C", gencc, fp3c}, 790 {63, 136, ALL, "FNABS%C", gencc, fp2}, 791 {63, 40, ALL, "FNEG%C", gencc, fp2}, 792 {63, 31, FP4, "FNMADD%C", gencc, fp4}, 793 {59, 31, FP4, "FNMADDS%C", gencc, fp4}, 794 {63, 30, FP4, "FNMSUB%C", gencc, fp4}, 795 {59, 30, FP4, "FNMSUBS%C", gencc, fp4}, 796 {63, 12, ALL, "FRSP%C", gencc, fp2}, 797 {63, 20, FP4, "FSUB%C", gencc, fp3}, 798 {59, 20, FP4, "FSUBS%C", gencc, fp3}, 799 800 {31, 982, ALL, "ICBI", dcb, 0}, 801 {19, 150, ALL, "ISYNC", gen, 0}, 802 803 {34, 0, 0, "MOVBZ", load, ldop}, 804 {35, 0, 0, "MOVBZU", load, ldop}, 805 {31, 119, ALL, "MOVBZU", ldx, 0}, 806 {31, 87, ALL, "MOVBZ", ldx, 0}, 807 {50, 0, 0, "FMOVD", fload, fldop}, 808 {51, 0, 0, "FMOVDU", fload, fldop}, 809 {31, 631, ALL, "FMOVDU", fldx, 0}, 810 {31, 599, ALL, "FMOVD", fldx, 0}, 811 {48, 0, 0, "FMOVS", load, fldop}, 812 {49, 0, 0, "FMOVSU", load, fldop}, 813 {31, 567, ALL, "FMOVSU", fldx, 0}, 814 {31, 535, ALL, "FMOVS", fldx, 0}, 815 {42, 0, 0, "MOVH", load, ldop}, 816 {43, 0, 0, "MOVHU", load, ldop}, 817 {31, 375, ALL, "MOVHU", ldx, 0}, 818 {31, 343, ALL, "MOVH", ldx, 0}, 819 {31, 790, ALL, "MOVHBR", ldx, 0}, 820 {40, 0, 0, "MOVHZ", load, ldop}, 821 {41, 0, 0, "MOVHZU", load, ldop}, 822 {31, 311, ALL, "MOVHZU", ldx, 0}, 823 {31, 279, ALL, "MOVHZ", ldx, 0}, 824 {46, 0, 0, "MOVMW", load, ldop}, 825 {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */ 826 {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"}, 827 {31, 533, ALL, "LSW", ldx, 0}, 828 {31, 20, ALL, "LWAR", ldx, 0}, 829 {31, 534, ALL, "MOVWBR", ldx, 0}, 830 {32, 0, 0, "MOVW", load, ldop}, 831 {33, 0, 0, "MOVWU", load, ldop}, 832 {31, 55, ALL, "MOVWU", ldx, 0}, 833 {31, 23, ALL, "MOVW", ldx, 0}, 834 835 {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */ 836 {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */ 837 838 {19, 0, ALL, "MOVFL", gen, "%S,%D"}, 839 {63, 64, ALL, "MOVCRFS", gen, "%S,%D"}, 840 {31, 512, ALL, "MOVW", gen, "XER,%D"}, 841 {31, 19, ALL, "MOVW", gen, "CR,R%d"}, 842 843 {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */ 844 {31, 83, ALL, "MOVW", gen, "MSR,R%d"}, 845 {31, 339, ALL, "MOVW", gen, "%P,R%d"}, 846 {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"}, 847 {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"}, 848 {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"}, 849 {63, 70, ALL, "MTFSB0%C", gencc, "%D"}, 850 {63, 38, ALL, "MTFSB1%C", gencc, "%D"}, 851 {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */ 852 {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"}, 853 {31, 146, ALL, "MOVW", gen, "R%s,MSR"}, 854 {31, 467, ALL, "MOVW", gen, "R%s,%P"}, 855 {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"}, 856 {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"}, 857 858 {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */ 859 {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */ 860 {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */ 861 862 {31, 235, OEM, "MULLW%V%C", gencc, ir3}, 863 {7, 0, 0, "MULLW", qmuldiv, "%i,R%a,R%d"}, 864 865 {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */ 866 867 {31, 476, ALL, "NAND%C", gencc, il3}, 868 {31, 104, OEM, "NEG%V%C", neg, ir2}, 869 {31, 124, ALL, "NOR%C", gencc, il3}, 870 {31, 444, ALL, "OR%C", or, il3}, 871 {31, 412, ALL, "ORN%C", or, il3}, 872 {24, 0, 0, "OR", and, "%I,R%d,R%a"}, 873 {25, 0, 0, "OR", shifted, 0}, 874 875 {19, 50, ALL, "RFI", gen, 0}, 876 877 {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */ 878 {20, 0, 0, "RLWMI%C", gencc, rlimi}, 879 {21, 0, 0, "RLWNM%C", gencc, rlimi}, 880 {23, 0, 0, "RLWNM%C", gencc, rlim}, 881 882 {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */ 883 884 {17, 1, ALL, "SYSCALL", gen, 0}, 885 886 {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */ 887 {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */ 888 {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */ 889 {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */ 890 {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */ 891 {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */ 892 893 {31, 24, ALL, "SLW%C", shift, il3}, 894 895 {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */ 896 {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */ 897 898 {31, 792, ALL, "SRAW%C", shift, il3}, 899 {31, 824, ALL, "SRAW%C", shifti, il3s}, 900 901 {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */ 902 {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */ 903 {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */ 904 {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */ 905 {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */ 906 {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */ 907 {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */ 908 909 {31, 536, ALL, "SRW%C", shift, il3}, 910 911 {38, 0, 0, "MOVB", store, stop}, 912 {39, 0, 0, "MOVBU", store, stop}, 913 {31, 247, ALL, "MOVBU", stx, 0}, 914 {31, 215, ALL, "MOVB", stx, 0}, 915 {54, 0, 0, "FMOVD", fstore, fstop}, 916 {55, 0, 0, "FMOVDU", fstore, fstop}, 917 {31, 759, ALL, "FMOVDU", fstx, 0}, 918 {31, 727, ALL, "FMOVD", fstx, 0}, 919 {52, 0, 0, "FMOVS", fstore, fstop}, 920 {53, 0, 0, "FMOVSU", fstore, fstop}, 921 {31, 695, ALL, "FMOVSU", fstx, 0}, 922 {31, 663, ALL, "FMOVS", fstx, 0}, 923 {44, 0, 0, "MOVH", store, stop}, 924 {31, 918, ALL, "MOVHBR", stx, 0}, 925 {45, 0, 0, "MOVHU", store, stop}, 926 {31, 439, ALL, "MOVHU", stx, 0}, 927 {31, 407, ALL, "MOVH", stx, 0}, 928 {47, 0, 0, "MOVMW", store, stop}, 929 {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"}, 930 {31, 661, ALL, "STSW", stx, 0}, 931 {36, 0, 0, "MOVW", store, stop}, 932 {31, 662, ALL, "MOVWBR", stx, 0}, 933 {31, 150, ALL, "STWCCC", stx, 0}, 934 {37, 0, 0, "MOVWU", store, stop}, 935 {31, 183, ALL, "MOVWU", stx, 0}, 936 {31, 151, ALL, "MOVW", stx, 0}, 937 938 {31, 40, OEM, "SUB%V%C", sub, ir3}, 939 {31, 8, OEM, "SUBC%V%C", sub, ir3}, 940 {31, 136, OEM, "SUBE%V%C", sub, ir3}, 941 {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"}, 942 {31, 232, OEM, "SUBME%V%C", sub, ir2}, 943 {31, 200, OEM, "SUBZE%V%C", sub, ir2}, 944 945 {31, 598, ALL, "SYNC", gen, 0}, 946 {31, 306, ALL, "TLBIE", gen, "R%b"}, 947 {31, 370, ALL, "TLBIA", gen, 0}, 948 {31, 1010, ALL, "TLBLI", gen, "R%b"}, 949 {31, 978, ALL, "TLBLD", gen, "R%b"}, 950 {31, 4, ALL, "TW", gen, "%d,R%a,R%b"}, 951 {3, 0, 0, "TW", gen, "%d,R%a,%i"}, 952 953 {31, 316, ALL, "XOR", and, il3}, 954 {26, 0, 0, "XOR", and, il2u}, 955 {27, 0, 0, "XOR", shifted, 0}, 956 957 {0}, 958 }; 959 960 typedef struct Spr Spr; 961 struct Spr { 962 int n; 963 char *name; 964 }; 965 966 static Spr sprname[] = { 967 {0, "MQ"}, 968 {1, "XER"}, 969 {268, "TBL"}, 970 {269, "TBU"}, 971 {8, "LR"}, 972 {9, "CTR"}, 973 {528, "IBAT0U"}, 974 {529, "IBAT0L"}, 975 {530, "IBAT1U"}, 976 {531, "IBAT1L"}, 977 {532, "IBAT2U"}, 978 {533, "IBAT2L"}, 979 {534, "IBAT3U"}, 980 {535, "IBAT3L"}, 981 {536, "DBAT0U"}, 982 {537, "DBAT0L"}, 983 {538, "DBAT1U"}, 984 {539, "DBAT1L"}, 985 {540, "DBAT2U"}, 986 {541, "DBAT2L"}, 987 {542, "DBAT3U"}, 988 {543, "DBAT3L"}, 989 {25, "SDR1"}, 990 {19, "DAR"}, 991 {272, "SPRG0"}, 992 {273, "SPRG1"}, 993 {274, "SPRG2"}, 994 {275, "SPRG3"}, 995 {18, "DSISR"}, 996 {26, "SRR0"}, 997 {27, "SRR1"}, 998 {284, "TBLW"}, 999 {285, "TBUW"}, 1000 {22, "DEC"}, 1001 {282, "EAR"}, 1002 {1008, "HID0"}, 1003 {1009, "HID1"}, 1004 {976, "DMISS"}, 1005 {977, "DCMP"}, 1006 {978, "HASH1"}, 1007 {979, "HASH2"}, 1008 {980, "IMISS"}, 1009 {981, "ICMP"}, 1010 {982, "RPA"}, 1011 {1010, "IABR"}, 1012 {1013, "DABR"}, 1013 {0,0}, 1014 }; 1015 1016 static void 1017 format(char *mnemonic, Instr *i, char *f) 1018 { 1019 int n, s; 1020 ulong mask; 1021 1022 if (mnemonic) 1023 format(0, i, mnemonic); 1024 if (f == 0) 1025 return; 1026 if (mnemonic) 1027 bprint(i, "\t"); 1028 for ( ; *f; f++) { 1029 if (*f != '%') { 1030 bprint(i, "%c", *f); 1031 continue; 1032 } 1033 switch (*++f) { 1034 case 'V': 1035 if(i->oe) 1036 bprint(i, "V"); 1037 break; 1038 1039 case 'C': 1040 if(i->rc) 1041 bprint(i, "CC"); 1042 break; 1043 1044 case 'a': 1045 bprint(i, "%d", i->ra); 1046 break; 1047 1048 case 'b': 1049 bprint(i, "%d", i->rb); 1050 break; 1051 1052 case 'c': 1053 bprint(i, "%d", i->frc); 1054 break; 1055 1056 case 'd': 1057 case 's': 1058 bprint(i, "%d", i->rd); 1059 break; 1060 1061 case 'S': 1062 if(i->ra & 3) 1063 bprint(i, "CR(INVAL:%d)", i->ra); 1064 else if(i->op == 63) 1065 bprint(i, "FPSCR(%d)", i->crfs); 1066 else 1067 bprint(i, "CR(%d)", i->crfs); 1068 break; 1069 1070 case 'D': 1071 if(i->rd & 3) 1072 bprint(i, "CR(INVAL:%d)", i->rd); 1073 else if(i->op == 63) 1074 bprint(i, "FPSCR(%d)", i->crfd); 1075 else 1076 bprint(i, "CR(%d)", i->crfd); 1077 break; 1078 1079 case 'l': 1080 address(i); 1081 break; 1082 1083 case 'i': 1084 bprint(i, "$%ld", i->simm); 1085 break; 1086 1087 case 'I': 1088 bprint(i, "$%lx", i->uimm); 1089 break; 1090 1091 case 'w': 1092 bprint(i, "[%lux]", i->w0); 1093 break; 1094 1095 case 'P': 1096 n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f); 1097 for(s=0; sprname[s].name; s++) 1098 if(sprname[s].n == n) 1099 break; 1100 if(sprname[s].name) { 1101 if(n < 10) 1102 bprint(i, sprname[s].name); 1103 else 1104 bprint(i, "SPR(%s)", sprname[s].name); 1105 } else 1106 bprint(i, "SPR(%d)", n); 1107 break; 1108 1109 case 'n': 1110 bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */ 1111 break; 1112 1113 case 'm': 1114 bprint(i, "%lx", i->crm); 1115 break; 1116 1117 case 'M': 1118 bprint(i, "%lx", i->fm); 1119 break; 1120 1121 case 'z': 1122 if(i->mb <= i->me) 1123 mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me)); 1124 else 1125 mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1)))); 1126 bprint(i, "%lux", mask); 1127 break; 1128 1129 case 'k': 1130 bprint(i, "%d", i->sh); 1131 break; 1132 1133 case 'K': 1134 bprint(i, "$%x", i->imm); 1135 break; 1136 1137 case 'L': 1138 if(i->lk) 1139 bprint(i, "L"); 1140 break; 1141 1142 case 'j': 1143 if(i->aa) 1144 pglobal(i, i->li, 1, "(SB)"); 1145 else 1146 pglobal(i, i->addr+i->li, 1, ""); 1147 break; 1148 1149 case 'J': 1150 if(i->aa) 1151 pglobal(i, i->bd, 1, "(SB)"); 1152 else 1153 pglobal(i, i->addr+i->bd, 1, ""); 1154 break; 1155 1156 case '\0': 1157 bprint(i, "%%"); 1158 return; 1159 1160 default: 1161 bprint(i, "%%%c", *f); 1162 break; 1163 } 1164 } 1165 } 1166 1167 static int 1168 printins(Map *map, ulong pc, char *buf, int n) 1169 { 1170 Instr i; 1171 Opcode *o; 1172 1173 mymap = map; 1174 memset(&i, 0, sizeof(i)); 1175 i.curr = buf; 1176 i.end = buf+n-1; 1177 if(mkinstr(pc, &i) < 0) 1178 return -1; 1179 for(o = opcodes; o->mnemonic != 0; o++) 1180 if(i.op == o->op && (i.xo & o->xomask) == o->xo) { 1181 if (o->f) 1182 (*o->f)(o, &i); 1183 else 1184 format(o->mnemonic, &i, o->ken); 1185 return i.size*4; 1186 } 1187 bprint(&i, "unknown %lux", i.w0); 1188 return i.size*4; 1189 } 1190 1191 static int 1192 powerinst(Map *map, ulong pc, char modifier, char *buf, int n) 1193 { 1194 USED(modifier); 1195 return printins(map, pc, buf, n); 1196 } 1197 1198 static int 1199 powerdas(Map *map, ulong pc, char *buf, int n) 1200 { 1201 Instr instr; 1202 1203 mymap = map; 1204 memset(&instr, 0, sizeof(instr)); 1205 instr.curr = buf; 1206 instr.end = buf+n-1; 1207 if (mkinstr(pc, &instr) < 0) 1208 return -1; 1209 if (instr.end-instr.curr > 8) 1210 instr.curr = _hexify(instr.curr, instr.w0, 7); 1211 if (instr.end-instr.curr > 9 && instr.size == 2) { 1212 *instr.curr++ = ' '; 1213 instr.curr = _hexify(instr.curr, instr.w1, 7); 1214 } 1215 *instr.curr = 0; 1216 return instr.size*4; 1217 } 1218 1219 static int 1220 powerinstlen(Map *map, ulong pc) 1221 { 1222 Instr i; 1223 1224 mymap = map; 1225 if (mkinstr(pc, &i) < 0) 1226 return -1; 1227 return i.size*4; 1228 } 1229 1230 static int 1231 powerfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) 1232 { 1233 char *reg; 1234 Instr i; 1235 1236 mymap = map; 1237 if (mkinstr(pc, &i) < 0) 1238 return -1; 1239 foll[0] = pc+4; 1240 foll[1] = pc+4; 1241 switch(i.op) { 1242 default: 1243 return 1; 1244 1245 case 18: /* branch */ 1246 foll[0] = i.li; 1247 if(!i.aa) 1248 foll[0] += pc; 1249 break; 1250 1251 case 16: /* conditional branch */ 1252 foll[0] = i.bd; 1253 if(!i.aa) 1254 foll[0] += pc; 1255 break; 1256 1257 case 19: /* conditional branch to register */ 1258 if(i.xo == 528) 1259 reg = "CTR"; 1260 else if(i.xo == 16) 1261 reg = "LR"; 1262 else 1263 return 1; /* not a branch */ 1264 foll[0] = (*rget)(map, reg); 1265 break; 1266 } 1267 if(i.lk) 1268 return 2; 1269 return 1; 1270 } 1271