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