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