vcodas.c 10 KB

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