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