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