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