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
mkinstr(Instr * i,Map * map,uvlong pc)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
bprint(Instr * i,char * fmt,...)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
format(char * mnemonic,Instr * i,char * f)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
copz(int cop,Instr * i)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
cop0(Instr * i)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
_mipscoinst(Map * map,uvlong pc,char * buf,int n)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