1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 6 /* 7 * Sparc64-specific debugger interface 8 */ 9 10 static char *sparc64excep(Map*, Rgetter); 11 static int sparc64foll(Map*, uvlong, Rgetter, uvlong*); 12 static int sparc64inst(Map*, uvlong, char, char*, int); 13 static int sparc64das(Map*, uvlong, char*, int); 14 static int sparc64instlen(Map*, uvlong); 15 16 Machdata sparc64mach = 17 { 18 {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */ 19 4, /* break point size */ 20 21 beswab, /* convert short to local byte order */ 22 beswal, /* convert long to local byte order */ 23 beswav, /* convert vlong to local byte order */ 24 risctrace, /* C traceback */ 25 riscframe, /* frame finder */ 26 sparc64excep, /* print exception */ 27 0, /* breakpoint fixup */ 28 beieeesftos, /* single precision float printer */ 29 beieeedftos, /* double precision float printer */ 30 sparc64foll, /* following addresses */ 31 sparc64inst, /* print instruction */ 32 sparc64das, /* dissembler */ 33 sparc64instlen, /* instruction size */ 34 }; 35 36 static char *trapname[] = 37 { 38 0, 39 "power on reset", 40 "watchdog reset", 41 "external reset", 42 "software reset", 43 "RED", 44 0, 0, 45 "instruction access exception", 46 "instruction access MMU miss", 47 "instruction access error", 48 0, 0, 0, 0, 0, 49 "illegal instruction", 50 "privileged opcode", 51 "unimplemented LDD", 52 "unimplemented STD", 53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 "fp disabled", 55 "fp exception ieee 754", 56 "fp exception other", 57 0, 0, 0, 0, 58 "division by zero", 59 "internal processor error", 60 0, 0, 0, 0, 0, 0, 61 "data access exception", 62 "data access MMU miss", 63 "data access error", 64 "data access protection", 65 "mem address not aligned", 66 "LDDF mem address not aligned", 67 "STDF mem address not aligned", 68 "privileged action", 69 "LDQF mem address nto aligned", 70 "STQF mem address not aligned", 71 }; 72 73 static char* 74 excname(ulong tt) 75 { 76 static char buf[32]; 77 78 if(tt < sizeof trapname/sizeof(char*) && trapname[tt]) 79 return trapname[tt]; 80 if(tt >= 258) 81 sprint(buf, "trap instruction %ld", tt-128); 82 else if(65<=tt && tt<=79) 83 sprint(buf, "interrupt level %ld", tt-64); 84 else switch(tt){ 85 case 64: 86 return "async data error"; 87 case 96: 88 return "mondo interrupt"; 89 case 100: 90 return "instruction access MMU miss"; 91 case 104: 92 return "data access MMU miss"; 93 case 108: 94 return "data access protection"; 95 case 256: 96 return "syscall"; 97 case 257: 98 return "breakpoint"; 99 default: 100 sprint(buf, "unknown trap %ld", tt); 101 } 102 return buf; 103 } 104 105 static char* 106 sparc64excep(Map *map, Rgetter rget) 107 { 108 long tt; 109 110 tt = (*rget)(map, "TT"); 111 return excname(tt); 112 } 113 114 /* Sparc disassembler and related functions */ 115 116 struct opcode { 117 char *mnemonic; 118 void (*f)(struct instr*, char*); 119 int flag; 120 }; 121 122 static char FRAMENAME[] = ".frame"; 123 124 typedef struct instr Instr; 125 126 struct instr { 127 uchar op; /* bits 31-30 */ 128 uchar rd; /* bits 29-25 */ 129 uchar op2; /* bits 24-22 */ 130 uchar a; /* bit 29 */ 131 uchar cond; /* bits 28-25 */ 132 uchar op3; /* bits 24-19 */ 133 uchar rs1; /* bits 18-14 */ 134 uchar i; /* bit 13 */ 135 uchar asi; /* bits 12-05 */ 136 uchar rs2; /* bits 04-00 */ 137 short simm13; /* bits 12-00, signed */ 138 ushort opf; /* bits 13-05 */ 139 ulong immdisp22; /* bits 21-00 */ 140 ulong simmdisp22; /* bits 21-00, signed */ 141 ulong disp30; /* bits 30-00 */ 142 ulong imm32; /* SETHI+ADD constant */ 143 int target; /* SETHI+ADD dest reg */ 144 long w0; 145 long w1; 146 uvlong addr; /* pc of instruction */ 147 char *curr; /* current fill level in output buffer */ 148 char *end; /* end of buffer */ 149 int size; /* number of longs in instr */ 150 char *err; /* errmsg */ 151 }; 152 153 static Map *mymap; /* disassembler context */ 154 static int dascase; 155 156 static int mkinstr(uvlong, Instr*); 157 static void bra1(Instr*, char*, char*[]); 158 static void bra(Instr*, char*); 159 static void fbra(Instr*, char*); 160 static void cbra(Instr*, char*); 161 static void unimp(Instr*, char*); 162 static void fpop(Instr*, char*); 163 static void shift(Instr*, char*); 164 static void sethi(Instr*, char*); 165 static void load(Instr*, char*); 166 static void loada(Instr*, char*); 167 static void store(Instr*, char*); 168 static void storea(Instr*, char*); 169 static void add(Instr*, char*); 170 static void cmp(Instr*, char*); 171 static void wr(Instr*, char*); 172 static void jmpl(Instr*, char*); 173 static void rd(Instr*, char*); 174 static void loadf(Instr*, char*); 175 static void storef(Instr*, char*); 176 static void loadc(Instr*, char*); 177 static void loadcsr(Instr*, char*); 178 static void trap(Instr*, char*); 179 180 static struct opcode sparc64op0[8] = { 181 [0] "UNIMP", unimp, 0, /* page 137 */ 182 [2] "B", bra, 0, /* page 119 */ 183 [4] "SETHI", sethi, 0, /* page 104 */ 184 [6] "FB", fbra, 0, /* page 121 */ 185 [7] "CB", cbra, 0, /* page 123 */ 186 }; 187 188 static struct opcode sparc64op2[64] = { 189 [0x00] "ADD", add, 0, /* page 108 */ 190 [0x10] "ADDCC", add, 0, 191 [0x08] "ADDX", add, 0, 192 [0x18] "ADDXCC", add, 0, 193 194 [0x20] "TADD", add, 0, /* page 109 */ 195 [0x22] "TADDCCTV", add, 0, 196 197 [0x04] "SUB", add, 0, /* page 110 */ 198 [0x14] "SUBCC", cmp, 0, 199 [0x0C] "SUBX", add, 0, 200 [0x1C] "SUBXCC", add, 0, 201 202 [0x21] "TSUB", add, 0, /* page 111 */ 203 [0x23] "TSUBCCTV", add, 0, 204 205 [0x24] "MULSCC", add, 0, /* page 112 */ 206 207 [0x0A] "UMUL", add, 0, /* page 113 */ 208 [0x0B] "SMUL", add, 0, 209 [0x1A] "UMULCC", add, 0, 210 [0x1B] "SMULCC", add, 0, 211 212 [0x0E] "UDIV", add, 0, /* page 115 */ 213 [0x0F] "SDIV", add, 0, 214 [0x1E] "UDIVCC", add, 0, 215 [0x1F] "SDIVCC", add, 0, 216 217 [0x01] "AND", add, 0, /* page 106 */ 218 [0x11] "ANDCC", add, 0, 219 [0x05] "ANDN", add, 0, 220 [0x15] "ANDNCC", add, 0, 221 [0x02] "OR", add, 0, 222 [0x12] "ORCC", add, 0, 223 [0x06] "ORN", add, 0, 224 [0x16] "ORNCC", add, 0, 225 [0x03] "XOR", add, 0, 226 [0x13] "XORCC", add, 0, 227 [0x07] "XORN", add, 0, 228 [0x17] "XORNCC", add, 0, 229 230 [0x25] "SLL", shift, 0, /* page 107 */ 231 [0x26] "SRL", shift, 0, 232 [0x27] "SRA", shift, 0, 233 234 [0x3C] "SAVE", add, 0, /* page 117 */ 235 [0x3D] "RESTORE", add, 0, 236 237 [0x38] "JMPL", jmpl, 0, /* page 126 */ 238 239 [0x39] "RETT", add, 0, /* page 127 */ 240 241 [0x3A] "T", trap, 0, /* page 129 */ 242 243 [0x28] "rdy", rd, 0, /* page 131 */ 244 [0x29] "rdpsr", rd, 0, 245 [0x2A] "rdwim", rd, 0, 246 [0x2B] "rdtbr", rd, 0, 247 248 [0x30] "wry", wr, 0, /* page 133 */ 249 [0x31] "wrpsr", wr, 0, 250 [0x32] "wrwim", wr, 0, 251 [0x33] "wrtbr", wr, 0, 252 253 [0x3B] "flush", add, 0, /* page 138 */ 254 255 [0x34] "FPOP", fpop, 0, /* page 140 */ 256 [0x35] "FPOP", fpop, 0, 257 }; 258 259 static struct opcode sparc64op3[64]={ 260 [0x09] "ldsb", load, 0, /* page 90 */ 261 [0x19] "ldsba", loada, 0, 262 [0x0A] "ldsh", load, 0, 263 [0x1A] "ldsha", loada, 0, 264 [0x01] "ldub", load, 0, 265 [0x11] "lduba", loada, 0, 266 [0x02] "lduh", load, 0, 267 [0x12] "lduha", loada, 0, 268 [0x00] "ld", load, 0, 269 [0x10] "lda", loada, 0, 270 [0x03] "ldd", load, 0, 271 [0x13] "ldda", loada, 0, 272 273 [0x20] "ldf", loadf, 0, /* page 92 */ 274 [0x23] "lddf", loadf, 0, 275 [0x21] "ldfsr", loadf,0, 276 277 [0x30] "ldc", loadc, 0, /* page 94 */ 278 [0x33] "lddc", loadc, 0, 279 [0x31] "ldcsr", loadcsr,0, 280 281 [0x05] "stb", store, 0, /* page 95 */ 282 [0x15] "stba", storea, 0, 283 [0x06] "sth", store, 0, 284 [0x16] "stha", storea, 0, 285 [0x04] "st", store, 0, 286 [0x14] "sta", storea, 0, 287 [0x07] "std", store, 0, 288 [0x17] "stda", storea, 0, 289 290 [0x24] "stf", storef, 0, /* page 97 */ 291 [0x27] "stdf", storef, 0, 292 [0x25] "stfsr", storef,0, 293 [0x26] "stdfq", storef,0, 294 295 [0x34] "stc", loadc, 0, /* page 99 */ 296 [0x37] "stdc", loadc, 0, 297 [0x35] "stcsr", loadcsr,0, 298 [0x36] "stdcq", loadcsr,0, 299 300 [0x0D] "ldstub", store, 0, /* page 101 */ 301 [0x1D] "ldstuba", storea, 0, 302 303 [0x0F] "swap", load, 0, /* page 102 */ 304 [0x1F] "swapa", loada, 0, 305 }; 306 307 #pragma varargck argpos bprint 2 308 #pragma varargck type "T" char* 309 310 /* convert to lower case from upper, according to dascase */ 311 static int 312 Tfmt(Fmt *f) 313 { 314 char buf[128]; 315 char *s, *t, *oa; 316 317 oa = va_arg(f->args, char*); 318 if(dascase){ 319 for(s=oa,t=buf; *t = *s; s++,t++) 320 if('A'<=*t && *t<='Z') 321 *t += 'a'-'A'; 322 return fmtstrcpy(f, buf); 323 } 324 return fmtstrcpy(f, oa); 325 } 326 327 static void 328 bprint(Instr *i, char *fmt, ...) 329 { 330 va_list arg; 331 332 va_start(arg, fmt); 333 i->curr = vseprint(i->curr, i->end, fmt, arg); 334 va_end(arg); 335 } 336 337 static int 338 decode(ulong pc, Instr *i) 339 { 340 ulong w; 341 342 if (get4(mymap, pc, &w) < 0) { 343 werrstr("can't read instruction: %r"); 344 return -1; 345 } 346 i->op = (w >> 30) & 0x03; 347 i->rd = (w >> 25) & 0x1F; 348 i->op2 = (w >> 22) & 0x07; 349 i->a = (w >> 29) & 0x01; 350 i->cond = (w >> 25) & 0x0F; 351 i->op3 = (w >> 19) & 0x3F; 352 i->rs1 = (w >> 14) & 0x1F; 353 i->i = (w >> 13) & 0x01; 354 i->asi = (w >> 5) & 0xFF; 355 i->rs2 = (w >> 0) & 0x1F; 356 i->simm13 = (w >> 0) & 0x1FFF; 357 if(i->simm13 & (1<<12)) 358 i->simm13 |= ~((1<<13)-1); 359 i->opf = (w >> 5) & 0x1FF; 360 i->immdisp22 = (w >> 0) & 0x3FFFFF; 361 i->simmdisp22 = i->immdisp22; 362 if(i->simmdisp22 & (1<<21)) 363 i->simmdisp22 |= ~((1<<22)-1); 364 i->disp30 = (w >> 0) & 0x3FFFFFFF; 365 i->w0 = w; 366 i->target = -1; 367 i->addr = pc; 368 i->size = 1; 369 return 1; 370 } 371 372 static int 373 mkinstr(uvlong pc, Instr *i) 374 { 375 Instr xi; 376 377 if (decode(pc, i) < 0) 378 return -1; 379 if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */ 380 if (decode(pc+4, &xi) < 0) 381 return -1; 382 if(xi.op==2 && xi.op3==0) /* ADD */ 383 if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */ 384 i->imm32 = xi.simm13 + (i->immdisp22<<10); 385 i->target = xi.rd; 386 i->w1 = xi.w0; 387 i->size++; 388 return 1; 389 } 390 } 391 if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */ 392 if (decode(pc+4, &xi) < 0) 393 return -1; 394 if(i->op==2 && i->opf==1) /* FMOVS */ 395 if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */ 396 i->w1 = xi.w0; 397 i->size++; 398 } 399 } 400 return 1; 401 } 402 403 static int 404 printins(Map *map, uvlong pc, char *buf, int n) 405 { 406 Instr instr; 407 void (*f)(Instr*, char*); 408 409 mymap = map; 410 memset(&instr, 0, sizeof(instr)); 411 instr.curr = buf; 412 instr.end = buf+n-1; 413 if (mkinstr(pc, &instr) < 0) 414 return -1; 415 switch(instr.op){ 416 case 0: 417 f = sparc64op0[instr.op2].f; 418 if(f) 419 (*f)(&instr, sparc64op0[instr.op2].mnemonic); 420 else 421 bprint(&instr, "unknown %lux", instr.w0); 422 break; 423 424 case 1: 425 bprint(&instr, "CALL\t"); 426 instr.curr += symoff(instr.curr, instr.end-instr.curr, 427 pc+instr.disp30*4, CTEXT); 428 if (!dascase) 429 bprint(&instr, "(SB)"); 430 break; 431 432 case 2: 433 f = sparc64op2[instr.op3].f; 434 if(f) 435 (*f)(&instr, sparc64op2[instr.op3].mnemonic); 436 else 437 bprint(&instr, "unknown %lux", instr.w0); 438 break; 439 440 case 3: 441 f = sparc64op3[instr.op3].f; 442 if(f) 443 (*f)(&instr, sparc64op3[instr.op3].mnemonic); 444 else 445 bprint(&instr, "unknown %lux", instr.w0); 446 break; 447 } 448 if (instr.err) { 449 if (instr.curr != buf) 450 bprint(&instr, "\t\t;"); 451 bprint(&instr, instr.err); 452 } 453 return instr.size*4; 454 } 455 456 static int 457 sparc64inst(Map *map, uvlong pc, char modifier, char *buf, int n) 458 { 459 static int fmtinstalled = 0; 460 461 /* a modifier of 'I' toggles the dissassembler type */ 462 if (!fmtinstalled) { 463 fmtinstalled = 1; 464 fmtinstall('T', Tfmt); 465 } 466 if ((asstype == ASUNSPARC && modifier == 'i') 467 || (asstype == ASPARC && modifier == 'I')) 468 dascase = 'a'-'A'; 469 else 470 dascase = 0; 471 return printins(map, pc, buf, n); 472 } 473 474 static int 475 sparc64das(Map *map, uvlong pc, char *buf, int n) 476 { 477 Instr instr; 478 479 mymap = map; 480 memset(&instr, 0, sizeof(instr)); 481 instr.curr = buf; 482 instr.end = buf+n-1; 483 if (mkinstr(pc, &instr) < 0) 484 return -1; 485 if (instr.end-instr.curr > 8) 486 instr.curr = _hexify(instr.curr, instr.w0, 7); 487 if (instr.end-instr.curr > 9 && instr.size == 2) { 488 *instr.curr++ = ' '; 489 instr.curr = _hexify(instr.curr, instr.w1, 7); 490 } 491 *instr.curr = 0; 492 return instr.size*4; 493 } 494 495 static int 496 sparc64instlen(Map *map, uvlong pc) 497 { 498 Instr i; 499 500 mymap = map; 501 if (mkinstr(pc, &i) < 0) 502 return -1; 503 return i.size*4; 504 } 505 506 static int 507 plocal(Instr *i) 508 { 509 long offset; 510 Symbol s; 511 512 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) 513 return -1; 514 if (s.value > i->simm13) { 515 if(getauto(&s, s.value-i->simm13, CAUTO, &s)) { 516 bprint(i, "%s+%lld(SP)", s.name, s.value); 517 return 1; 518 } 519 } else { 520 offset = i->simm13-s.value; 521 if (getauto(&s, offset-4, CPARAM, &s)) { 522 bprint(i, "%s+%ld(FP)", s.name, offset); 523 return 1; 524 } 525 } 526 return -1; 527 } 528 529 static void 530 address(Instr *i) 531 { 532 Symbol s, s2; 533 uvlong off, off1; 534 535 if (i->rs1 == 1 && plocal(i) >= 0) 536 return; 537 off = mach->sb+i->simm13; 538 if(i->rs1 == 2 && findsym(off, CANY, &s) 539 && s.value-off < 4096 540 && (s.class == CDATA || s.class == CTEXT)) { 541 if(off==s.value && s.name[0]=='$'){ 542 off1 = 0; 543 geta(mymap, s.value, &off1); 544 if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ 545 bprint(i, "$%s(SB)", s2.name); 546 return; 547 } 548 } 549 bprint(i, "%s", s.name); 550 if (s.value != off) 551 bprint(i, "+%llux", s.value-off); 552 bprint(i, "(SB)"); 553 return; 554 } 555 bprint(i, "%ux(R%d)", i->simm13, i->rs1); 556 } 557 558 static void 559 unimp(Instr *i, char *m) 560 { 561 bprint(i, "%T", m); 562 } 563 564 static char *bratab[16] = { /* page 91 */ 565 [0X8] "A", 566 [0X0] "N", 567 [0X9] "NE", 568 [0X1] "E", 569 [0XA] "G", 570 [0X2] "LE", 571 [0XB] "GE", 572 [0X3] "L", 573 [0XC] "GU", 574 [0X4] "LEU", 575 [0XD] "CC", 576 [0X5] "CS", 577 [0XE] "POS", 578 [0X6] "NEG", 579 [0XF] "VC", 580 [0X7] "VS", 581 }; 582 583 static char *fbratab[16] = { /* page 91 */ 584 [0X8] "A", 585 [0X0] "N", 586 [0X7] "U", 587 [0X6] "G", 588 [0X5] "UG", 589 [0X4] "L", 590 [0X3] "UL", 591 [0X2] "LG", 592 [0X1] "NE", 593 [0X9] "E", 594 [0XA] "UE", 595 [0XB] "GE", 596 [0XC] "UGE", 597 [0XD] "LE", 598 [0XE] "ULE", 599 [0XF] "O", 600 }; 601 602 static char *cbratab[16] = { /* page 91 */ 603 [0X8] "A", 604 [0X0] "N", 605 [0X7] "3", 606 [0X6] "2", 607 [0X5] "23", 608 [0X4] "1", 609 [0X3] "13", 610 [0X2] "12", 611 [0X1] "123", 612 [0X9] "0", 613 [0XA] "03", 614 [0XB] "02", 615 [0XC] "023", 616 [0XD] "01", 617 [0XE] "013", 618 [0XF] "012", 619 }; 620 621 static void 622 bra1(Instr *i, char *m, char *tab[]) 623 { 624 long imm; 625 626 imm = i->simmdisp22; 627 if(i->a) 628 bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase); 629 else 630 bprint(i, "%T%T\t", m, tab[i->cond]); 631 i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT); 632 if (!dascase) 633 bprint(i, "(SB)"); 634 } 635 636 static void 637 bra(Instr *i, char *m) /* page 91 */ 638 { 639 bra1(i, m, bratab); 640 } 641 642 static void 643 fbra(Instr *i, char *m) /* page 93 */ 644 { 645 bra1(i, m, fbratab); 646 } 647 648 static void 649 cbra(Instr *i, char *m) /* page 95 */ 650 { 651 bra1(i, m, cbratab); 652 } 653 654 static void 655 trap(Instr *i, char *m) /* page 101 */ 656 { 657 if(i->i == 0) 658 bprint(i, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1); 659 else 660 bprint(i, "%T%T\t$%ux+R%d", m, bratab[i->cond], i->simm13, i->rs1); 661 } 662 663 static void 664 sethi(Instr *i, char *m) /* page 89 */ 665 { 666 ulong imm; 667 668 imm = i->immdisp22<<10; 669 if(dascase){ 670 bprint(i, "%T\t%lux, R%d", m, imm, i->rd); 671 return; 672 } 673 if(imm==0 && i->rd==0){ 674 bprint(i, "NOP"); 675 return; 676 } 677 if(i->target < 0){ 678 bprint(i, "MOVW\t$%lux, R%d", imm, i->rd); 679 return; 680 } 681 bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target); 682 } 683 684 static char ldtab[] = { 685 'W', 686 'B', 687 'H', 688 'D', 689 }; 690 691 static char* 692 moveinstr(int op3, char *m) 693 { 694 char *s; 695 int c; 696 static char buf[8]; 697 698 if(!dascase){ 699 /* batshit cases */ 700 if(op3 == 0xF || op3 == 0x1F) 701 return "SWAP"; 702 if(op3 == 0xD || op3 == 0x1D) 703 return "TAS"; /* really LDSTUB */ 704 c = ldtab[op3&3]; 705 s = ""; 706 if((op3&11)==1 || (op3&11)==2) 707 s="U"; 708 sprint(buf, "MOV%c%s", c, s); 709 return buf; 710 } 711 return m; 712 } 713 714 static void 715 load(Instr *i, char *m) /* page 68 */ 716 { 717 m = moveinstr(i->op3, m); 718 if(i->i == 0) 719 bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd); 720 else{ 721 bprint(i, "%s\t", m); 722 address(i); 723 bprint(i, ", R%d", i->rd); 724 } 725 } 726 727 static void 728 loada(Instr *i, char *m) /* page 68 */ 729 { 730 m = moveinstr(i->op3, m); 731 if(i->i == 0) 732 bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd); 733 else 734 bprint(i, "unknown ld asi %lux", i->w0); 735 } 736 737 static void 738 store(Instr *i, char *m) /* page 74 */ 739 { 740 m = moveinstr(i->op3, m); 741 if(i->i == 0) 742 bprint(i, "%s\tR%d, (R%d+R%d)", 743 m, i->rd, i->rs1, i->rs2); 744 else{ 745 bprint(i, "%s\tR%d, ", m, i->rd); 746 address(i); 747 } 748 } 749 750 static void 751 storea(Instr *i, char *m) /* page 74 */ 752 { 753 m = moveinstr(i->op3, m); 754 if(i->i == 0) 755 bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi); 756 else 757 bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi); 758 } 759 760 static void 761 shift(Instr *i, char *m) /* page 88 */ 762 { 763 if(i->i == 0){ 764 if(i->rs1 == i->rd) 765 if(dascase) 766 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2); 767 else 768 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1); 769 else 770 if(dascase) 771 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd); 772 else 773 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd); 774 }else{ 775 if(i->rs1 == i->rd) 776 if(dascase) 777 bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1); 778 else 779 bprint(i, "%T\tR%d, $%d", m, i->rs1, i->simm13&0x1F); 780 else 781 if(dascase) 782 bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd); 783 else 784 bprint(i, "%T\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd); 785 } 786 } 787 788 static void 789 add(Instr *i, char *m) /* page 82 */ 790 { 791 if(i->i == 0){ 792 if(dascase) 793 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2); 794 else 795 if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */ 796 bprint(i, "MOVW\tR%d", i->rs2); 797 else 798 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1); 799 }else{ 800 if(dascase) 801 bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13); 802 else 803 if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */ 804 bprint(i, "MOVW\t$%ux", i->simm13); 805 else if(i->op3==0 && i->rd && i->rs1==2){ 806 /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */ 807 bprint(i, "MOVW\t$"); 808 address(i); 809 } else 810 bprint(i, "%T\t$%ux, R%d", m, i->simm13, i->rs1); 811 } 812 if(i->rs1 != i->rd) 813 bprint(i, ", R%d", i->rd); 814 } 815 816 static void 817 cmp(Instr *i, char *m) 818 { 819 if(dascase || i->rd){ 820 add(i, m); 821 return; 822 } 823 if(i->i == 0) 824 bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2); 825 else 826 bprint(i, "CMP\tR%d, $%ux", i->rs1, i->simm13); 827 } 828 829 static char *regtab[4] = { 830 "Y", 831 "PSTATE", 832 "WIM", /* XXX not any more */ 833 "TT", 834 }; 835 836 static void 837 wr(Instr *i, char *m) /* page 82 */ 838 { 839 if(dascase){ 840 if(i->i == 0) 841 bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2); 842 else 843 bprint(i, "%s\tR%d, $%ux", m, i->rs1, i->simm13); 844 }else{ 845 if(i->i && i->simm13==0) 846 bprint(i, "MOVW\tR%d", i->rs1); 847 else if(i->i == 0) 848 bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1); 849 else 850 bprint(i, "wr\t$%ux, R%d", i->simm13, i->rs1); 851 } 852 bprint(i, ", %s", regtab[i->op3&3]); 853 } 854 855 static void 856 rd(Instr *i, char *m) /* page 103 */ 857 { 858 if(i->rs1==15 && i->rd==0){ 859 m = "stbar"; 860 if(!dascase) 861 m = "STBAR"; 862 bprint(i, "%s", m); 863 }else{ 864 if(!dascase) 865 m = "MOVW"; 866 bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd); 867 } 868 } 869 870 static void 871 jmpl(Instr *i, char *m) /* page 82 */ 872 { 873 if(i->i == 0){ 874 if(i->rd == 15) 875 bprint(i, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1); 876 else 877 bprint(i, "%T\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd); 878 }else{ 879 if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0) 880 bprint(i, "RETURN"); 881 else{ 882 bprint(i, "%T\t", m); 883 address(i); 884 bprint(i, ", R%d", i->rd); 885 } 886 } 887 } 888 889 static void 890 loadf(Instr *i, char *m) /* page 70 */ 891 { 892 if(!dascase){ 893 m = "FMOVD"; 894 if(i->op3 == 0x20) 895 m = "FMOVF"; 896 else if(i->op3 == 0x21) 897 m = "MOVW"; 898 } 899 if(i->i == 0) 900 bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2); 901 else{ 902 bprint(i, "%s\t", m); 903 address(i); 904 } 905 if(i->op3 == 0x21) 906 bprint(i, ", FSR"); 907 else 908 bprint(i, ", R%d", i->rd); 909 } 910 911 static 912 void storef(Instr *i, char *m) /* page 70 */ 913 { 914 if(!dascase){ 915 m = "FMOVD"; 916 if(i->op3 == 0x25 || i->op3 == 0x26) 917 m = "MOVW"; 918 else if(i->op3 == 0x20) 919 m = "FMOVF"; 920 } 921 bprint(i, "%s\t", m); 922 if(i->op3 == 0x25) 923 bprint(i, "FSR, "); 924 else if(i->op3 == 0x26) 925 bprint(i, "FQ, "); 926 else 927 bprint(i, "R%d, ", i->rd); 928 if(i->i == 0) 929 bprint(i, "(R%d+R%d)", i->rs1, i->rs2); 930 else 931 address(i); 932 } 933 934 static 935 void loadc(Instr *i, char *m) /* page 72 */ 936 { 937 if(i->i == 0) 938 bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd); 939 else{ 940 bprint(i, "%s\t", m); 941 address(i); 942 bprint(i, ", C%d", i->rd); 943 } 944 } 945 946 static 947 void loadcsr(Instr *i, char *m) /* page 72 */ 948 { 949 if(i->i == 0) 950 bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2); 951 else{ 952 bprint(i, "%s\t", m); 953 address(i); 954 bprint(i, ", CSR"); 955 } 956 } 957 958 static struct{ 959 int opf; 960 char *name; 961 } fptab1[] = { /* ignores rs1 */ 962 0xC4, "FITOS", /* page 109 */ 963 0xC8, "FITOD", 964 0xCC, "FITOX", 965 966 0xD1, "FSTOI", /* page 110 */ 967 0xD2, "FDTOI", 968 0xD3, "FXTOI", 969 970 0xC9, "FSTOD", /* page 111 */ 971 0xCD, "FSTOX", 972 0xC6, "FDTOS", 973 0xCE, "FDTOX", 974 0xC7, "FXTOS", 975 0xCB, "FXTOD", 976 977 0x01, "FMOVS", /* page 112 */ 978 0x05, "FNEGS", 979 0x09, "FABSS", 980 981 0x29, "FSQRTS", /* page 113 */ 982 0x2A, "FSQRTD", 983 0x2B, "FSQRTX", 984 985 0, 0, 986 }; 987 988 static struct{ 989 int opf; 990 char *name; 991 } fptab2[] = { /* uses rs1 */ 992 993 0x41, "FADDS", /* page 114 */ 994 0x42, "FADDD", 995 0x43, "FADDX", 996 0x45, "FSUBS", 997 0x46, "FSUBD", 998 0x47, "FSUBX", 999 1000 0x49, "FMULS", /* page 115 */ 1001 0x4A, "FMULD", 1002 0x4B, "FMULX", 1003 0x4D, "FDIVS", 1004 0x4E, "FDIVD", 1005 0x4F, "FDIVX", 1006 1007 0x51, "FCMPS", /* page 116 */ 1008 0x52, "FCMPD", 1009 0x53, "FCMPX", 1010 0x55, "FCMPES", 1011 0x56, "FCMPED", 1012 0x57, "FCMPEX", 1013 1014 0, 0 1015 }; 1016 1017 static void 1018 fpop(Instr *i, char *m) /* page 108-116 */ 1019 { 1020 int j; 1021 1022 if(dascase==0 && i->size==2){ 1023 bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd); 1024 return; 1025 } 1026 for(j=0; fptab1[j].name; j++) 1027 if(fptab1[j].opf == i->opf){ 1028 bprint(i, "%T\tF%d, F%d", fptab1[j].name, i->rs2, i->rd); 1029 return; 1030 } 1031 for(j=0; fptab2[j].name; j++) 1032 if(fptab2[j].opf == i->opf){ 1033 bprint(i, "%T\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd); 1034 return; 1035 } 1036 bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd); 1037 } 1038 1039 static int 1040 sparc64foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) 1041 { 1042 ulong w, r1, r2; 1043 char buf[8]; 1044 Instr i; 1045 1046 mymap = map; 1047 if (mkinstr(pc, &i) < 0) 1048 return -1; 1049 w = i.w0; 1050 switch(w & 0xC1C00000){ 1051 case 0x00800000: /* branch on int cond */ 1052 case 0x01800000: /* branch on fp cond */ 1053 case 0x01C00000: /* branch on copr cond */ 1054 foll[0] = pc+8; 1055 foll[1] = pc + (i.simmdisp22<<2); 1056 return 2; 1057 } 1058 1059 if((w&0xC0000000) == 0x40000000){ /* CALL */ 1060 foll[0] = pc + (i.disp30<<2); 1061 return 1; 1062 } 1063 1064 if((w&0xC1F80000) == 0x81C00000){ /* JMPL */ 1065 sprint(buf, "R%ld", (w>>14)&0xF); 1066 r1 = (*rget)(map, buf); 1067 if(w & 0x2000) /* JMPL R1+simm13 */ 1068 r2 = i.simm13; 1069 else{ /* JMPL R1+R2 */ 1070 sprint(buf, "R%ld", w&0xF); 1071 r2 = (*rget)(map, buf); 1072 } 1073 foll[0] = r1 + r2; 1074 return 1; 1075 } 1076 foll[0] = pc+i.size*4; 1077 return 1; 1078 } 1079