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 24: 497 m = "eret"; 498 break; 499 500 case 32: 501 m = "wait"; 502 break; 503 } 504 if (m) { 505 format(m, i, 0); 506 if (i->curr < i->end) 507 *i->curr++ = 0; 508 return; 509 } 510 } 511 copz(0, i); 512 } 513 514 int 515 _mipscoinst(Map *map, uvlong pc, char *buf, int n) 516 { 517 Instr i; 518 Opcode *o; 519 uchar op; 520 521 i.curr = buf; 522 i.end = buf+n-1; 523 if (mkinstr(&i, map, pc) < 0) 524 return -1; 525 switch (i.op) { 526 527 case 0x00: /* SPECIAL */ 528 o = sopcodes; 529 op = i.function; 530 break; 531 532 case 0x01: /* REGIMM */ 533 o = ropcodes; 534 op = i.rt; 535 break; 536 537 case 0x10: /* COP0 */ 538 cop0(&i); 539 return 4; 540 541 case 0x11: /* COP1 */ 542 if (i.rs & 0x10) { 543 o = fopcodes; 544 op = i.function; 545 break; 546 } 547 /*FALLTHROUGH*/ 548 case 0x12: /* COP2 */ 549 case 0x13: /* COP3 */ 550 copz(i.op-0x10, &i); 551 return 4; 552 553 default: 554 o = opcodes; 555 op = i.op; 556 break; 557 } 558 format(o[op].mnemonic, &i, o[op].mipsco); 559 return 4; 560 } 561