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