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 i->curr = doprint(i->curr, i->end, fmt, (&fmt+1)); 313 } 314 315 static void 316 format(char *mnemonic, Instr *i, char *f) 317 { 318 if (mnemonic) 319 format(0, i, mnemonic); 320 if (f == 0) 321 return; 322 if (i->curr < i->end) 323 *i->curr++ = '\t'; 324 for ( ; *f && i->curr < i->end; f++) { 325 if (*f != '%') { 326 *i->curr++ = *f; 327 continue; 328 } 329 switch (*++f) { 330 331 case 's': 332 bprint(i, "%d", i->rs); 333 break; 334 335 case 't': 336 bprint(i, "%d", i->rt); 337 break; 338 339 case 'd': 340 bprint(i, "%d", i->rd); 341 break; 342 343 case 'a': 344 bprint(i, "%d", i->sa); 345 break; 346 347 case 'l': 348 if (i->rs == 30) { 349 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); 350 bprint(i, "(SB)"); 351 } else 352 bprint(i, "%lx(r%d)", i->immediate, i->rs); 353 break; 354 355 case 'i': 356 bprint(i, "$%lx", i->immediate); 357 break; 358 359 case 'u': 360 *i->curr++ = '$'; 361 i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); 362 bprint(i, "(SB)"); 363 break; 364 365 case 'j': 366 i->curr += symoff(i->curr, i->end-i->curr, 367 (i->target<<2)|(i->addr & 0xF0000000), CANY); 368 bprint(i, "(SB)"); 369 break; 370 371 case 'b': 372 i->curr += symoff(i->curr, i->end-i->curr, 373 (i->immediate<<2)+i->addr+4, CANY); 374 break; 375 376 case 'c': 377 bprint(i, "%lux", i->cofun); 378 break; 379 380 case 'w': 381 bprint(i, "[%lux]", i->w0); 382 break; 383 384 case 'f': 385 *i->curr++ = fsub[i->rs & 0x0F]; 386 break; 387 388 case '\0': 389 *i->curr++ = '%'; 390 return; 391 392 default: 393 bprint(i, "%%%c", *f); 394 break; 395 } 396 } 397 } 398 399 static void 400 copz(int cop, Instr *i) 401 { 402 char *f, *m, buf[16]; 403 404 m = buf; 405 f = "%t,%d"; 406 switch (i->rs) { 407 408 case 0: 409 sprint(buf, "mfc%d", cop); 410 break; 411 412 case 2: 413 sprint(buf, "cfc%d", cop); 414 break; 415 416 case 4: 417 sprint(buf, "mtc%d", cop); 418 break; 419 420 case 6: 421 sprint(buf, "ctc%d", cop); 422 break; 423 424 case 8: 425 f = "%b"; 426 switch (i->rt) { 427 428 case 0: 429 sprint(buf, "bc%df", cop); 430 break; 431 432 case 1: 433 sprint(buf, "bc%dt", cop); 434 break; 435 436 case 2: 437 sprint(buf, "bc%dfl", cop); 438 break; 439 440 case 3: 441 sprint(buf, "bc%dtl", cop); 442 break; 443 444 default: 445 sprint(buf, "cop%d", cop); 446 f = mipscoxxx; 447 break; 448 } 449 break; 450 451 default: 452 sprint(buf, "cop%d", cop); 453 if (i->rs & 0x10) 454 f = "function %c"; 455 else 456 f = mipscoxxx; 457 break; 458 } 459 format(m, i, f); 460 } 461 462 static void 463 cop0(Instr *i) 464 { 465 char *m = 0; 466 467 if (i->rs >= 0x10) { 468 switch (i->cofun) { 469 470 case 1: 471 m = "tlbr"; 472 break; 473 474 case 2: 475 m = "tlbwi"; 476 break; 477 478 case 6: 479 m = "tlbwr"; 480 break; 481 482 case 8: 483 m = "tlbp"; 484 break; 485 486 case 16: 487 m = "rfe"; 488 break; 489 490 case 32: 491 m = "eret"; 492 break; 493 } 494 if (m) { 495 format(m, i, 0); 496 if (i->curr < i->end) 497 *i->curr++ = 0; 498 return; 499 } 500 } 501 copz(0, i); 502 } 503 504 int 505 _mipscoinst(Map *map, ulong pc, char *buf, int n) 506 { 507 Instr i; 508 Opcode *o; 509 uchar op; 510 511 i.curr = buf; 512 i.end = buf+n-1; 513 if (mkinstr(&i, map, pc) < 0) 514 return -1; 515 switch (i.op) { 516 517 case 0x00: /* SPECIAL */ 518 o = sopcodes; 519 op = i.function; 520 break; 521 522 case 0x01: /* REGIMM */ 523 o = ropcodes; 524 op = i.rt; 525 break; 526 527 case 0x10: /* COP0 */ 528 cop0(&i); 529 return 4; 530 531 case 0x11: /* COP1 */ 532 if (i.rs & 0x10) { 533 o = fopcodes; 534 op = i.function; 535 break; 536 } 537 /*FALLTHROUGH*/ 538 case 0x12: /* COP2 */ 539 case 0x13: /* COP3 */ 540 copz(i.op-0x10, &i); 541 return 4; 542 543 default: 544 o = opcodes; 545 op = i.op; 546 break; 547 } 548 format(o[op].mnemonic, &i, o[op].mipsco); 549 return 4; 550 } 551