xref: /plan9/sys/src/libmach/vdb.c (revision 426f2a32150b219ea919a1d76cbd0c50d6d55686)
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