1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 /*
5 * Mips-specific debugger interface
6 */
7
8 static char *mipsexcep(Map*, Rgetter);
9 static int mipsfoll(Map*, uvlong, Rgetter, uvlong*);
10 static int mipsinst(Map*, uvlong, char, char*, int);
11 static int mipsdas(Map*, uvlong, char*, int);
12 static int mipsinstlen(Map*, uvlong);
13
14 /*
15 * Debugger interface
16 */
17 Machdata mipsmach =
18 {
19 {0, 0, 0, 0xD}, /* break point */
20 4, /* break point size */
21
22 beswab, /* short to local byte order */
23 beswal, /* long to local byte order */
24 beswav, /* vlong to local byte order */
25 risctrace, /* C traceback */
26 riscframe, /* Frame finder */
27 mipsexcep, /* print exception */
28 0, /* breakpoint fixup */
29 beieeesftos, /* single precision float printer */
30 beieeedftos, /* double precisioin float printer */
31 mipsfoll, /* following addresses */
32 mipsinst, /* print instruction */
33 mipsdas, /* dissembler */
34 mipsinstlen, /* instruction size */
35 };
36
37 Machdata mipsmachle =
38 {
39 {0, 0, 0, 0xD}, /* break point */
40 4, /* break point size */
41
42 leswab, /* short to local byte order */
43 leswal, /* long to local byte order */
44 leswav, /* vlong to local byte order */
45 risctrace, /* C traceback */
46 riscframe, /* Frame finder */
47 mipsexcep, /* print exception */
48 0, /* breakpoint fixup */
49 leieeesftos, /* single precision float printer */
50 leieeedftos, /* double precisioin float printer */
51 mipsfoll, /* following addresses */
52 mipsinst, /* print instruction */
53 mipsdas, /* dissembler */
54 mipsinstlen, /* instruction size */
55 };
56
57 /*
58 * mips r4k little-endian
59 */
60 Machdata mipsmach2le =
61 {
62 {0, 0, 0, 0xD}, /* break point */
63 4, /* break point size */
64
65 leswab, /* short to local byte order */
66 leswal, /* long to local byte order */
67 leswav, /* vlong to local byte order */
68 risctrace, /* C traceback */
69 riscframe, /* Frame finder */
70 mipsexcep, /* print exception */
71 0, /* breakpoint fixup */
72 leieeesftos, /* single precision float printer */
73 leieeedftos, /* double precisioin float printer */
74 mipsfoll, /* following addresses */
75 mipsinst, /* print instruction */
76 mipsdas, /* dissembler */
77 mipsinstlen, /* instruction size */
78 };
79
80 /*
81 * mips r4k big-endian
82 */
83 Machdata mipsmach2be =
84 {
85 {0, 0, 0, 0xD}, /* break point */
86 4, /* break point size */
87
88 beswab, /* short to local byte order */
89 beswal, /* long to local byte order */
90 beswav, /* vlong to local byte order */
91 risctrace, /* C traceback */
92 riscframe, /* Frame finder */
93 mipsexcep, /* print exception */
94 0, /* breakpoint fixup */
95 beieeesftos, /* single precision float printer */
96 beieeedftos, /* double precisioin float printer */
97 mipsfoll, /* following addresses */
98 mipsinst, /* print instruction */
99 mipsdas, /* dissembler */
100 mipsinstlen, /* instruction size */
101 };
102
103
104 static char *excname[] =
105 {
106 "external interrupt",
107 "TLB modification",
108 "TLB miss (load or fetch)",
109 "TLB miss (store)",
110 "address error (load or fetch)",
111 "address error (store)",
112 "bus error (fetch)",
113 "bus error (data load or store)",
114 "system call",
115 "breakpoint",
116 "reserved instruction",
117 "coprocessor unusable",
118 "arithmetic overflow",
119 "undefined 13",
120 "undefined 14",
121 "system call",
122 /* the following is made up */
123 "floating point exception" /* FPEXC */
124 };
125
126 static char*
mipsexcep(Map * map,Rgetter rget)127 mipsexcep(Map *map, Rgetter rget)
128 {
129 int e;
130 long c;
131
132 c = (*rget)(map, "CAUSE");
133 if(c & 0x00002000) /* INTR3 */
134 e = 16; /* Floating point exception */
135 else
136 e = (c>>2)&0x0F;
137 return excname[e];
138 }
139
140 /* mips disassembler and related functions */
141
142 static char FRAMENAME[] = ".frame";
143
144 typedef struct {
145 uvlong addr;
146 uchar op; /* bits 31-26 */
147 uchar rs; /* bits 25-21 */
148 uchar rt; /* bits 20-16 */
149 uchar rd; /* bits 15-11 */
150 uchar sa; /* bits 10-6 */
151 uchar function; /* bits 5-0 */
152 long immediate; /* bits 15-0 */
153 ulong cofun; /* bits 24-0 */
154 ulong target; /* bits 25-0 */
155 long w0;
156 long w1;
157 int size; /* instruction size */
158 char *curr; /* fill point in buffer */
159 char *end; /* end of buffer */
160 char *err; /* error message */
161 } Instr;
162
163 static Map *mymap;
164
165 static int
decode(uvlong pc,Instr * i)166 decode(uvlong pc, Instr *i)
167 {
168 ulong w;
169
170 if (get4(mymap, pc, &w) < 0) {
171 werrstr("can't read instruction: %r");
172 return -1;
173 }
174
175 i->addr = pc;
176 i->size = 1;
177 i->op = (w >> 26) & 0x3F;
178 i->rs = (w >> 21) & 0x1F;
179 i->rt = (w >> 16) & 0x1F;
180 i->rd = (w >> 11) & 0x1F;
181 i->sa = (w >> 6) & 0x1F;
182 i->function = w & 0x3F;
183 i->immediate = w & 0x0000FFFF;
184 if (i->immediate & 0x8000)
185 i->immediate |= ~0x0000FFFF;
186 i->cofun = w & 0x01FFFFFF;
187 i->target = w & 0x03FFFFFF;
188 i->w0 = w;
189 return 1;
190 }
191
192 static int
mkinstr(uvlong pc,Instr * i)193 mkinstr(uvlong pc, Instr *i)
194 {
195 Instr x;
196
197 if (decode(pc, i) < 0)
198 return -1;
199 /*
200 * if it's a LUI followed by an ORI,
201 * it's an immediate load of a large constant.
202 * fix the LUI immediate in any case.
203 */
204 if (i->op == 0x0F) {
205 if (decode(pc+4, &x) < 0)
206 return 0;
207 i->immediate <<= 16;
208 if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
209 i->immediate |= (x.immediate & 0xFFFF);
210 i->w1 = x.w0;
211 i->size++;
212 return 1;
213 }
214 }
215 /*
216 * if it's a LWC1 followed by another LWC1
217 * into an adjacent register, it's a load of
218 * a floating point double.
219 */
220 else if (i->op == 0x31 && (i->rt & 0x01)) {
221 if (decode(pc+4, &x) < 0)
222 return 0;
223 if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
224 i->rt -= 1;
225 i->w1 = x.w0;
226 i->size++;
227 return 1;
228 }
229 }
230 /*
231 * similarly for double stores
232 */
233 else if (i->op == 0x39 && (i->rt & 0x01)) {
234 if (decode(pc+4, &x) < 0)
235 return 0;
236 if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
237 i->rt -= 1;
238 i->w1 = x.w0;
239 i->size++;
240 }
241 }
242 return 1;
243 }
244
245 #pragma varargck argpos bprint 2
246
247 static void
bprint(Instr * i,char * fmt,...)248 bprint(Instr *i, char *fmt, ...)
249 {
250 va_list arg;
251
252 va_start(arg, fmt);
253 i->curr = vseprint(i->curr, i->end, fmt, arg);
254 va_end(arg);
255 }
256
257 typedef struct Opcode Opcode;
258
259 struct Opcode {
260 char *mnemonic;
261 void (*f)(Opcode *, Instr *);
262 char *ken;
263 };
264
265 static void format(char *, Instr *, char *);
266
267 static void
branch(Opcode * o,Instr * i)268 branch(Opcode *o, Instr *i)
269 {
270 if (i->rs == 0 && i->rt == 0)
271 format("JMP", i, "%b");
272 else if (i->rs == 0)
273 format(o->mnemonic, i, "R%t,%b");
274 else if (i->rt < 2)
275 format(o->mnemonic, i, "R%s,%b");
276 else
277 format(o->mnemonic, i, "R%s,R%t,%b");
278 }
279
280 static void
addi(Opcode * o,Instr * i)281 addi(Opcode *o, Instr *i)
282 {
283 if (i->rs == i->rt)
284 format(o->mnemonic, i, "%i,R%t");
285 else if (i->rs == 0)
286 format("MOVW", i, "%i,R%t");
287 else if (i->rs == 30) {
288 bprint(i, "MOVW\t$");
289 i->curr += symoff(i->curr, i->end-i->curr,
290 i->immediate+mach->sb, CANY);
291 bprint(i, "(SB),R%d", i->rt);
292 }
293 else
294 format(o->mnemonic, i, o->ken);
295 }
296
297 static void
andi(Opcode * o,Instr * i)298 andi(Opcode *o, Instr *i)
299 {
300 if (i->rs == i->rt)
301 format(o->mnemonic, i, "%i,R%t");
302 else
303 format(o->mnemonic, i, o->ken);
304 }
305
306 static int
plocal(Instr * i,char * m,char r,int store)307 plocal(Instr *i, char *m, char r, int store)
308 {
309 int offset;
310 char *reg;
311 Symbol s;
312
313 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
314 return 0;
315 if (s.value > i->immediate) {
316 if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
317 return 0;
318 reg = "(SP)";
319 offset = i->immediate;
320 } else {
321 offset = i->immediate-s.value;
322 if (!getauto(&s, offset-4, CPARAM, &s))
323 return 0;
324 reg = "(FP)";
325 }
326 if (store)
327 bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
328 else
329 bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
330 return 1;
331 }
332
333 static void
lw(Opcode * o,Instr * i,char r)334 lw(Opcode *o, Instr *i, char r)
335 {
336 char *m;
337
338 if (r == 'F') {
339 if (i->size == 2)
340 m = "MOVD";
341 else
342 m = "MOVF";
343 }
344 else
345 m = o->mnemonic;
346 if (i->rs == 29 && plocal(i, m, r, 0))
347 return;
348
349 if (i->rs == 30 && mach->sb) {
350 bprint(i, "%s\t", m);
351 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
352 bprint(i, "(SB),%c%d", r, i->rt);
353 return;
354 }
355 if (r == 'F')
356 format(m, i, "%l,F%t");
357 else
358 format(m, i, o->ken);
359 }
360
361 static void
load(Opcode * o,Instr * i)362 load(Opcode *o, Instr *i)
363 {
364 lw(o, i, 'R');
365 }
366
367 static void
lwc1(Opcode * o,Instr * i)368 lwc1(Opcode *o, Instr *i)
369 {
370 lw(o, i, 'F');
371 }
372
373 static void
sw(Opcode * o,Instr * i,char r)374 sw(Opcode *o, Instr *i, char r)
375 {
376 char *m;
377
378 if (r == 'F') {
379 if (i->size == 2)
380 m = "MOVD";
381 else
382 m = "MOVF";
383 }
384 else
385 m = o->mnemonic;
386 if (i->rs == 29 && plocal(i, m, r, 1))
387 return;
388
389 if (i->rs == 30 && mach->sb) {
390 bprint(i, "%s\t%c%d,", m, r, i->rt);
391 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
392 bprint(i, "(SB)");
393 return;
394 }
395 if (r == 'F')
396 format(m, i, "F%t,%l");
397 else
398 format(m, i, o->ken);
399 }
400
401 static void
store(Opcode * o,Instr * i)402 store(Opcode *o, Instr *i)
403 {
404 sw(o, i, 'R');
405 }
406
407 static void
swc1(Opcode * o,Instr * i)408 swc1(Opcode *o, Instr *i)
409 {
410 sw(o, i, 'F');
411 }
412
413 static void
sll(Opcode * o,Instr * i)414 sll(Opcode *o, Instr *i)
415 {
416 if (i->w0 == 0)
417 bprint(i, "NOOP");
418 else if (i->rd == i->rt)
419 format(o->mnemonic, i, "$%a,R%d");
420 else
421 format(o->mnemonic, i, o->ken);
422 }
423
424 static void
sl32(Opcode * o,Instr * i)425 sl32(Opcode *o, Instr *i)
426 {
427 i->sa += 32;
428 if (i->rd == i->rt)
429 format(o->mnemonic, i, "$%a,R%d");
430 else
431 format(o->mnemonic, i, o->ken);
432 }
433
434 static void
sllv(Opcode * o,Instr * i)435 sllv(Opcode *o, Instr *i)
436 {
437 if (i->rd == i->rt)
438 format(o->mnemonic, i, "R%s,R%d");
439 else
440 format(o->mnemonic, i, o->ken);
441 }
442
443 static void
jal(Opcode * o,Instr * i)444 jal(Opcode *o, Instr *i)
445 {
446 if (i->rd == 31)
447 format("JAL", i, "(R%s)");
448 else
449 format(o->mnemonic, i, o->ken);
450 }
451
452 static void
add(Opcode * o,Instr * i)453 add(Opcode *o, Instr *i)
454 {
455 if (i->rd == i->rs)
456 format(o->mnemonic, i, "R%t,R%d");
457 else if (i->rd == i->rt)
458 format(o->mnemonic, i, "R%s,R%d");
459 else
460 format(o->mnemonic, i, o->ken);
461 }
462
463 static void
sub(Opcode * o,Instr * i)464 sub(Opcode *o, Instr *i)
465 {
466 if (i->rd == i->rs)
467 format(o->mnemonic, i, "R%t,R%d");
468 else
469 format(o->mnemonic, i, o->ken);
470 }
471
472 static void
or(Opcode * o,Instr * i)473 or(Opcode *o, Instr *i)
474 {
475 if (i->rs == 0 && i->rt == 0)
476 format("MOVW", i, "$0,R%d");
477 else if (i->rs == 0)
478 format("MOVW", i, "R%t,R%d");
479 else if (i->rt == 0)
480 format("MOVW", i, "R%s,R%d");
481 else
482 add(o, i);
483 }
484
485 static void
nor(Opcode * o,Instr * i)486 nor(Opcode *o, Instr *i)
487 {
488 if (i->rs == 0 && i->rt == 0 && i->rd == 0)
489 format("NOP", i, 0);
490 else
491 add(o, i);
492 }
493
494 static char mipscoload[] = "r%t,%l";
495 static char mipsload[] = "%l,R%t";
496 static char mipsstore[] = "R%t,%l";
497 static char mipsalui[] = "%i,R%s,R%t";
498 static char mipsalu3op[] = "R%t,R%s,R%d";
499 static char mipsrtrs[] = "R%t,R%s";
500 static char mipscorsrt[] = "r%s,r%t";
501 static char mipscorsi[] = "r%s,%i";
502 static char mipscoxxx[] = "%w";
503 static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
504 static char mipsfp3[] = "F%t,F%d,F%a";
505 static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
506 static char mipsfp2[] = "F%d,F%a";
507 static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
508 static char mipsfpc[] = "F%t,F%d";
509
510 static Opcode opcodes[64] = {
511 0, 0, 0,
512 0, 0, 0,
513 "JMP", 0, "%j",
514 "JAL", 0, "%j",
515 "BEQ", branch, 0,
516 "BNE", branch, 0,
517 "BLEZ", branch, 0,
518 "BGTZ", branch, 0,
519 "ADD", addi, mipsalui,
520 "ADDU", addi, mipsalui,
521 "SGT", 0, mipsalui,
522 "SGTU", 0, mipsalui,
523 "AND", andi, mipsalui,
524 "OR", andi, mipsalui,
525 "XOR", andi, mipsalui,
526 "MOVW", 0, "$%u,R%t",
527 "cop0", 0, 0,
528 "cop1", 0, 0,
529 "cop2", 0, 0,
530 "cop3", 0, 0,
531 "BEQL", branch, 0,
532 "BNEL", branch, 0,
533 "BLEZL", branch, 0,
534 "BGTZL", branch, 0,
535 "instr18", 0, mipscoxxx,
536 "instr19", 0, mipscoxxx,
537 "MOVVL", load, mipsload,
538 "MOVVR", load, mipsload,
539 "instr1C", 0, mipscoxxx,
540 "instr1D", 0, mipscoxxx,
541 "instr1E", 0, mipscoxxx,
542 "instr1F", 0, mipscoxxx,
543 "MOVB", load, mipsload,
544 "MOVH", load, mipsload,
545 "lwl", 0, mipscoload,
546 "MOVW", load, mipsload,
547 "MOVBU", load, mipsload,
548 "MOVHU", load, mipsload,
549 "lwr", 0, mipscoload,
550 "instr27", 0, mipscoxxx,
551 "MOVB", store, mipsstore,
552 "MOVH", store, mipsstore,
553 "swl", 0, mipscoload,
554 "MOVW", store, mipsstore,
555 "MOVVL", store, mipsstore,
556 "MOVVR", store, mipsstore,
557 "swr", 0, mipscoload,
558 "CACHE", 0, "%C,%l",
559 "ll", 0, mipscoload,
560 "MOVW", lwc1, mipscoload,
561 "lwc2", 0, mipscoload,
562 "lwc3", 0, mipscoload,
563 "instr34", 0, mipscoxxx,
564 "ldc1", 0, mipscoload,
565 "ldc2", 0, mipscoload,
566 "MOVV", load, mipsload,
567 "sc", 0, mipscoload,
568 "swc1", swc1, mipscoload,
569 "swc2", 0, mipscoload,
570 "swc3", 0, mipscoload,
571 "instr3C", 0, mipscoxxx,
572 "sdc1", 0, mipscoload,
573 "sdc2", 0, mipscoload,
574 "MOVV", store, mipsstore,
575 };
576
577 static Opcode sopcodes[64] = {
578 "SLL", sll, "$%a,R%t,R%d",
579 "special01", 0, mipscoxxx,
580 "SRL", sll, "$%a,R%t,R%d",
581 "SRA", sll, "$%a,R%t,R%d",
582 "SLL", sllv, "R%s,R%t,R%d",
583 "special05", 0, mipscoxxx,
584 "SRL", sllv, "R%s,R%t,R%d",
585 "SRA", sllv, "R%s,R%t,R%d",
586 "JMP", 0, "(R%s)",
587 "jal", jal, "r%d,r%s",
588 "special0A", 0, mipscoxxx,
589 "special0B", 0, mipscoxxx,
590 "SYSCALL", 0, 0,
591 "BREAK", 0, 0,
592 "special0E", 0, mipscoxxx,
593 "SYNC", 0, 0,
594 "MOVW", 0, "HI,R%d",
595 "MOVW", 0, "R%s,HI",
596 "MOVW", 0, "LO,R%d",
597 "MOVW", 0, "R%s,LO",
598 "SLLV", sllv, "R%s,R%t,R%d",
599 "special15", 0, mipscoxxx,
600 "SRLV", sllv, "R%s,R%t,R%d",
601 "SRAV", sllv, "R%s,R%t,R%d",
602 "MUL", 0, mipsrtrs,
603 "MULU", 0, mipsrtrs,
604 "DIV", 0, mipsrtrs,
605 "DIVU", 0, mipsrtrs,
606 "special1C", 0, mipscoxxx,
607 "special1D", 0, mipscoxxx,
608 "DDIV", 0, "R%s,R%t",
609 "special1F", 0, mipscoxxx,
610 "ADD", add, mipsalu3op,
611 "ADDU", add, mipsalu3op,
612 "SUB", sub, mipsalu3op,
613 "SUBU", sub, mipsalu3op,
614 "AND", add, mipsalu3op,
615 "OR", or, mipsalu3op,
616 "XOR", add, mipsalu3op,
617 "NOR", nor, mipsalu3op,
618 "special28", 0, mipscoxxx,
619 "special29", 0, mipscoxxx,
620 "SGT", 0, mipsalu3op,
621 "SGTU", 0, mipsalu3op,
622 "special2C", 0, mipscoxxx,
623 "special2D", 0, mipscoxxx,
624 "special2E", 0, mipscoxxx,
625 "DSUBU", 0, "R%s,R%t,R%d",
626 "tge", 0, mipscorsrt,
627 "tgeu", 0, mipscorsrt,
628 "tlt", 0, mipscorsrt,
629 "tltu", 0, mipscorsrt,
630 "teq", 0, mipscorsrt,
631 "special35", 0, mipscoxxx,
632 "tne", 0, mipscorsrt,
633 "special37", 0, mipscoxxx,
634 "SLLV", sll, "$%a,R%t,R%d",
635 "special39", 0, mipscoxxx,
636 "SRLV", sll, "$%a,R%t,R%d",
637 "SRAV", sll, "$%a,R%t,R%d",
638 "SLLV", sl32, "$%a,R%t,R%d",
639 "special3D", 0, mipscoxxx,
640 "SRLV", sl32, "$%a,R%t,R%d",
641 "SRAV", sl32, "$%a,R%t,R%d",
642 };
643
644 static Opcode ropcodes[32] = {
645 "BLTZ", branch, 0,
646 "BGEZ", branch, 0,
647 "BLTZL", branch, 0,
648 "BGEZL", branch, 0,
649 "regimm04", 0, mipscoxxx,
650 "regimm05", 0, mipscoxxx,
651 "regimm06", 0, mipscoxxx,
652 "regimm07", 0, mipscoxxx,
653 "tgei", 0, mipscorsi,
654 "tgeiu", 0, mipscorsi,
655 "tlti", 0, mipscorsi,
656 "tltiu", 0, mipscorsi,
657 "teqi", 0, mipscorsi,
658 "regimm0D", 0, mipscoxxx,
659 "tnei", 0, mipscorsi,
660 "regimm0F", 0, mipscoxxx,
661 "BLTZAL", branch, 0,
662 "BGEZAL", branch, 0,
663 "BLTZALL", branch, 0,
664 "BGEZALL", branch, 0,
665 "regimm14", 0, mipscoxxx,
666 "regimm15", 0, mipscoxxx,
667 "regimm16", 0, mipscoxxx,
668 "regimm17", 0, mipscoxxx,
669 "regimm18", 0, mipscoxxx,
670 "regimm19", 0, mipscoxxx,
671 "regimm1A", 0, mipscoxxx,
672 "regimm1B", 0, mipscoxxx,
673 "regimm1C", 0, mipscoxxx,
674 "regimm1D", 0, mipscoxxx,
675 "regimm1E", 0, mipscoxxx,
676 "regimm1F", 0, mipscoxxx,
677 };
678
679 static Opcode fopcodes[64] = {
680 "ADD%f", 0, mipsfp3,
681 "SUB%f", 0, mipsfp3,
682 "MUL%f", 0, mipsfp3,
683 "DIV%f", 0, mipsfp3,
684 "sqrt.%f", 0, mipscofp2,
685 "ABS%f", 0, mipsfp2,
686 "MOV%f", 0, mipsfp2,
687 "NEG%f", 0, mipsfp2,
688 "finstr08", 0, mipscoxxx,
689 "finstr09", 0, mipscoxxx,
690 "finstr0A", 0, mipscoxxx,
691 "finstr0B", 0, mipscoxxx,
692 "round.w.%f", 0, mipscofp2,
693 "trunc.w%f", 0, mipscofp2,
694 "ceil.w%f", 0, mipscofp2,
695 "floor.w%f", 0, mipscofp2,
696 "finstr10", 0, mipscoxxx,
697 "finstr11", 0, mipscoxxx,
698 "finstr12", 0, mipscoxxx,
699 "finstr13", 0, mipscoxxx,
700 "finstr14", 0, mipscoxxx,
701 "finstr15", 0, mipscoxxx,
702 "finstr16", 0, mipscoxxx,
703 "finstr17", 0, mipscoxxx,
704 "finstr18", 0, mipscoxxx,
705 "finstr19", 0, mipscoxxx,
706 "finstr1A", 0, mipscoxxx,
707 "finstr1B", 0, mipscoxxx,
708 "finstr1C", 0, mipscoxxx,
709 "finstr1D", 0, mipscoxxx,
710 "finstr1E", 0, mipscoxxx,
711 "finstr1F", 0, mipscoxxx,
712 "cvt.s.%f", 0, mipscofp2,
713 "cvt.d.%f", 0, mipscofp2,
714 "cvt.e.%f", 0, mipscofp2,
715 "cvt.q.%f", 0, mipscofp2,
716 "cvt.w.%f", 0, mipscofp2,
717 "finstr25", 0, mipscoxxx,
718 "finstr26", 0, mipscoxxx,
719 "finstr27", 0, mipscoxxx,
720 "finstr28", 0, mipscoxxx,
721 "finstr29", 0, mipscoxxx,
722 "finstr2A", 0, mipscoxxx,
723 "finstr2B", 0, mipscoxxx,
724 "finstr2C", 0, mipscoxxx,
725 "finstr2D", 0, mipscoxxx,
726 "finstr2E", 0, mipscoxxx,
727 "finstr2F", 0, mipscoxxx,
728 "c.f.%f", 0, mipscofpc,
729 "c.un.%f", 0, mipscofpc,
730 "CMPEQ%f", 0, mipsfpc,
731 "c.ueq.%f", 0, mipscofpc,
732 "c.olt.%f", 0, mipscofpc,
733 "c.ult.%f", 0, mipscofpc,
734 "c.ole.%f", 0, mipscofpc,
735 "c.ule.%f", 0, mipscofpc,
736 "c.sf.%f", 0, mipscofpc,
737 "c.ngle.%f", 0, mipscofpc,
738 "c.seq.%f", 0, mipscofpc,
739 "c.ngl.%f", 0, mipscofpc,
740 "CMPGT%f", 0, mipsfpc,
741 "c.nge.%f", 0, mipscofpc,
742 "CMPGE%f", 0, mipsfpc,
743 "c.ngt.%f", 0, mipscofpc,
744 };
745
746 static char *cop0regs[32] = {
747 "INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
748 "CONTEXT", "PageMask", "Wired", "Error",
749 "BADVADDR", "Count", "TLBVIRT", "Compare",
750 "STATUS", "CAUSE", "EPC", "PRID",
751 "Config", "LLadr", "WatchLo", "WatchHi",
752 "20", "21", "22", "23",
753 "24", "25", "26", "CacheErr",
754 "TagLo", "TagHi", "ErrorEPC", "31"
755 };
756
757 static char fsub[16] = {
758 'F', 'D', 'e', 'q', 'W', '?', '?', '?',
759 '?', '?', '?', '?', '?', '?', '?', '?'
760 };
761
762 static char *cacheps[] = {
763 "I", "D", "SI", "SD"
764 };
765
766 static char *cacheop[] = {
767 "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
768 };
769
770 static void
format(char * mnemonic,Instr * i,char * f)771 format(char *mnemonic, Instr *i, char *f)
772 {
773 if (mnemonic)
774 format(0, i, mnemonic);
775 if (f == 0)
776 return;
777 if (mnemonic)
778 if (i->curr < i->end)
779 *i->curr++ = '\t';
780 for ( ; *f && i->curr < i->end; f++) {
781 if (*f != '%') {
782 *i->curr++ = *f;
783 continue;
784 }
785 switch (*++f) {
786
787 case 's':
788 bprint(i, "%d", i->rs);
789 break;
790
791 case 't':
792 bprint(i, "%d", i->rt);
793 break;
794
795 case 'd':
796 bprint(i, "%d", i->rd);
797 break;
798
799 case 'a':
800 bprint(i, "%d", i->sa);
801 break;
802
803 case 'l':
804 bprint(i, "%lx(R%d)",i->immediate, i->rs);
805 break;
806
807 case 'i':
808 bprint(i, "$%lx", i->immediate);
809 break;
810
811 case 'u':
812 i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
813 bprint(i, "(SB)");
814 break;
815
816 case 'j':
817 i->curr += symoff(i->curr, i->end-i->curr,
818 (i->target<<2)|(i->addr & 0xF0000000), CANY);
819 bprint(i, "(SB)");
820 break;
821
822 case 'b':
823 i->curr += symoff(i->curr, i->end-i->curr,
824 (i->immediate<<2)+i->addr+4, CANY);
825 break;
826
827 case 'c':
828 bprint(i, "$%lx", i->cofun);
829 break;
830
831 case 'w':
832 bprint(i, "[%lux]", i->w0);
833 break;
834
835 case 'm':
836 bprint(i, "M(%s)", cop0regs[i->rd]);
837 break;
838
839 case 'f':
840 *i->curr++ = fsub[i->rs & 0x0F];
841 break;
842
843 case 'C':
844 bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
845 break;
846
847 case '\0':
848 *i->curr++ = '%';
849 return;
850
851 default:
852 bprint(i, "%%%c", *f);
853 break;
854 }
855 }
856 *i->curr = 0;
857 }
858
859 static void
copz(int cop,Instr * i)860 copz(int cop, Instr *i)
861 {
862 char *f, *m, buf[16];
863
864 m = buf;
865 f = "%t,%d";
866 switch (i->rs) {
867
868 case 0:
869 sprint(buf, "mfc%d", cop);
870 break;
871
872 case 2:
873 sprint(buf, "cfc%d", cop);
874 break;
875
876 case 4:
877 sprint(buf, "mtc%d", cop);
878 break;
879
880 case 6:
881 sprint(buf, "ctc%d", cop);
882 break;
883
884 case 8:
885 f = "%b";
886 switch (i->rt) {
887
888 case 0:
889 sprint(buf, "bc%df", cop);
890 break;
891
892 case 1:
893 sprint(buf, "bc%dt", cop);
894 break;
895
896 case 2:
897 sprint(buf, "bc%dfl", cop);
898 break;
899
900 case 3:
901 sprint(buf, "bc%dtl", cop);
902 break;
903
904 default:
905 sprint(buf, "cop%d", cop);
906 f = mipscoxxx;
907 break;
908 }
909 break;
910
911 default:
912 sprint(buf, "cop%d", cop);
913 if (i->rs & 0x10)
914 f = "function %c";
915 else
916 f = mipscoxxx;
917 break;
918 }
919 format(m, i, f);
920 }
921
922 static void
cop0(Instr * i)923 cop0(Instr *i)
924 {
925 char *m = 0;
926
927 if (i->rs < 8) {
928 switch (i->rs) {
929
930 case 0:
931 case 1:
932 format("MOVW", i, "%m,R%t");
933 return;
934
935 case 4:
936 case 5:
937 format("MOVW", i, "R%t,%m");
938 return;
939 }
940 }
941 else if (i->rs >= 0x10) {
942 switch (i->cofun) {
943
944 case 1:
945 m = "TLBR";
946 break;
947
948 case 2:
949 m = "TLBWI";
950 break;
951
952 case 6:
953 m = "TLBWR";
954 break;
955
956 case 8:
957 m = "TLBP";
958 break;
959
960 case 16:
961 m = "RFE";
962 break;
963
964 case 32:
965 m = "ERET";
966 break;
967 }
968 if (m) {
969 format(m, i, 0);
970 return;
971 }
972 }
973 copz(0, i);
974 }
975
976 static void
cop1(Instr * i)977 cop1(Instr *i)
978 {
979 char *m = "MOVW";
980
981 switch (i->rs) {
982
983 case 0:
984 format(m, i, "F%d,R%t");
985 return;
986
987 case 2:
988 format(m, i, "FCR%d,R%t");
989 return;
990
991 case 4:
992 format(m, i, "R%t,F%d");
993 return;
994
995 case 6:
996 format(m, i, "R%t,FCR%d");
997 return;
998
999 case 8:
1000 switch (i->rt) {
1001
1002 case 0:
1003 format("BFPF", i, "%b");
1004 return;
1005
1006 case 1:
1007 format("BFPT", i, "%b");
1008 return;
1009 }
1010 break;
1011 }
1012 copz(1, i);
1013 }
1014
1015 static int
printins(Map * map,uvlong pc,char * buf,int n)1016 printins(Map *map, uvlong pc, char *buf, int n)
1017 {
1018 Instr i;
1019 Opcode *o;
1020 uchar op;
1021
1022 i.curr = buf;
1023 i.end = buf+n-1;
1024 mymap = map;
1025 if (mkinstr(pc, &i) < 0)
1026 return -1;
1027 switch (i.op) {
1028
1029 case 0x00: /* SPECIAL */
1030 o = sopcodes;
1031 op = i.function;
1032 break;
1033
1034 case 0x01: /* REGIMM */
1035 o = ropcodes;
1036 op = i.rt;
1037 break;
1038
1039 case 0x10: /* COP0 */
1040 cop0(&i);
1041 return i.size*4;
1042
1043 case 0x11: /* COP1 */
1044 if (i.rs & 0x10) {
1045 o = fopcodes;
1046 op = i.function;
1047 break;
1048 }
1049 cop1(&i);
1050 return i.size*4;
1051
1052 case 0x12: /* COP2 */
1053 case 0x13: /* COP3 */
1054 copz(i.op-0x10, &i);
1055 return i.size*4;
1056
1057 default:
1058 o = opcodes;
1059 op = i.op;
1060 break;
1061 }
1062 if (o[op].f)
1063 (*o[op].f)(&o[op], &i);
1064 else
1065 format(o[op].mnemonic, &i, o[op].ken);
1066 return i.size*4;
1067 }
1068
1069 extern int _mipscoinst(Map *, uvlong, char*, int);
1070
1071 /* modifier 'I' toggles the default disassembler type */
1072 static int
mipsinst(Map * map,uvlong pc,char modifier,char * buf,int n)1073 mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1074 {
1075 if ((asstype == AMIPSCO && modifier == 'i')
1076 || (asstype == AMIPS && modifier == 'I'))
1077 return _mipscoinst(map, pc, buf, n);
1078 else
1079 return printins(map, pc, buf, n);
1080 }
1081
1082 static int
mipsdas(Map * map,uvlong pc,char * buf,int n)1083 mipsdas(Map *map, uvlong pc, char *buf, int n)
1084 {
1085 Instr i;
1086
1087 i.curr = buf;
1088 i.end = buf+n;
1089 mymap = map;
1090 if (mkinstr(pc, &i) < 0)
1091 return -1;
1092 if (i.end-i.curr > 8)
1093 i.curr = _hexify(buf, i.w0, 7);
1094 if (i.size == 2 && i.end-i.curr > 9) {
1095 *i.curr++ = ' ';
1096 i.curr = _hexify(i.curr, i.w1, 7);
1097 }
1098 *i.curr = 0;
1099 return i.size*4;
1100 }
1101
1102 static int
mipsinstlen(Map * map,uvlong pc)1103 mipsinstlen(Map *map, uvlong pc)
1104 {
1105 Instr i;
1106
1107 mymap = map;
1108 if (mkinstr(pc, &i) < 0)
1109 return -1;
1110 return i.size*4;
1111 }
1112
1113 static int
mipsfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)1114 mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1115 {
1116 ulong w, l;
1117 char buf[8];
1118 Instr i;
1119
1120 mymap = map;
1121 if (mkinstr(pc, &i) < 0)
1122 return -1;
1123 w = i.w0;
1124 if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */
1125 Conditional:
1126 foll[0] = pc+8;
1127 l = ((w&0xFFFF)<<2);
1128 if(w & 0x8000)
1129 l |= 0xFFFC0000;
1130 foll[1] = pc+4 + l;
1131 return 2;
1132 }
1133
1134 l = (w&0xFC000000)>>26;
1135 switch(l){
1136 case 0: /* SPECIAL */
1137 if((w&0x3E) == 0x08){ /* JR, JALR */
1138 sprint(buf, "R%ld", (w>>21)&0x1F);
1139 foll[0] = (*rget)(map, buf);
1140 return 1;
1141 }
1142 foll[0] = pc+i.size*4;
1143 return 1;
1144 case 0x30: /* Load-Linked followed by NOP, STC */
1145 foll[0] = pc+12;
1146 return 1;
1147 case 1: /* BCOND */
1148 case 4: /* BEQ */
1149 case 20: /* BEQL */
1150 case 5: /* BNE */
1151 case 21: /* BNEL */
1152 case 6: /* BLEZ */
1153 case 22: /* BLEZL */
1154 case 7: /* BGTZ */
1155 case 23: /* BGTZL */
1156 goto Conditional;
1157 case 2: /* J */
1158 case 3: /* JAL */
1159 foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1160 return 1;
1161 }
1162
1163 foll[0] = pc+i.size*4;
1164 return 1;
1165 }
1166