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