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*, ulong, Rgetter, ulong*); 11 static int sparcinst(Map*, ulong, char, char*, int); 12 static int sparcdas(Map*, ulong, char*, int); 13 static int sparcinstlen(Map*, ulong); 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 88 typedef struct instr Instr; 89 90 struct opcode { 91 char *mnemonic; 92 void (*f)(Instr*, char*); 93 int flag; 94 }; 95 96 static char FRAMENAME[] = ".frame"; 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 ulong 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(ulong, 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 static void 288 bprint(Instr *i, char *fmt, ...) 289 { 290 va_list arg; 291 292 va_start(arg, fmt); 293 i->curr = vseprint(i->curr, i->end, fmt, arg); 294 va_end(arg); 295 } 296 297 static int 298 decode(ulong pc, Instr *i) 299 { 300 long w; 301 302 if (get4(mymap, pc, &w) < 0) { 303 werrstr("can't read instruction: %r"); 304 return -1; 305 } 306 i->op = (w >> 30) & 0x03; 307 i->rd = (w >> 25) & 0x1F; 308 i->op2 = (w >> 22) & 0x07; 309 i->a = (w >> 29) & 0x01; 310 i->cond = (w >> 25) & 0x0F; 311 i->op3 = (w >> 19) & 0x3F; 312 i->rs1 = (w >> 14) & 0x1F; 313 i->i = (w >> 13) & 0x01; 314 i->asi = (w >> 5) & 0xFF; 315 i->rs2 = (w >> 0) & 0x1F; 316 i->simm13 = (w >> 0) & 0x1FFF; 317 if(i->simm13 & (1<<12)) 318 i->simm13 |= ~((1<<13)-1); 319 i->opf = (w >> 5) & 0x1FF; 320 i->immdisp22 = (w >> 0) & 0x3FFFFF; 321 i->simmdisp22 = i->immdisp22; 322 if(i->simmdisp22 & (1<<21)) 323 i->simmdisp22 |= ~((1<<22)-1); 324 i->disp30 = (w >> 0) & 0x3FFFFFFF; 325 i->w0 = w; 326 i->target = -1; 327 i->addr = pc; 328 i->size = 1; 329 return 1; 330 } 331 332 static int 333 mkinstr(ulong pc, Instr *i) 334 { 335 Instr xi; 336 337 if (decode(pc, i) < 0) 338 return -1; 339 if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */ 340 if (decode(pc+4, &xi) < 0) 341 return -1; 342 if(xi.op==2 && xi.op3==0) /* ADD */ 343 if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */ 344 i->imm32 = xi.simm13 + (i->immdisp22<<10); 345 i->target = xi.rd; 346 i->w1 = xi.w0; 347 i->size++; 348 return 1; 349 } 350 } 351 if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */ 352 if (decode(pc+4, &xi) < 0) 353 return -1; 354 if(i->op==2 && i->opf==1) /* FMOVS */ 355 if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */ 356 i->w1 = xi.w0; 357 i->size++; 358 } 359 } 360 return 1; 361 } 362 363 static int 364 printins(Map *map, ulong pc, char *buf, int n) 365 { 366 Instr instr; 367 void (*f)(Instr*, char*); 368 369 mymap = map; 370 memset(&instr, 0, sizeof(instr)); 371 instr.curr = buf; 372 instr.end = buf+n-1; 373 if (mkinstr(pc, &instr) < 0) 374 return -1; 375 switch(instr.op){ 376 case 0: 377 f = sparcop0[instr.op2].f; 378 if(f) 379 (*f)(&instr, sparcop0[instr.op2].mnemonic); 380 else 381 bprint(&instr, "unknown %lux", instr.w0); 382 break; 383 384 case 1: 385 bprint(&instr, "%X", "CALL\t"); 386 instr.curr += symoff(instr.curr, instr.end-instr.curr, 387 pc+instr.disp30*4, CTEXT); 388 if (!dascase) 389 bprint(&instr, "(SB)"); 390 break; 391 392 case 2: 393 f = sparcop2[instr.op3].f; 394 if(f) 395 (*f)(&instr, sparcop2[instr.op3].mnemonic); 396 else 397 bprint(&instr, "unknown %lux", instr.w0); 398 break; 399 400 case 3: 401 f = sparcop3[instr.op3].f; 402 if(f) 403 (*f)(&instr, sparcop3[instr.op3].mnemonic); 404 else 405 bprint(&instr, "unknown %lux", instr.w0); 406 break; 407 } 408 if (instr.err) { 409 if (instr.curr != buf) 410 bprint(&instr, "\t\t;"); 411 bprint(&instr, instr.err); 412 } 413 return instr.size*4; 414 } 415 416 /* convert to lower case from upper, according to dascase */ 417 static int 418 Xconv(Fmt *f) 419 { 420 char buf[128]; 421 char *s, *t, *oa; 422 423 oa = va_arg(f->args, char*); 424 if(dascase){ 425 for(s=oa,t=buf; *t = *s; s++,t++) 426 if('A'<=*t && *t<='Z') 427 *t += 'a'-'A'; 428 return fmtstrcpy(f, buf); 429 } 430 return fmtstrcpy(f, oa); 431 } 432 433 static int 434 sparcinst(Map *map, ulong pc, char modifier, char *buf, int n) 435 { 436 static int fmtinstalled = 0; 437 438 /* a modifier of 'I' toggles the dissassembler type */ 439 if (!fmtinstalled) { 440 fmtinstalled = 1; 441 fmtinstall('X', Xconv); 442 } 443 if ((asstype == ASUNSPARC && modifier == 'i') 444 || (asstype == ASPARC && modifier == 'I')) 445 dascase = 'a'-'A'; 446 else 447 dascase = 0; 448 return printins(map, pc, buf, n); 449 } 450 451 static int 452 sparcdas(Map *map, ulong pc, char *buf, int n) 453 { 454 Instr instr; 455 456 mymap = map; 457 memset(&instr, 0, sizeof(instr)); 458 instr.curr = buf; 459 instr.end = buf+n-1; 460 if (mkinstr(pc, &instr) < 0) 461 return -1; 462 if (instr.end-instr.curr > 8) 463 instr.curr = _hexify(instr.curr, instr.w0, 7); 464 if (instr.end-instr.curr > 9 && instr.size == 2) { 465 *instr.curr++ = ' '; 466 instr.curr = _hexify(instr.curr, instr.w1, 7); 467 } 468 *instr.curr = 0; 469 return instr.size*4; 470 } 471 472 static int 473 sparcinstlen(Map *map, ulong pc) 474 { 475 Instr i; 476 477 mymap = map; 478 if (mkinstr(pc, &i) < 0) 479 return -1; 480 return i.size*4; 481 } 482 483 static int 484 plocal(Instr *i) 485 { 486 int offset; 487 Symbol s; 488 489 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) 490 return -1; 491 if (s.value > i->simm13) { 492 if(getauto(&s, s.value-i->simm13, CAUTO, &s)) { 493 bprint(i, "%s+%d(SP)", s.name, s.value); 494 return 1; 495 } 496 } else { 497 offset = i->simm13-s.value; 498 if (getauto(&s, offset-4, CPARAM, &s)) { 499 bprint(i, "%s+%d(FP)", s.name, offset); 500 return 1; 501 } 502 } 503 return -1; 504 } 505 506 static void 507 address(Instr *i) 508 { 509 Symbol s, s2; 510 long off, off1; 511 512 if (i->rs1 == 1 && plocal(i) >= 0) 513 return; 514 off = mach->sb+i->simm13; 515 if(i->rs1 == 2 && findsym(off, CANY, &s) 516 && s.value-off < 4096 517 && (s.class == CDATA || s.class == CTEXT)) { 518 if(off==s.value && s.name[0]=='$'){ 519 off1 = 0; 520 get4(mymap, s.value, &off1); 521 if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ 522 bprint(i, "$%s(SB)", s2.name); 523 return; 524 } 525 } 526 bprint(i, "%s", s.name); 527 if (s.value != off) 528 bprint(i, "+%lux", s.value-off); 529 bprint(i, "(SB)"); 530 return; 531 } 532 bprint(i, "%lux(R%d)", i->simm13, i->rs1); 533 } 534 535 static void 536 unimp(Instr *i, char *m) 537 { 538 bprint(i, "%X", m); 539 } 540 541 static char *bratab[16] = { /* page 91 */ 542 "N", /* 0x0 */ 543 "E", /* 0x1 */ 544 "LE", /* 0x2 */ 545 "L", /* 0x3 */ 546 "LEU", /* 0x4 */ 547 "CS", /* 0x5 */ 548 "NEG", /* 0x6 */ 549 "VS", /* 0x7 */ 550 "A", /* 0x8 */ 551 "NE", /* 0x9 */ 552 "G", /* 0xa */ 553 "GE", /* 0xb */ 554 "GU", /* 0xc */ 555 "CC", /* 0xd */ 556 "POS", /* 0xe */ 557 "VC", /* 0xf */ 558 }; 559 560 static char *fbratab[16] = { /* page 91 */ 561 "N", /* 0x0 */ 562 "NE", /* 0x1 */ 563 "LG", /* 0x2 */ 564 "UL", /* 0x3 */ 565 "L", /* 0x4 */ 566 "UG", /* 0x5 */ 567 "G", /* 0x6 */ 568 "U", /* 0x7 */ 569 "A", /* 0x8 */ 570 "E", /* 0x9 */ 571 "UE", /* 0xa */ 572 "GE", /* 0xb */ 573 "UGE", /* 0xc */ 574 "LE", /* 0xd */ 575 "ULE", /* 0xe */ 576 "O", /* 0xf */ 577 }; 578 579 static char *cbratab[16] = { /* page 91 */ 580 "N", /* 0x0 */ 581 "123", /* 0x1 */ 582 "12", /* 0x2 */ 583 "13", /* 0x3 */ 584 "1", /* 0x4 */ 585 "23", /* 0x5 */ 586 "2", /* 0x6 */ 587 "3", /* 0x7 */ 588 "A", /* 0x8 */ 589 "0", /* 0x9 */ 590 "03", /* 0xa */ 591 "02", /* 0xb */ 592 "023", /* 0xc */ 593 "01", /* 0xd */ 594 "013", /* 0xe */ 595 "012", /* 0xf */ 596 }; 597 598 static void 599 bra1(Instr *i, char *m, char *tab[]) 600 { 601 long imm; 602 603 imm = i->simmdisp22; 604 if(i->a) 605 bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase); 606 else 607 bprint(i, "%X%X\t", m, tab[i->cond]); 608 i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT); 609 if (!dascase) 610 bprint(i, "(SB)"); 611 } 612 613 static void 614 bra(Instr *i, char *m) /* page 91 */ 615 { 616 bra1(i, m, bratab); 617 } 618 619 static void 620 fbra(Instr *i, char *m) /* page 93 */ 621 { 622 bra1(i, m, fbratab); 623 } 624 625 static void 626 cbra(Instr *i, char *m) /* page 95 */ 627 { 628 bra1(i, m, cbratab); 629 } 630 631 static void 632 trap(Instr *i, char *m) /* page 101 */ 633 { 634 if(i->i == 0) 635 bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1); 636 else 637 bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1); 638 } 639 640 static void 641 sethi(Instr *i, char *m) /* page 89 */ 642 { 643 ulong imm; 644 645 imm = i->immdisp22<<10; 646 if(dascase){ 647 bprint(i, "%X\t%lux, R%d", m, imm, i->rd); 648 return; 649 } 650 if(imm==0 && i->rd==0){ 651 bprint(i, "NOP"); 652 return; 653 } 654 if(i->target < 0){ 655 bprint(i, "MOVW\t$%lux, R%d", imm, i->rd); 656 return; 657 } 658 bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target); 659 } 660 661 static char ldtab[] = { 662 'W', 663 'B', 664 'H', 665 'D', 666 }; 667 668 static char* 669 moveinstr(int op3, char *m) 670 { 671 char *s; 672 int c; 673 static char buf[8]; 674 675 if(!dascase){ 676 /* batshit cases */ 677 if(op3 == 0xF || op3 == 0x1F) 678 return "SWAP"; 679 if(op3 == 0xD || op3 == 0x1D) 680 return "TAS"; /* really LDSTUB */ 681 c = ldtab[op3&3]; 682 s = ""; 683 if((op3&11)==1 || (op3&11)==2) 684 s="U"; 685 sprint(buf, "MOV%c%s", c, s); 686 return buf; 687 } 688 return m; 689 } 690 691 static void 692 load(Instr *i, char *m) /* page 68 */ 693 { 694 m = moveinstr(i->op3, m); 695 if(i->i == 0) 696 bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd); 697 else{ 698 bprint(i, "%s\t", m); 699 address(i); 700 bprint(i, ", R%d", i->rd); 701 } 702 } 703 704 static void 705 loada(Instr *i, char *m) /* page 68 */ 706 { 707 m = moveinstr(i->op3, m); 708 if(i->i == 0) 709 bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd); 710 else 711 bprint(i, "unknown ld asi %lux", i->w0); 712 } 713 714 static void 715 store(Instr *i, char *m) /* page 74 */ 716 { 717 m = moveinstr(i->op3, m); 718 if(i->i == 0) 719 bprint(i, "%s\tR%d, (R%d+R%d)", 720 m, i->rd, i->rs1, i->rs2); 721 else{ 722 bprint(i, "%s\tR%d, ", m, i->rd); 723 address(i); 724 } 725 } 726 727 static void 728 storea(Instr *i, char *m) /* page 74 */ 729 { 730 m = moveinstr(i->op3, m); 731 if(i->i == 0) 732 bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi); 733 else 734 bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi); 735 } 736 737 static void 738 shift(Instr *i, char *m) /* page 88 */ 739 { 740 if(i->i == 0){ 741 if(i->rs1 == i->rd) 742 if(dascase) 743 bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); 744 else 745 bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); 746 else 747 if(dascase) 748 bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd); 749 else 750 bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd); 751 }else{ 752 if(i->rs1 == i->rd) 753 if(dascase) 754 bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1); 755 else 756 bprint(i, "%X\tR%d, $%d", m, i->rs1, i->simm13&0x1F); 757 else 758 if(dascase) 759 bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd); 760 else 761 bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd); 762 } 763 } 764 765 static void 766 add(Instr *i, char *m) /* page 82 */ 767 { 768 if(i->i == 0){ 769 if(dascase) 770 bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); 771 else 772 if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */ 773 bprint(i, "MOVW\tR%d", i->rs2); 774 else 775 bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); 776 }else{ 777 if(dascase) 778 bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13); 779 else 780 if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */ 781 bprint(i, "MOVW\t$%lux", i->simm13); 782 else if(i->op3==0 && i->rd && i->rs1==2){ 783 /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */ 784 bprint(i, "MOVW\t$"); 785 address(i); 786 } else 787 bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1); 788 } 789 if(i->rs1 != i->rd) 790 bprint(i, ", R%d", i->rd); 791 } 792 793 static void 794 cmp(Instr *i, char *m) 795 { 796 if(dascase || i->rd){ 797 add(i, m); 798 return; 799 } 800 if(i->i == 0) 801 bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2); 802 else 803 bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13); 804 } 805 806 static char *regtab[4] = { 807 "Y", 808 "PSR", 809 "WIM", 810 "TBR", 811 }; 812 813 static void 814 wr(Instr *i, char *m) /* page 82 */ 815 { 816 if(dascase){ 817 if(i->i == 0) 818 bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2); 819 else 820 bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13); 821 }else{ 822 if(i->i && i->simm13==0) 823 bprint(i, "MOVW\tR%d", i->rs1); 824 else if(i->i == 0) 825 bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1); 826 else 827 bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1); 828 } 829 bprint(i, ", %s", regtab[i->op3&3]); 830 } 831 832 static void 833 rd(Instr *i, char *m) /* page 103 */ 834 { 835 if(i->rs1==15 && i->rd==0){ 836 m = "stbar"; 837 if(!dascase) 838 m = "STBAR"; 839 bprint(i, "%s", m); 840 }else{ 841 if(!dascase) 842 m = "MOVW"; 843 bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd); 844 } 845 } 846 847 static void 848 jmpl(Instr *i, char *m) /* page 82 */ 849 { 850 if(i->i == 0){ 851 if(i->rd == 15) 852 bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1); 853 else 854 bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd); 855 }else{ 856 if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0) 857 bprint(i, "RETURN"); 858 else{ 859 bprint(i, "%X\t", m); 860 address(i); 861 bprint(i, ", R%d", i->rd); 862 } 863 } 864 } 865 866 static void 867 loadf(Instr *i, char *m) /* page 70 */ 868 { 869 if(!dascase){ 870 m = "FMOVD"; 871 if(i->op3 == 0x20) 872 m = "FMOVF"; 873 else if(i->op3 == 0x21) 874 m = "MOVW"; 875 } 876 if(i->i == 0) 877 bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2); 878 else{ 879 bprint(i, "%s\t", m); 880 address(i); 881 } 882 if(i->op3 == 0x21) 883 bprint(i, ", FSR"); 884 else 885 bprint(i, ", R%d", i->rd); 886 } 887 888 static 889 void storef(Instr *i, char *m) /* page 70 */ 890 { 891 if(!dascase){ 892 m = "FMOVD"; 893 if(i->op3 == 0x25 || i->op3 == 0x26) 894 m = "MOVW"; 895 else if(i->op3 == 0x20) 896 m = "FMOVF"; 897 } 898 bprint(i, "%s\t", m); 899 if(i->op3 == 0x25) 900 bprint(i, "FSR, "); 901 else if(i->op3 == 0x26) 902 bprint(i, "FQ, "); 903 else 904 bprint(i, "R%d, ", i->rd); 905 if(i->i == 0) 906 bprint(i, "(R%d+R%d)", i->rs1, i->rs2); 907 else 908 address(i); 909 } 910 911 static 912 void loadc(Instr *i, char *m) /* page 72 */ 913 { 914 if(i->i == 0) 915 bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd); 916 else{ 917 bprint(i, "%s\t", m); 918 address(i); 919 bprint(i, ", C%d", i->rd); 920 } 921 } 922 923 static 924 void loadcsr(Instr *i, char *m) /* page 72 */ 925 { 926 if(i->i == 0) 927 bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2); 928 else{ 929 bprint(i, "%s\t", m); 930 address(i); 931 bprint(i, ", CSR"); 932 } 933 } 934 935 static struct{ 936 int opf; 937 char *name; 938 } fptab1[] = { /* ignores rs1 */ 939 0xC4, "FITOS", /* page 109 */ 940 0xC8, "FITOD", 941 0xCC, "FITOX", 942 943 0xD1, "FSTOI", /* page 110 */ 944 0xD2, "FDTOI", 945 0xD3, "FXTOI", 946 947 0xC9, "FSTOD", /* page 111 */ 948 0xCD, "FSTOX", 949 0xC6, "FDTOS", 950 0xCE, "FDTOX", 951 0xC7, "FXTOS", 952 0xCB, "FXTOD", 953 954 0x01, "FMOVS", /* page 112 */ 955 0x05, "FNEGS", 956 0x09, "FABSS", 957 958 0x29, "FSQRTS", /* page 113 */ 959 0x2A, "FSQRTD", 960 0x2B, "FSQRTX", 961 962 0, 0, 963 }; 964 965 static struct{ 966 int opf; 967 char *name; 968 } fptab2[] = { /* uses rs1 */ 969 970 0x41, "FADDS", /* page 114 */ 971 0x42, "FADDD", 972 0x43, "FADDX", 973 0x45, "FSUBS", 974 0x46, "FSUBD", 975 0x47, "FSUBX", 976 977 0x49, "FMULS", /* page 115 */ 978 0x4A, "FMULD", 979 0x4B, "FMULX", 980 0x4D, "FDIVS", 981 0x4E, "FDIVD", 982 0x4F, "FDIVX", 983 984 0x51, "FCMPS", /* page 116 */ 985 0x52, "FCMPD", 986 0x53, "FCMPX", 987 0x55, "FCMPES", 988 0x56, "FCMPED", 989 0x57, "FCMPEX", 990 991 0, 0 992 }; 993 994 static void 995 fpop(Instr *i, char *m) /* page 108-116 */ 996 { 997 int j; 998 999 if(dascase==0 && i->size==2){ 1000 bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd); 1001 return; 1002 } 1003 for(j=0; fptab1[j].name; j++) 1004 if(fptab1[j].opf == i->opf){ 1005 bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd); 1006 return; 1007 } 1008 for(j=0; fptab2[j].name; j++) 1009 if(fptab2[j].opf == i->opf){ 1010 bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd); 1011 return; 1012 } 1013 bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd); 1014 } 1015 1016 static int 1017 sparcfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) 1018 { 1019 ulong w, r1, r2; 1020 char buf[8]; 1021 Instr i; 1022 1023 mymap = map; 1024 if (mkinstr(pc, &i) < 0) 1025 return -1; 1026 w = i.w0; 1027 switch(w & 0xC1C00000){ 1028 case 0x00800000: /* branch on int cond */ 1029 case 0x01800000: /* branch on fp cond */ 1030 case 0x01C00000: /* branch on copr cond */ 1031 foll[0] = pc+8; 1032 foll[1] = pc + (i.simmdisp22<<2); 1033 return 2; 1034 } 1035 1036 if((w&0xC0000000) == 0x40000000){ /* CALL */ 1037 foll[0] = pc + (i.disp30<<2); 1038 return 1; 1039 } 1040 1041 if((w&0xC1F80000) == 0x81C00000){ /* JMPL */ 1042 sprint(buf, "R%ld", (w>>14)&0xF); 1043 r1 = (*rget)(map, buf); 1044 if(w & 0x2000) /* JMPL R1+simm13 */ 1045 r2 = i.simm13; 1046 else{ /* JMPL R1+R2 */ 1047 sprint(buf, "R%ld", w&0xF); 1048 r2 = (*rget)(map, buf); 1049 } 1050 foll[0] = r1 + r2; 1051 return 1; 1052 } 1053 foll[0] = pc+i.size*4; 1054 return 1; 1055 } 1056