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