1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 6 /* mips native disassembler */ 7 8 typedef struct { 9 long addr; /* pc of instr */ 10 uchar op; /* bits 31-26 */ 11 uchar rs; /* bits 25-21 */ 12 uchar rt; /* bits 20-16 */ 13 uchar rd; /* bits 15-11 */ 14 uchar sa; /* bits 10-6 */ 15 uchar function; /* bits 5-0 */ 16 long immediate; /* bits 15-0 */ 17 ulong cofun; /* bits 24-0 */ 18 ulong target; /* bits 25-0 */ 19 long w0; 20 char *curr; /* current fill point */ 21 char *end; /* end of buffer */ 22 char *err; 23 } Instr; 24 25 typedef struct { 26 char *mnemonic; 27 char *mipsco; 28 } Opcode; 29 30 static char mipscoload[] = "r%t,%l"; 31 static char mipscoalui[] = "r%t,r%s,%i"; 32 static char mipscoalu3op[] = "r%d,r%s,r%t"; 33 static char mipscoboc[] = "r%s,r%t,%b"; 34 static char mipscoboc0[] = "r%s,%b"; 35 static char mipscorsrt[] = "r%s,r%t"; 36 static char mipscorsi[] = "r%s,%i"; 37 static char mipscoxxx[] = "%w"; 38 static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */ 39 static char mipscofp2[] = "f%a,f%d"; /* fd,fs */ 40 static char mipscofpc[] = "f%d,f%t"; /* fs,ft */ 41 42 static Opcode opcodes[64] = { 43 0, 0, 44 0, 0, 45 "j", "%j", 46 "jal", "%j", 47 "beq", mipscoboc, 48 "bne", mipscoboc, 49 "blez", mipscoboc0, 50 "bgtz", mipscoboc0, 51 "addi", mipscoalui, 52 "addiu", mipscoalui, 53 "slti", mipscoalui, 54 "sltiu", mipscoalui, 55 "andi", mipscoalui, 56 "ori", mipscoalui, 57 "xori", mipscoalui, 58 "lui", "r%t,%u", 59 "cop0", 0, 60 "cop1", 0, 61 "cop2", 0, 62 "cop3", 0, 63 "beql", mipscoboc, 64 "bnel", mipscoboc, 65 "blezl", mipscoboc0, 66 "bgtzl", mipscoboc0, 67 "instr18", mipscoxxx, 68 "instr19", mipscoxxx, 69 "instr1A", mipscoxxx, 70 "instr1B", mipscoxxx, 71 "instr1C", mipscoxxx, 72 "instr1D", mipscoxxx, 73 "instr1E", mipscoxxx, 74 "instr1F", mipscoxxx, 75 "lb", mipscoload, 76 "lh", mipscoload, 77 "lwl", mipscoload, 78 "lw", mipscoload, 79 "lbu", mipscoload, 80 "lhu", mipscoload, 81 "lwr", mipscoload, 82 "instr27", mipscoxxx, 83 "sb", mipscoload, 84 "sh", mipscoload, 85 "swl", mipscoload, 86 "sw", mipscoload, 87 "instr2C", mipscoxxx, 88 "instr2D", mipscoxxx, 89 "swr", mipscoload, 90 "cache", "", 91 "ll", mipscoload, 92 "lwc1", mipscoload, 93 "lwc2", mipscoload, 94 "lwc3", mipscoload, 95 "instr34", mipscoxxx, 96 "ld", mipscoload, 97 "ld", mipscoload, 98 "ld", mipscoload, 99 "sc", mipscoload, 100 "swc1", mipscoload, 101 "swc2", mipscoload, 102 "swc3", mipscoload, 103 "instr3C", mipscoxxx, 104 "sd", mipscoload, 105 "sd", mipscoload, 106 "sd", mipscoload, 107 }; 108 109 static Opcode sopcodes[64] = { 110 "sll", "r%d,r%t,$%a", 111 "special01", mipscoxxx, 112 "srl", "r%d,r%t,$%a", 113 "sra", "r%d,r%t,$%a", 114 "sllv", "r%d,r%t,R%s", 115 "special05", mipscoxxx, 116 "srlv", "r%d,r%t,r%s", 117 "srav", "r%d,r%t,r%s", 118 "jr", "r%s", 119 "jalr", "r%d,r%s", 120 "special0A", mipscoxxx, 121 "special0B", mipscoxxx, 122 "syscall", "", 123 "break", "", 124 "special0E", mipscoxxx, 125 "sync", "", 126 "mfhi", "r%d", 127 "mthi", "r%s", 128 "mflo", "r%d", 129 "mtlo", "r%s", 130 "special14", mipscoxxx, 131 "special15", mipscoxxx, 132 "special16", mipscoxxx, 133 "special17", mipscoxxx, 134 "mult", mipscorsrt, 135 "multu", mipscorsrt, 136 "div", mipscorsrt, 137 "divu", mipscorsrt, 138 "special1C", mipscoxxx, 139 "special1D", mipscoxxx, 140 "special1E", mipscoxxx, 141 "special1F", mipscoxxx, 142 "add", mipscoalu3op, 143 "addu", mipscoalu3op, 144 "sub", mipscoalu3op, 145 "subu", mipscoalu3op, 146 "and", mipscoalu3op, 147 "or", mipscoalu3op, 148 "xor", mipscoalu3op, 149 "nor", mipscoalu3op, 150 "special28", mipscoxxx, 151 "special29", mipscoxxx, 152 "slt", mipscoalu3op, 153 "sltu", mipscoalu3op, 154 "special2C", mipscoxxx, 155 "special2D", mipscoxxx, 156 "special2E", mipscoxxx, 157 "special2F", mipscoxxx, 158 "tge", mipscorsrt, 159 "tgeu", mipscorsrt, 160 "tlt", mipscorsrt, 161 "tltu", mipscorsrt, 162 "teq", mipscorsrt, 163 "special35", mipscoxxx, 164 "tne", mipscorsrt, 165 "special37", mipscoxxx, 166 "special38", mipscoxxx, 167 "special39", mipscoxxx, 168 "special3A", mipscoxxx, 169 "special3B", mipscoxxx, 170 "special3C", mipscoxxx, 171 "special3D", mipscoxxx, 172 "special3E", mipscoxxx, 173 "special3F", mipscoxxx, 174 }; 175 176 static Opcode ropcodes[32] = { 177 "bltz", mipscoboc0, 178 "bgez", mipscoboc0, 179 "bltzl", mipscoboc0, 180 "bgezl", mipscoboc0, 181 "regimm04", mipscoxxx, 182 "regimm05", mipscoxxx, 183 "regimm06", mipscoxxx, 184 "regimm07", mipscoxxx, 185 "tgei", mipscorsi, 186 "tgeiu", mipscorsi, 187 "tlti", mipscorsi, 188 "tltiu", mipscorsi, 189 "teqi", mipscorsi, 190 "regimm0D", mipscoxxx, 191 "tnei", mipscorsi, 192 "regimm0F", mipscoxxx, 193 "bltzal", mipscoboc0, 194 "bgezal", mipscoboc0, 195 "bltzall", mipscoboc0, 196 "bgezall", mipscoboc0, 197 "regimm14", mipscoxxx, 198 "regimm15", mipscoxxx, 199 "regimm16", mipscoxxx, 200 "regimm17", mipscoxxx, 201 "regimm18", mipscoxxx, 202 "regimm19", mipscoxxx, 203 "regimm1A", mipscoxxx, 204 "regimm1B", mipscoxxx, 205 "regimm1C", mipscoxxx, 206 "regimm1D", mipscoxxx, 207 "regimm1E", mipscoxxx, 208 "regimm1F", mipscoxxx, 209 }; 210 211 static Opcode fopcodes[64] = { 212 "add.%f", mipscofp3, 213 "sub.%f", mipscofp3, 214 "mul.%f", mipscofp3, 215 "div.%f", mipscofp3, 216 "sqrt.%f", mipscofp2, 217 "abs.%f", mipscofp2, 218 "mov.%f", mipscofp2, 219 "neg.%f", mipscofp2, 220 "finstr08", mipscoxxx, 221 "finstr09", mipscoxxx, 222 "finstr0A", mipscoxxx, 223 "finstr0B", mipscoxxx, 224 "round.w.%f", mipscofp2, 225 "trunc.w%f", mipscofp2, 226 "ceil.w%f", mipscofp2, 227 "floor.w%f", mipscofp2, 228 "finstr10", mipscoxxx, 229 "finstr11", mipscoxxx, 230 "finstr12", mipscoxxx, 231 "finstr13", mipscoxxx, 232 "finstr14", mipscoxxx, 233 "finstr15", mipscoxxx, 234 "finstr16", mipscoxxx, 235 "finstr17", mipscoxxx, 236 "finstr18", mipscoxxx, 237 "finstr19", mipscoxxx, 238 "finstr1A", mipscoxxx, 239 "finstr1B", mipscoxxx, 240 "finstr1C", mipscoxxx, 241 "finstr1D", mipscoxxx, 242 "finstr1E", mipscoxxx, 243 "finstr1F", mipscoxxx, 244 "cvt.s.%f", mipscofp2, 245 "cvt.d.%f", mipscofp2, 246 "cvt.e.%f", mipscofp2, 247 "cvt.q.%f", mipscofp2, 248 "cvt.w.%f", mipscofp2, 249 "finstr25", mipscoxxx, 250 "finstr26", mipscoxxx, 251 "finstr27", mipscoxxx, 252 "finstr28", mipscoxxx, 253 "finstr29", mipscoxxx, 254 "finstr2A", mipscoxxx, 255 "finstr2B", mipscoxxx, 256 "finstr2C", mipscoxxx, 257 "finstr2D", mipscoxxx, 258 "finstr2E", mipscoxxx, 259 "finstr2F", mipscoxxx, 260 "c.f.%f", mipscofpc, 261 "c.un.%f", mipscofpc, 262 "c.eq.%f", mipscofpc, 263 "c.ueq.%f", mipscofpc, 264 "c.olt.%f", mipscofpc, 265 "c.ult.%f", mipscofpc, 266 "c.ole.%f", mipscofpc, 267 "c.ule.%f", mipscofpc, 268 "c.sf.%f", mipscofpc, 269 "c.ngle.%f", mipscofpc, 270 "c.seq.%f", mipscofpc, 271 "c.ngl.%f", mipscofpc, 272 "c.lt.%f", mipscofpc, 273 "c.nge.%f", mipscofpc, 274 "c.le.%f", mipscofpc, 275 "c.ngt.%f", mipscofpc, 276 }; 277 278 static char fsub[16] = { 279 's', 'd', 'e', 'q', 'w', '?', '?', '?', 280 '?', '?', '?', '?', '?', '?', '?', '?' 281 }; 282 283 284 static int 285 mkinstr(Instr *i, Map *map, ulong pc) 286 { 287 long w; 288 289 if (get4(map, pc, &w) < 0) { 290 werrstr("can't read instruction: %r"); 291 return -1; 292 } 293 i->addr = pc; 294 i->op = (w >> 26) & 0x3F; 295 i->rs = (w >> 21) & 0x1F; 296 i->rt = (w >> 16) & 0x1F; 297 i->rd = (w >> 11) & 0x1F; 298 i->sa = (w >> 6) & 0x1F; 299 i->function = w & 0x3F; 300 i->immediate = w & 0x0000FFFF; 301 if (i->immediate & 0x8000) 302 i->immediate |= ~0x0000FFFF; 303 i->cofun = w & 0x01FFFFFF; 304 i->target = w & 0x03FFFFFF; 305 i->w0 = w; 306 return 1; 307 } 308 309 static void 310 bprint(Instr *i, char *fmt, ...) 311 { 312 va_list arg; 313 314 va_start(arg, fmt); 315 i->curr = vseprint(i->curr, i->end, fmt, arg); 316 va_end(arg); 317 } 318 319 static void 320 format(char *mnemonic, Instr *i, char *f) 321 { 322 if (mnemonic) 323 format(0, i, mnemonic); 324 if (f == 0) 325 return; 326 if (i->curr < i->end) 327 *i->curr++ = '\t'; 328 for ( ; *f && i->curr < i->end; f++) { 329 if (*f != '%') { 330 *i->curr++ = *f; 331 continue; 332 } 333 switch (*++f) { 334 335 case 's': 336 bprint(i, "%d", i->rs); 337 break; 338 339 case 't': 340 bprint(i, "%d", i->rt); 341 break; 342 343 case 'd': 344 bprint(i, "%d", i->rd); 345 break; 346 347 case 'a': 348 bprint(i, "%d", i->sa); 349 break; 350 351 case 'l': 352 if (i->rs == 30) { 353 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); 354 bprint(i, "(SB)"); 355 } else 356 bprint(i, "%lx(r%d)", i->immediate, i->rs); 357 break; 358 359 case 'i': 360 bprint(i, "$%lx", i->immediate); 361 break; 362 363 case 'u': 364 *i->curr++ = '$'; 365 i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); 366 bprint(i, "(SB)"); 367 break; 368 369 case 'j': 370 i->curr += symoff(i->curr, i->end-i->curr, 371 (i->target<<2)|(i->addr & 0xF0000000), CANY); 372 bprint(i, "(SB)"); 373 break; 374 375 case 'b': 376 i->curr += symoff(i->curr, i->end-i->curr, 377 (i->immediate<<2)+i->addr+4, CANY); 378 break; 379 380 case 'c': 381 bprint(i, "%lux", i->cofun); 382 break; 383 384 case 'w': 385 bprint(i, "[%lux]", i->w0); 386 break; 387 388 case 'f': 389 *i->curr++ = fsub[i->rs & 0x0F]; 390 break; 391 392 case '\0': 393 *i->curr++ = '%'; 394 return; 395 396 default: 397 bprint(i, "%%%c", *f); 398 break; 399 } 400 } 401 } 402 403 static void 404 copz(int cop, Instr *i) 405 { 406 char *f, *m, buf[16]; 407 408 m = buf; 409 f = "%t,%d"; 410 switch (i->rs) { 411 412 case 0: 413 sprint(buf, "mfc%d", cop); 414 break; 415 416 case 2: 417 sprint(buf, "cfc%d", cop); 418 break; 419 420 case 4: 421 sprint(buf, "mtc%d", cop); 422 break; 423 424 case 6: 425 sprint(buf, "ctc%d", cop); 426 break; 427 428 case 8: 429 f = "%b"; 430 switch (i->rt) { 431 432 case 0: 433 sprint(buf, "bc%df", cop); 434 break; 435 436 case 1: 437 sprint(buf, "bc%dt", cop); 438 break; 439 440 case 2: 441 sprint(buf, "bc%dfl", cop); 442 break; 443 444 case 3: 445 sprint(buf, "bc%dtl", cop); 446 break; 447 448 default: 449 sprint(buf, "cop%d", cop); 450 f = mipscoxxx; 451 break; 452 } 453 break; 454 455 default: 456 sprint(buf, "cop%d", cop); 457 if (i->rs & 0x10) 458 f = "function %c"; 459 else 460 f = mipscoxxx; 461 break; 462 } 463 format(m, i, f); 464 } 465 466 static void 467 cop0(Instr *i) 468 { 469 char *m = 0; 470 471 if (i->rs >= 0x10) { 472 switch (i->cofun) { 473 474 case 1: 475 m = "tlbr"; 476 break; 477 478 case 2: 479 m = "tlbwi"; 480 break; 481 482 case 6: 483 m = "tlbwr"; 484 break; 485 486 case 8: 487 m = "tlbp"; 488 break; 489 490 case 16: 491 m = "rfe"; 492 break; 493 494 case 32: 495 m = "eret"; 496 break; 497 } 498 if (m) { 499 format(m, i, 0); 500 if (i->curr < i->end) 501 *i->curr++ = 0; 502 return; 503 } 504 } 505 copz(0, i); 506 } 507 508 int 509 _mipscoinst(Map *map, ulong pc, char *buf, int n) 510 { 511 Instr i; 512 Opcode *o; 513 uchar op; 514 515 i.curr = buf; 516 i.end = buf+n-1; 517 if (mkinstr(&i, map, pc) < 0) 518 return -1; 519 switch (i.op) { 520 521 case 0x00: /* SPECIAL */ 522 o = sopcodes; 523 op = i.function; 524 break; 525 526 case 0x01: /* REGIMM */ 527 o = ropcodes; 528 op = i.rt; 529 break; 530 531 case 0x10: /* COP0 */ 532 cop0(&i); 533 return 4; 534 535 case 0x11: /* COP1 */ 536 if (i.rs & 0x10) { 537 o = fopcodes; 538 op = i.function; 539 break; 540 } 541 /*FALLTHROUGH*/ 542 case 0x12: /* COP2 */ 543 case 0x13: /* COP3 */ 544 copz(i.op-0x10, &i); 545 return 4; 546 547 default: 548 o = opcodes; 549 op = i.op; 550 break; 551 } 552 format(o[op].mnemonic, &i, o[op].mipsco); 553 return 4; 554 } 555