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