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