1 #include <lib9.h> 2 #include <bio.h> 3 #include "mach.h" 4 /* 5 * Mips-specific debugger interface 6 */ 7 8 static char *mipsexcep(Map*, Rgetter); 9 static int mipsfoll(Map*, uvlong, Rgetter, uvlong*); 10 static int mipsinst(Map*, uvlong, char, char*, int); 11 static int mipsdas(Map*, uvlong, char*, int); 12 static int mipsinstlen(Map*, uvlong); 13 14 /* 15 * Debugger interface 16 */ 17 Machdata mipsmach = 18 { 19 {0, 0, 0, 0xD}, /* break point */ 20 4, /* break point size */ 21 22 beswab, /* short to local byte order */ 23 beswal, /* long to local byte order */ 24 beswav, /* vlong to local byte order */ 25 risctrace, /* C traceback */ 26 riscframe, /* Frame finder */ 27 mipsexcep, /* print exception */ 28 0, /* breakpoint fixup */ 29 beieeesftos, /* single precision float printer */ 30 beieeedftos, /* double precisioin float printer */ 31 mipsfoll, /* following addresses */ 32 mipsinst, /* print instruction */ 33 mipsdas, /* dissembler */ 34 mipsinstlen, /* instruction size */ 35 }; 36 37 Machdata mipsmachle = 38 { 39 {0, 0, 0, 0xD}, /* break point */ 40 4, /* break point size */ 41 42 leswab, /* short to local byte order */ 43 leswal, /* long to local byte order */ 44 leswav, /* vlong to local byte order */ 45 risctrace, /* C traceback */ 46 riscframe, /* Frame finder */ 47 mipsexcep, /* print exception */ 48 0, /* breakpoint fixup */ 49 leieeesftos, /* single precision float printer */ 50 leieeedftos, /* double precisioin float printer */ 51 mipsfoll, /* following addresses */ 52 mipsinst, /* print instruction */ 53 mipsdas, /* dissembler */ 54 mipsinstlen, /* instruction size */ 55 }; 56 57 /* 58 * mips r4k little-endian 59 */ 60 Machdata mipsmach2le = 61 { 62 {0, 0, 0, 0xD}, /* break point */ 63 4, /* break point size */ 64 65 leswab, /* short to local byte order */ 66 leswal, /* long to local byte order */ 67 leswav, /* vlong to local byte order */ 68 risctrace, /* C traceback */ 69 riscframe, /* Frame finder */ 70 mipsexcep, /* print exception */ 71 0, /* breakpoint fixup */ 72 leieeesftos, /* single precision float printer */ 73 leieeedftos, /* double precisioin float printer */ 74 mipsfoll, /* following addresses */ 75 mipsinst, /* print instruction */ 76 mipsdas, /* dissembler */ 77 mipsinstlen, /* instruction size */ 78 }; 79 80 /* 81 * mips r4k big-endian 82 */ 83 Machdata mipsmach2be = 84 { 85 {0, 0, 0, 0xD}, /* break point */ 86 4, /* break point size */ 87 88 beswab, /* short to local byte order */ 89 beswal, /* long to local byte order */ 90 beswav, /* vlong to local byte order */ 91 risctrace, /* C traceback */ 92 riscframe, /* Frame finder */ 93 mipsexcep, /* print exception */ 94 0, /* breakpoint fixup */ 95 beieeesftos, /* single precision float printer */ 96 beieeedftos, /* double precisioin float printer */ 97 mipsfoll, /* following addresses */ 98 mipsinst, /* print instruction */ 99 mipsdas, /* dissembler */ 100 mipsinstlen, /* instruction size */ 101 }; 102 103 104 static char *excname[] = 105 { 106 "external interrupt", 107 "TLB modification", 108 "TLB miss (load or fetch)", 109 "TLB miss (store)", 110 "address error (load or fetch)", 111 "address error (store)", 112 "bus error (fetch)", 113 "bus error (data load or store)", 114 "system call", 115 "breakpoint", 116 "reserved instruction", 117 "coprocessor unusable", 118 "arithmetic overflow", 119 "undefined 13", 120 "undefined 14", 121 "system call", 122 /* the following is made up */ 123 "floating point exception" /* FPEXC */ 124 }; 125 126 static char* 127 mipsexcep(Map *map, Rgetter rget) 128 { 129 int e; 130 long c; 131 132 c = (*rget)(map, "CAUSE"); 133 if(c & 0x00002000) /* INTR3 */ 134 e = 16; /* Floating point exception */ 135 else 136 e = (c>>2)&0x0F; 137 return excname[e]; 138 } 139 140 /* mips disassembler and related functions */ 141 142 static char FRAMENAME[] = ".frame"; 143 144 typedef struct { 145 uvlong addr; 146 uchar op; /* bits 31-26 */ 147 uchar rs; /* bits 25-21 */ 148 uchar rt; /* bits 20-16 */ 149 uchar rd; /* bits 15-11 */ 150 uchar sa; /* bits 10-6 */ 151 uchar function; /* bits 5-0 */ 152 long immediate; /* bits 15-0 */ 153 ulong cofun; /* bits 24-0 */ 154 ulong target; /* bits 25-0 */ 155 long w0; 156 long w1; 157 int size; /* instruction size */ 158 char *curr; /* fill point in buffer */ 159 char *end; /* end of buffer */ 160 char *err; /* error message */ 161 } Instr; 162 163 static Map *mymap; 164 165 static int 166 decode(uvlong pc, Instr *i) 167 { 168 ulong w; 169 170 if (get4(mymap, pc, &w) < 0) { 171 werrstr("can't read instruction: %r"); 172 return -1; 173 } 174 175 i->addr = pc; 176 i->size = 1; 177 i->op = (w >> 26) & 0x3F; 178 i->rs = (w >> 21) & 0x1F; 179 i->rt = (w >> 16) & 0x1F; 180 i->rd = (w >> 11) & 0x1F; 181 i->sa = (w >> 6) & 0x1F; 182 i->function = w & 0x3F; 183 i->immediate = w & 0x0000FFFF; 184 if (i->immediate & 0x8000) 185 i->immediate |= ~0x0000FFFF; 186 i->cofun = w & 0x01FFFFFF; 187 i->target = w & 0x03FFFFFF; 188 i->w0 = w; 189 return 1; 190 } 191 192 static int 193 mkinstr(uvlong pc, Instr *i) 194 { 195 Instr x; 196 197 if (decode(pc, i) < 0) 198 return -1; 199 /* 200 * if it's a LUI followed by an ORI, 201 * it's an immediate load of a large constant. 202 * fix the LUI immediate in any case. 203 */ 204 if (i->op == 0x0F) { 205 if (decode(pc+4, &x) < 0) 206 return 0; 207 i->immediate <<= 16; 208 if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) { 209 i->immediate |= (x.immediate & 0xFFFF); 210 i->w1 = x.w0; 211 i->size++; 212 return 1; 213 } 214 } 215 /* 216 * if it's a LWC1 followed by another LWC1 217 * into an adjacent register, it's a load of 218 * a floating point double. 219 */ 220 else if (i->op == 0x31 && (i->rt & 0x01)) { 221 if (decode(pc+4, &x) < 0) 222 return 0; 223 if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) { 224 i->rt -= 1; 225 i->w1 = x.w0; 226 i->size++; 227 return 1; 228 } 229 } 230 /* 231 * similarly for double stores 232 */ 233 else if (i->op == 0x39 && (i->rt & 0x01)) { 234 if (decode(pc+4, &x) < 0) 235 return 0; 236 if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) { 237 i->rt -= 1; 238 i->w1 = x.w0; 239 i->size++; 240 } 241 } 242 return 1; 243 } 244 245 #pragma varargck argpos bprint 2 246 247 static void 248 bprint(Instr *i, char *fmt, ...) 249 { 250 va_list arg; 251 252 va_start(arg, fmt); 253 i->curr = vseprint(i->curr, i->end, fmt, arg); 254 va_end(arg); 255 } 256 257 typedef struct Opcode Opcode; 258 259 struct Opcode { 260 char *mnemonic; 261 void (*f)(Opcode *, Instr *); 262 char *ken; 263 }; 264 265 static void format(char *, Instr *, char *); 266 267 static void 268 branch(Opcode *o, Instr *i) 269 { 270 if (i->rs == 0 && i->rt == 0) 271 format("JMP", i, "%b"); 272 else if (i->rs == 0) 273 format(o->mnemonic, i, "R%t,%b"); 274 else if (i->rt < 2) 275 format(o->mnemonic, i, "R%s,%b"); 276 else 277 format(o->mnemonic, i, "R%s,R%t,%b"); 278 } 279 280 static void 281 addi(Opcode *o, Instr *i) 282 { 283 if (i->rs == i->rt) 284 format(o->mnemonic, i, "%i,R%t"); 285 else if (i->rs == 0) 286 format("MOVW", i, "%i,R%t"); 287 else if (i->rs == 30) { 288 bprint(i, "MOVW\t$"); 289 i->curr += symoff(i->curr, i->end-i->curr, 290 i->immediate+mach->sb, CANY); 291 bprint(i, "(SB),R%d", i->rt); 292 } 293 else 294 format(o->mnemonic, i, o->ken); 295 } 296 297 static void 298 andi(Opcode *o, Instr *i) 299 { 300 if (i->rs == i->rt) 301 format(o->mnemonic, i, "%i,R%t"); 302 else 303 format(o->mnemonic, i, o->ken); 304 } 305 306 static int 307 plocal(Instr *i, char *m, char r, int store) 308 { 309 int offset; 310 char *reg; 311 Symbol s; 312 313 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) 314 return 0; 315 if (s.value > i->immediate) { 316 if(!getauto(&s, s.value-i->immediate, CAUTO, &s)) 317 return 0; 318 reg = "(SP)"; 319 offset = i->immediate; 320 } else { 321 offset = i->immediate-s.value; 322 if (!getauto(&s, offset-4, CPARAM, &s)) 323 return 0; 324 reg = "(FP)"; 325 } 326 if (store) 327 bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg); 328 else 329 bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt); 330 return 1; 331 } 332 333 static void 334 lw(Opcode *o, Instr *i, char r) 335 { 336 char *m; 337 338 if (r == 'F') { 339 if (i->size == 2) 340 m = "MOVD"; 341 else 342 m = "MOVF"; 343 } 344 else 345 m = o->mnemonic; 346 if (i->rs == 29 && plocal(i, m, r, 0)) 347 return; 348 349 if (i->rs == 30 && mach->sb) { 350 bprint(i, "%s\t", m); 351 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); 352 bprint(i, "(SB),%c%d", r, i->rt); 353 return; 354 } 355 if (r == 'F') 356 format(m, i, "%l,F%t"); 357 else 358 format(m, i, o->ken); 359 } 360 361 static void 362 load(Opcode *o, Instr *i) 363 { 364 lw(o, i, 'R'); 365 } 366 367 static void 368 lwc1(Opcode *o, Instr *i) 369 { 370 lw(o, i, 'F'); 371 } 372 373 static void 374 sw(Opcode *o, Instr *i, char r) 375 { 376 char *m; 377 378 if (r == 'F') { 379 if (i->size == 2) 380 m = "MOVD"; 381 else 382 m = "MOVF"; 383 } 384 else 385 m = o->mnemonic; 386 if (i->rs == 29 && plocal(i, m, r, 1)) 387 return; 388 389 if (i->rs == 30 && mach->sb) { 390 bprint(i, "%s\t%c%d,", m, r, i->rt); 391 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); 392 bprint(i, "(SB)"); 393 return; 394 } 395 if (r == 'F') 396 format(m, i, "F%t,%l"); 397 else 398 format(m, i, o->ken); 399 } 400 401 static void 402 store(Opcode *o, Instr *i) 403 { 404 sw(o, i, 'R'); 405 } 406 407 static void 408 swc1(Opcode *o, Instr *i) 409 { 410 sw(o, i, 'F'); 411 } 412 413 static void 414 sll(Opcode *o, Instr *i) 415 { 416 if (i->w0 == 0) 417 bprint(i, "NOOP"); 418 else if (i->rd == i->rt) 419 format(o->mnemonic, i, "$%a,R%d"); 420 else 421 format(o->mnemonic, i, o->ken); 422 } 423 424 static void 425 sl32(Opcode *o, Instr *i) 426 { 427 i->sa += 32; 428 if (i->rd == i->rt) 429 format(o->mnemonic, i, "$%a,R%d"); 430 else 431 format(o->mnemonic, i, o->ken); 432 } 433 434 static void 435 sllv(Opcode *o, Instr *i) 436 { 437 if (i->rd == i->rt) 438 format(o->mnemonic, i, "R%s,R%d"); 439 else 440 format(o->mnemonic, i, o->ken); 441 } 442 443 static void 444 jal(Opcode *o, Instr *i) 445 { 446 if (i->rd == 31) 447 format("JAL", i, "(R%s)"); 448 else 449 format(o->mnemonic, i, o->ken); 450 } 451 452 static void 453 add(Opcode *o, Instr *i) 454 { 455 if (i->rd == i->rs) 456 format(o->mnemonic, i, "R%t,R%d"); 457 else if (i->rd == i->rt) 458 format(o->mnemonic, i, "R%s,R%d"); 459 else 460 format(o->mnemonic, i, o->ken); 461 } 462 463 static void 464 sub(Opcode *o, Instr *i) 465 { 466 if (i->rd == i->rs) 467 format(o->mnemonic, i, "R%t,R%d"); 468 else 469 format(o->mnemonic, i, o->ken); 470 } 471 472 static void 473 or(Opcode *o, Instr *i) 474 { 475 if (i->rs == 0 && i->rt == 0) 476 format("MOVW", i, "$0,R%d"); 477 else if (i->rs == 0) 478 format("MOVW", i, "R%t,R%d"); 479 else if (i->rt == 0) 480 format("MOVW", i, "R%s,R%d"); 481 else 482 add(o, i); 483 } 484 485 static void 486 nor(Opcode *o, Instr *i) 487 { 488 if (i->rs == 0 && i->rt == 0 && i->rd == 0) 489 format("NOP", i, 0); 490 else 491 add(o, i); 492 } 493 494 static char mipscoload[] = "r%t,%l"; 495 static char mipsload[] = "%l,R%t"; 496 static char mipsstore[] = "R%t,%l"; 497 static char mipsalui[] = "%i,R%s,R%t"; 498 static char mipsalu3op[] = "R%t,R%s,R%d"; 499 static char mipsrtrs[] = "R%t,R%s"; 500 static char mipscorsrt[] = "r%s,r%t"; 501 static char mipscorsi[] = "r%s,%i"; 502 static char mipscoxxx[] = "%w"; 503 static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */ 504 static char mipsfp3[] = "F%t,F%d,F%a"; 505 static char mipscofp2[] = "f%a,f%d"; /* fd,fs */ 506 static char mipsfp2[] = "F%d,F%a"; 507 static char mipscofpc[] = "f%d,f%t"; /* fs,ft */ 508 static char mipsfpc[] = "F%t,F%d"; 509 510 static Opcode opcodes[64] = { 511 0, 0, 0, 512 0, 0, 0, 513 "JMP", 0, "%j", 514 "JAL", 0, "%j", 515 "BEQ", branch, 0, 516 "BNE", branch, 0, 517 "BLEZ", branch, 0, 518 "BGTZ", branch, 0, 519 "ADD", addi, mipsalui, 520 "ADDU", addi, mipsalui, 521 "SGT", 0, mipsalui, 522 "SGTU", 0, mipsalui, 523 "AND", andi, mipsalui, 524 "OR", andi, mipsalui, 525 "XOR", andi, mipsalui, 526 "MOVW", 0, "$%u,R%t", 527 "cop0", 0, 0, 528 "cop1", 0, 0, 529 "cop2", 0, 0, 530 "cop3", 0, 0, 531 "BEQL", branch, 0, 532 "BNEL", branch, 0, 533 "BLEZL", branch, 0, 534 "BGTZL", branch, 0, 535 "instr18", 0, mipscoxxx, 536 "instr19", 0, mipscoxxx, 537 "MOVVL", load, mipsload, 538 "MOVVR", load, mipsload, 539 "instr1C", 0, mipscoxxx, 540 "instr1D", 0, mipscoxxx, 541 "instr1E", 0, mipscoxxx, 542 "instr1F", 0, mipscoxxx, 543 "MOVB", load, mipsload, 544 "MOVH", load, mipsload, 545 "lwl", 0, mipscoload, 546 "MOVW", load, mipsload, 547 "MOVBU", load, mipsload, 548 "MOVHU", load, mipsload, 549 "lwr", 0, mipscoload, 550 "instr27", 0, mipscoxxx, 551 "MOVB", store, mipsstore, 552 "MOVH", store, mipsstore, 553 "swl", 0, mipscoload, 554 "MOVW", store, mipsstore, 555 "MOVVL", store, mipsstore, 556 "MOVVR", store, mipsstore, 557 "swr", 0, mipscoload, 558 "CACHE", 0, "%C,%l", 559 "ll", 0, mipscoload, 560 "MOVW", lwc1, mipscoload, 561 "lwc2", 0, mipscoload, 562 "lwc3", 0, mipscoload, 563 "instr34", 0, mipscoxxx, 564 "ldc1", 0, mipscoload, 565 "ldc2", 0, mipscoload, 566 "MOVV", load, mipsload, 567 "sc", 0, mipscoload, 568 "swc1", swc1, mipscoload, 569 "swc2", 0, mipscoload, 570 "swc3", 0, mipscoload, 571 "instr3C", 0, mipscoxxx, 572 "sdc1", 0, mipscoload, 573 "sdc2", 0, mipscoload, 574 "MOVV", store, mipsstore, 575 }; 576 577 static Opcode sopcodes[64] = { 578 "SLL", sll, "$%a,R%t,R%d", 579 "special01", 0, mipscoxxx, 580 "SRL", sll, "$%a,R%t,R%d", 581 "SRA", sll, "$%a,R%t,R%d", 582 "SLL", sllv, "R%s,R%t,R%d", 583 "special05", 0, mipscoxxx, 584 "SRL", sllv, "R%s,R%t,R%d", 585 "SRA", sllv, "R%s,R%t,R%d", 586 "JMP", 0, "(R%s)", 587 "jal", jal, "r%d,r%s", 588 "special0A", 0, mipscoxxx, 589 "special0B", 0, mipscoxxx, 590 "SYSCALL", 0, 0, 591 "BREAK", 0, 0, 592 "special0E", 0, mipscoxxx, 593 "SYNC", 0, 0, 594 "MOVW", 0, "HI,R%d", 595 "MOVW", 0, "R%s,HI", 596 "MOVW", 0, "LO,R%d", 597 "MOVW", 0, "R%s,LO", 598 "SLLV", sllv, "R%s,R%t,R%d", 599 "special15", 0, mipscoxxx, 600 "SRLV", sllv, "R%s,R%t,R%d", 601 "SRAV", sllv, "R%s,R%t,R%d", 602 "MUL", 0, mipsrtrs, 603 "MULU", 0, mipsrtrs, 604 "DIV", 0, mipsrtrs, 605 "DIVU", 0, mipsrtrs, 606 "special1C", 0, mipscoxxx, 607 "special1D", 0, mipscoxxx, 608 "DDIV", 0, "R%s,R%t", 609 "special1F", 0, mipscoxxx, 610 "ADD", add, mipsalu3op, 611 "ADDU", add, mipsalu3op, 612 "SUB", sub, mipsalu3op, 613 "SUBU", sub, mipsalu3op, 614 "AND", add, mipsalu3op, 615 "OR", or, mipsalu3op, 616 "XOR", add, mipsalu3op, 617 "NOR", nor, mipsalu3op, 618 "special28", 0, mipscoxxx, 619 "special29", 0, mipscoxxx, 620 "SGT", 0, mipsalu3op, 621 "SGTU", 0, mipsalu3op, 622 "special2C", 0, mipscoxxx, 623 "special2D", 0, mipscoxxx, 624 "special2E", 0, mipscoxxx, 625 "DSUBU", 0, "R%s,R%t,R%d", 626 "tge", 0, mipscorsrt, 627 "tgeu", 0, mipscorsrt, 628 "tlt", 0, mipscorsrt, 629 "tltu", 0, mipscorsrt, 630 "teq", 0, mipscorsrt, 631 "special35", 0, mipscoxxx, 632 "tne", 0, mipscorsrt, 633 "special37", 0, mipscoxxx, 634 "SLLV", sll, "$%a,R%t,R%d", 635 "special39", 0, mipscoxxx, 636 "SRLV", sll, "$%a,R%t,R%d", 637 "SRAV", sll, "$%a,R%t,R%d", 638 "SLLV", sl32, "$%a,R%t,R%d", 639 "special3D", 0, mipscoxxx, 640 "SRLV", sl32, "$%a,R%t,R%d", 641 "SRAV", sl32, "$%a,R%t,R%d", 642 }; 643 644 static Opcode ropcodes[32] = { 645 "BLTZ", branch, 0, 646 "BGEZ", branch, 0, 647 "BLTZL", branch, 0, 648 "BGEZL", branch, 0, 649 "regimm04", 0, mipscoxxx, 650 "regimm05", 0, mipscoxxx, 651 "regimm06", 0, mipscoxxx, 652 "regimm07", 0, mipscoxxx, 653 "tgei", 0, mipscorsi, 654 "tgeiu", 0, mipscorsi, 655 "tlti", 0, mipscorsi, 656 "tltiu", 0, mipscorsi, 657 "teqi", 0, mipscorsi, 658 "regimm0D", 0, mipscoxxx, 659 "tnei", 0, mipscorsi, 660 "regimm0F", 0, mipscoxxx, 661 "BLTZAL", branch, 0, 662 "BGEZAL", branch, 0, 663 "BLTZALL", branch, 0, 664 "BGEZALL", branch, 0, 665 "regimm14", 0, mipscoxxx, 666 "regimm15", 0, mipscoxxx, 667 "regimm16", 0, mipscoxxx, 668 "regimm17", 0, mipscoxxx, 669 "regimm18", 0, mipscoxxx, 670 "regimm19", 0, mipscoxxx, 671 "regimm1A", 0, mipscoxxx, 672 "regimm1B", 0, mipscoxxx, 673 "regimm1C", 0, mipscoxxx, 674 "regimm1D", 0, mipscoxxx, 675 "regimm1E", 0, mipscoxxx, 676 "regimm1F", 0, mipscoxxx, 677 }; 678 679 static Opcode fopcodes[64] = { 680 "ADD%f", 0, mipsfp3, 681 "SUB%f", 0, mipsfp3, 682 "MUL%f", 0, mipsfp3, 683 "DIV%f", 0, mipsfp3, 684 "sqrt.%f", 0, mipscofp2, 685 "ABS%f", 0, mipsfp2, 686 "MOV%f", 0, mipsfp2, 687 "NEG%f", 0, mipsfp2, 688 "finstr08", 0, mipscoxxx, 689 "finstr09", 0, mipscoxxx, 690 "finstr0A", 0, mipscoxxx, 691 "finstr0B", 0, mipscoxxx, 692 "round.w.%f", 0, mipscofp2, 693 "trunc.w%f", 0, mipscofp2, 694 "ceil.w%f", 0, mipscofp2, 695 "floor.w%f", 0, mipscofp2, 696 "finstr10", 0, mipscoxxx, 697 "finstr11", 0, mipscoxxx, 698 "finstr12", 0, mipscoxxx, 699 "finstr13", 0, mipscoxxx, 700 "finstr14", 0, mipscoxxx, 701 "finstr15", 0, mipscoxxx, 702 "finstr16", 0, mipscoxxx, 703 "finstr17", 0, mipscoxxx, 704 "finstr18", 0, mipscoxxx, 705 "finstr19", 0, mipscoxxx, 706 "finstr1A", 0, mipscoxxx, 707 "finstr1B", 0, mipscoxxx, 708 "finstr1C", 0, mipscoxxx, 709 "finstr1D", 0, mipscoxxx, 710 "finstr1E", 0, mipscoxxx, 711 "finstr1F", 0, mipscoxxx, 712 "cvt.s.%f", 0, mipscofp2, 713 "cvt.d.%f", 0, mipscofp2, 714 "cvt.e.%f", 0, mipscofp2, 715 "cvt.q.%f", 0, mipscofp2, 716 "cvt.w.%f", 0, mipscofp2, 717 "finstr25", 0, mipscoxxx, 718 "finstr26", 0, mipscoxxx, 719 "finstr27", 0, mipscoxxx, 720 "finstr28", 0, mipscoxxx, 721 "finstr29", 0, mipscoxxx, 722 "finstr2A", 0, mipscoxxx, 723 "finstr2B", 0, mipscoxxx, 724 "finstr2C", 0, mipscoxxx, 725 "finstr2D", 0, mipscoxxx, 726 "finstr2E", 0, mipscoxxx, 727 "finstr2F", 0, mipscoxxx, 728 "c.f.%f", 0, mipscofpc, 729 "c.un.%f", 0, mipscofpc, 730 "CMPEQ%f", 0, mipsfpc, 731 "c.ueq.%f", 0, mipscofpc, 732 "c.olt.%f", 0, mipscofpc, 733 "c.ult.%f", 0, mipscofpc, 734 "c.ole.%f", 0, mipscofpc, 735 "c.ule.%f", 0, mipscofpc, 736 "c.sf.%f", 0, mipscofpc, 737 "c.ngle.%f", 0, mipscofpc, 738 "c.seq.%f", 0, mipscofpc, 739 "c.ngl.%f", 0, mipscofpc, 740 "CMPGT%f", 0, mipsfpc, 741 "c.nge.%f", 0, mipscofpc, 742 "CMPGE%f", 0, mipsfpc, 743 "c.ngt.%f", 0, mipscofpc, 744 }; 745 746 static char *cop0regs[32] = { 747 "INDEX", "RANDOM", "TLBPHYS", "EntryLo0", 748 "CONTEXT", "PageMask", "Wired", "Error", 749 "BADVADDR", "Count", "TLBVIRT", "Compare", 750 "STATUS", "CAUSE", "EPC", "PRID", 751 "Config", "LLadr", "WatchLo", "WatchHi", 752 "20", "21", "22", "23", 753 "24", "25", "26", "CacheErr", 754 "TagLo", "TagHi", "ErrorEPC", "31" 755 }; 756 757 static char fsub[16] = { 758 'F', 'D', 'e', 'q', 'W', '?', '?', '?', 759 '?', '?', '?', '?', '?', '?', '?', '?' 760 }; 761 762 static char *cacheps[] = { 763 "I", "D", "SI", "SD" 764 }; 765 766 static char *cacheop[] = { 767 "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV" 768 }; 769 770 static void 771 format(char *mnemonic, Instr *i, char *f) 772 { 773 if (mnemonic) 774 format(0, i, mnemonic); 775 if (f == 0) 776 return; 777 if (mnemonic) 778 if (i->curr < i->end) 779 *i->curr++ = '\t'; 780 for ( ; *f && i->curr < i->end; f++) { 781 if (*f != '%') { 782 *i->curr++ = *f; 783 continue; 784 } 785 switch (*++f) { 786 787 case 's': 788 bprint(i, "%d", i->rs); 789 break; 790 791 case 't': 792 bprint(i, "%d", i->rt); 793 break; 794 795 case 'd': 796 bprint(i, "%d", i->rd); 797 break; 798 799 case 'a': 800 bprint(i, "%d", i->sa); 801 break; 802 803 case 'l': 804 bprint(i, "%lx(R%d)",i->immediate, i->rs); 805 break; 806 807 case 'i': 808 bprint(i, "$%lx", i->immediate); 809 break; 810 811 case 'u': 812 i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); 813 bprint(i, "(SB)"); 814 break; 815 816 case 'j': 817 i->curr += symoff(i->curr, i->end-i->curr, 818 (i->target<<2)|(i->addr & 0xF0000000), CANY); 819 bprint(i, "(SB)"); 820 break; 821 822 case 'b': 823 i->curr += symoff(i->curr, i->end-i->curr, 824 (i->immediate<<2)+i->addr+4, CANY); 825 break; 826 827 case 'c': 828 bprint(i, "$%lx", i->cofun); 829 break; 830 831 case 'w': 832 bprint(i, "[%lux]", i->w0); 833 break; 834 835 case 'm': 836 bprint(i, "M(%s)", cop0regs[i->rd]); 837 break; 838 839 case 'f': 840 *i->curr++ = fsub[i->rs & 0x0F]; 841 break; 842 843 case 'C': 844 bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]); 845 break; 846 847 case '\0': 848 *i->curr++ = '%'; 849 return; 850 851 default: 852 bprint(i, "%%%c", *f); 853 break; 854 } 855 } 856 *i->curr = 0; 857 } 858 859 static void 860 copz(int cop, Instr *i) 861 { 862 char *f, *m, buf[16]; 863 864 m = buf; 865 f = "%t,%d"; 866 switch (i->rs) { 867 868 case 0: 869 sprint(buf, "mfc%d", cop); 870 break; 871 872 case 2: 873 sprint(buf, "cfc%d", cop); 874 break; 875 876 case 4: 877 sprint(buf, "mtc%d", cop); 878 break; 879 880 case 6: 881 sprint(buf, "ctc%d", cop); 882 break; 883 884 case 8: 885 f = "%b"; 886 switch (i->rt) { 887 888 case 0: 889 sprint(buf, "bc%df", cop); 890 break; 891 892 case 1: 893 sprint(buf, "bc%dt", cop); 894 break; 895 896 case 2: 897 sprint(buf, "bc%dfl", cop); 898 break; 899 900 case 3: 901 sprint(buf, "bc%dtl", cop); 902 break; 903 904 default: 905 sprint(buf, "cop%d", cop); 906 f = mipscoxxx; 907 break; 908 } 909 break; 910 911 default: 912 sprint(buf, "cop%d", cop); 913 if (i->rs & 0x10) 914 f = "function %c"; 915 else 916 f = mipscoxxx; 917 break; 918 } 919 format(m, i, f); 920 } 921 922 static void 923 cop0(Instr *i) 924 { 925 char *m = 0; 926 927 if (i->rs < 8) { 928 switch (i->rs) { 929 930 case 0: 931 case 1: 932 format("MOVW", i, "%m,R%t"); 933 return; 934 935 case 4: 936 case 5: 937 format("MOVW", i, "R%t,%m"); 938 return; 939 } 940 } 941 else if (i->rs >= 0x10) { 942 switch (i->cofun) { 943 944 case 1: 945 m = "TLBR"; 946 break; 947 948 case 2: 949 m = "TLBWI"; 950 break; 951 952 case 6: 953 m = "TLBWR"; 954 break; 955 956 case 8: 957 m = "TLBP"; 958 break; 959 960 case 16: 961 m = "RFE"; 962 break; 963 964 case 32: 965 m = "ERET"; 966 break; 967 } 968 if (m) { 969 format(m, i, 0); 970 return; 971 } 972 } 973 copz(0, i); 974 } 975 976 static void 977 cop1(Instr *i) 978 { 979 char *m = "MOVW"; 980 981 switch (i->rs) { 982 983 case 0: 984 format(m, i, "F%d,R%t"); 985 return; 986 987 case 2: 988 format(m, i, "FCR%d,R%t"); 989 return; 990 991 case 4: 992 format(m, i, "R%t,F%d"); 993 return; 994 995 case 6: 996 format(m, i, "R%t,FCR%d"); 997 return; 998 999 case 8: 1000 switch (i->rt) { 1001 1002 case 0: 1003 format("BFPF", i, "%b"); 1004 return; 1005 1006 case 1: 1007 format("BFPT", i, "%b"); 1008 return; 1009 } 1010 break; 1011 } 1012 copz(1, i); 1013 } 1014 1015 static int 1016 printins(Map *map, uvlong pc, char *buf, int n) 1017 { 1018 Instr i; 1019 Opcode *o; 1020 uchar op; 1021 1022 i.curr = buf; 1023 i.end = buf+n-1; 1024 mymap = map; 1025 if (mkinstr(pc, &i) < 0) 1026 return -1; 1027 switch (i.op) { 1028 1029 case 0x00: /* SPECIAL */ 1030 o = sopcodes; 1031 op = i.function; 1032 break; 1033 1034 case 0x01: /* REGIMM */ 1035 o = ropcodes; 1036 op = i.rt; 1037 break; 1038 1039 case 0x10: /* COP0 */ 1040 cop0(&i); 1041 return i.size*4; 1042 1043 case 0x11: /* COP1 */ 1044 if (i.rs & 0x10) { 1045 o = fopcodes; 1046 op = i.function; 1047 break; 1048 } 1049 cop1(&i); 1050 return i.size*4; 1051 1052 case 0x12: /* COP2 */ 1053 case 0x13: /* COP3 */ 1054 copz(i.op-0x10, &i); 1055 return i.size*4; 1056 1057 default: 1058 o = opcodes; 1059 op = i.op; 1060 break; 1061 } 1062 if (o[op].f) 1063 (*o[op].f)(&o[op], &i); 1064 else 1065 format(o[op].mnemonic, &i, o[op].ken); 1066 return i.size*4; 1067 } 1068 1069 extern int _mipscoinst(Map *, uvlong, char*, int); 1070 1071 /* modifier 'I' toggles the default disassembler type */ 1072 static int 1073 mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n) 1074 { 1075 if ((asstype == AMIPSCO && modifier == 'i') 1076 || (asstype == AMIPS && modifier == 'I')) 1077 return _mipscoinst(map, pc, buf, n); 1078 else 1079 return printins(map, pc, buf, n); 1080 } 1081 1082 static int 1083 mipsdas(Map *map, uvlong pc, char *buf, int n) 1084 { 1085 Instr i; 1086 1087 i.curr = buf; 1088 i.end = buf+n; 1089 mymap = map; 1090 if (mkinstr(pc, &i) < 0) 1091 return -1; 1092 if (i.end-i.curr > 8) 1093 i.curr = _hexify(buf, i.w0, 7); 1094 if (i.size == 2 && i.end-i.curr > 9) { 1095 *i.curr++ = ' '; 1096 i.curr = _hexify(i.curr, i.w1, 7); 1097 } 1098 *i.curr = 0; 1099 return i.size*4; 1100 } 1101 1102 static int 1103 mipsinstlen(Map *map, uvlong pc) 1104 { 1105 Instr i; 1106 1107 mymap = map; 1108 if (mkinstr(pc, &i) < 0) 1109 return -1; 1110 return i.size*4; 1111 } 1112 1113 static int 1114 mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) 1115 { 1116 ulong w, l; 1117 char buf[8]; 1118 Instr i; 1119 1120 mymap = map; 1121 if (mkinstr(pc, &i) < 0) 1122 return -1; 1123 w = i.w0; 1124 if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */ 1125 Conditional: 1126 foll[0] = pc+8; 1127 l = ((w&0xFFFF)<<2); 1128 if(w & 0x8000) 1129 l |= 0xFFFC0000; 1130 foll[1] = pc+4 + l; 1131 return 2; 1132 } 1133 1134 l = (w&0xFC000000)>>26; 1135 switch(l){ 1136 case 0: /* SPECIAL */ 1137 if((w&0x3E) == 0x08){ /* JR, JALR */ 1138 sprint(buf, "R%ld", (w>>21)&0x1F); 1139 foll[0] = (*rget)(map, buf); 1140 return 1; 1141 } 1142 foll[0] = pc+i.size*4; 1143 return 1; 1144 case 0x30: /* Load-Linked followed by NOP, STC */ 1145 foll[0] = pc+12; 1146 return 1; 1147 case 1: /* BCOND */ 1148 case 4: /* BEQ */ 1149 case 20: /* BEQL */ 1150 case 5: /* BNE */ 1151 case 21: /* BNEL */ 1152 case 6: /* BLEZ */ 1153 case 22: /* BLEZL */ 1154 case 7: /* BGTZ */ 1155 case 23: /* BGTZL */ 1156 goto Conditional; 1157 case 2: /* J */ 1158 case 3: /* JAL */ 1159 foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2); 1160 return 1; 1161 } 1162 1163 foll[0] = pc+i.size*4; 1164 return 1; 1165 } 1166