xref: /plan9/sys/src/libmach/vcodas.c (revision eaba85aa6b158bdf68fdb77f770e3ba0899a8b5e)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 	/* mips native disassembler */
7 
8 typedef struct {
9 	uvlong addr;			/* pc of instr */
10 	uchar op;			/* bits 31-26 */
11 	uchar rs;			/* bits 25-21 */
12 	uchar rt;			/* bits 20-16 */
13 	uchar rd;			/* bits 15-11 */
14 	uchar sa;			/* bits 10-6 */
15 	uchar function;			/* bits 5-0 */
16 	long immediate;			/* bits 15-0 */
17 	ulong cofun;			/* bits 24-0 */
18 	ulong target;			/* bits 25-0 */
19 	long w0;
20 	char *curr;			/* current fill point */
21 	char *end;			/* end of buffer */
22 	char *err;
23 } Instr;
24 
25 typedef struct {
26 	char *mnemonic;
27 	char *mipsco;
28 } Opcode;
29 
30 static char mipscoload[] = "r%t,%l";
31 static char mipscoalui[] = "r%t,r%s,%i";
32 static char mipscoalu3op[] = "r%d,r%s,r%t";
33 static char mipscoboc[] = "r%s,r%t,%b";
34 static char mipscoboc0[] = "r%s,%b";
35 static char mipscorsrt[] = "r%s,r%t";
36 static char mipscorsi[] = "r%s,%i";
37 static char mipscoxxx[] = "%w";
38 static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
39 static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
40 static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
41 
42 static Opcode opcodes[64] = {
43 	0,		0,
44 	0,		0,
45 	"j",		"%j",
46 	"jal",		"%j",
47 	"beq",		mipscoboc,
48 	"bne",		mipscoboc,
49 	"blez",		mipscoboc0,
50 	"bgtz",		mipscoboc0,
51 	"addi",		mipscoalui,
52 	"addiu",	mipscoalui,
53 	"slti",		mipscoalui,
54 	"sltiu",	mipscoalui,
55 	"andi",		mipscoalui,
56 	"ori",		mipscoalui,
57 	"xori",		mipscoalui,
58 	"lui",		"r%t,%u",
59 	"cop0",		0,
60 	"cop1",		0,
61 	"cop2",		0,
62 	"cop3",		0,
63 	"beql",		mipscoboc,
64 	"bnel",		mipscoboc,
65 	"blezl",	mipscoboc0,
66 	"bgtzl",	mipscoboc0,
67 	"instr18",	mipscoxxx,
68 	"instr19",	mipscoxxx,
69 	"instr1A",	mipscoxxx,
70 	"instr1B",	mipscoxxx,
71 	"instr1C",	mipscoxxx,
72 	"instr1D",	mipscoxxx,
73 	"instr1E",	mipscoxxx,
74 	"instr1F",	mipscoxxx,
75 	"lb",		mipscoload,
76 	"lh",		mipscoload,
77 	"lwl",		mipscoload,
78 	"lw",		mipscoload,
79 	"lbu",		mipscoload,
80 	"lhu",		mipscoload,
81 	"lwr",		mipscoload,
82 	"instr27",	mipscoxxx,
83 	"sb",		mipscoload,
84 	"sh",		mipscoload,
85 	"swl",		mipscoload,
86 	"sw",		mipscoload,
87 	"instr2C",	mipscoxxx,
88 	"instr2D",	mipscoxxx,
89 	"swr",		mipscoload,
90 	"cache",	"",
91 	"ll",		mipscoload,
92 	"lwc1",		mipscoload,
93 	"lwc2",		mipscoload,
94 	"lwc3",		mipscoload,
95 	"instr34",	mipscoxxx,
96 	"ld",		mipscoload,
97 	"ld",		mipscoload,
98 	"ld",		mipscoload,
99 	"sc",		mipscoload,
100 	"swc1",		mipscoload,
101 	"swc2",		mipscoload,
102 	"swc3",		mipscoload,
103 	"instr3C",	mipscoxxx,
104 	"sd",		mipscoload,
105 	"sd",		mipscoload,
106 	"sd",		mipscoload,
107 };
108 
109 static Opcode sopcodes[64] = {
110 	"sll",		"r%d,r%t,$%a",
111 	"special01",	mipscoxxx,
112 	"srl",		"r%d,r%t,$%a",
113 	"sra",		"r%d,r%t,$%a",
114 	"sllv",		"r%d,r%t,R%s",
115 	"special05",	mipscoxxx,
116 	"srlv",		"r%d,r%t,r%s",
117 	"srav",		"r%d,r%t,r%s",
118 	"jr",		"r%s",
119 	"jalr",		"r%d,r%s",
120 	"special0A",	mipscoxxx,
121 	"special0B",	mipscoxxx,
122 	"syscall",	"",
123 	"break",	"",
124 	"special0E",	mipscoxxx,
125 	"sync",		"",
126 	"mfhi",		"r%d",
127 	"mthi",		"r%s",
128 	"mflo",		"r%d",
129 	"mtlo",		"r%s",
130 	"special14",	mipscoxxx,
131 	"special15",	mipscoxxx,
132 	"special16",	mipscoxxx,
133 	"special17",	mipscoxxx,
134 	"mult",		mipscorsrt,
135 	"multu",	mipscorsrt,
136 	"div",		mipscorsrt,
137 	"divu",		mipscorsrt,
138 	"special1C",	mipscoxxx,
139 	"special1D",	mipscoxxx,
140 	"special1E",	mipscoxxx,
141 	"special1F",	mipscoxxx,
142 	"add",		mipscoalu3op,
143 	"addu",		mipscoalu3op,
144 	"sub",		mipscoalu3op,
145 	"subu",		mipscoalu3op,
146 	"and",		mipscoalu3op,
147 	"or",		mipscoalu3op,
148 	"xor",		mipscoalu3op,
149 	"nor",		mipscoalu3op,
150 	"special28",	mipscoxxx,
151 	"special29",	mipscoxxx,
152 	"slt",		mipscoalu3op,
153 	"sltu",		mipscoalu3op,
154 	"special2C",	mipscoxxx,
155 	"special2D",	mipscoxxx,
156 	"special2E",	mipscoxxx,
157 	"special2F",	mipscoxxx,
158 	"tge",		mipscorsrt,
159 	"tgeu",		mipscorsrt,
160 	"tlt",		mipscorsrt,
161 	"tltu",		mipscorsrt,
162 	"teq",		mipscorsrt,
163 	"special35",	mipscoxxx,
164 	"tne",		mipscorsrt,
165 	"special37",	mipscoxxx,
166 	"special38",	mipscoxxx,
167 	"special39",	mipscoxxx,
168 	"special3A",	mipscoxxx,
169 	"special3B",	mipscoxxx,
170 	"special3C",	mipscoxxx,
171 	"special3D",	mipscoxxx,
172 	"special3E",	mipscoxxx,
173 	"special3F",	mipscoxxx,
174 };
175 
176 static Opcode ropcodes[32] = {
177 	"bltz",		mipscoboc0,
178 	"bgez",		mipscoboc0,
179 	"bltzl",	mipscoboc0,
180 	"bgezl",	mipscoboc0,
181 	"regimm04",	mipscoxxx,
182 	"regimm05",	mipscoxxx,
183 	"regimm06",	mipscoxxx,
184 	"regimm07",	mipscoxxx,
185 	"tgei",		mipscorsi,
186 	"tgeiu",	mipscorsi,
187 	"tlti",		mipscorsi,
188 	"tltiu",	mipscorsi,
189 	"teqi",		mipscorsi,
190 	"regimm0D",	mipscoxxx,
191 	"tnei",		mipscorsi,
192 	"regimm0F",	mipscoxxx,
193 	"bltzal",	mipscoboc0,
194 	"bgezal",	mipscoboc0,
195 	"bltzall",	mipscoboc0,
196 	"bgezall",	mipscoboc0,
197 	"regimm14",	mipscoxxx,
198 	"regimm15",	mipscoxxx,
199 	"regimm16",	mipscoxxx,
200 	"regimm17",	mipscoxxx,
201 	"regimm18",	mipscoxxx,
202 	"regimm19",	mipscoxxx,
203 	"regimm1A",	mipscoxxx,
204 	"regimm1B",	mipscoxxx,
205 	"regimm1C",	mipscoxxx,
206 	"regimm1D",	mipscoxxx,
207 	"regimm1E",	mipscoxxx,
208 	"regimm1F",	mipscoxxx,
209 };
210 
211 static Opcode fopcodes[64] = {
212 	"add.%f",	mipscofp3,
213 	"sub.%f",	mipscofp3,
214 	"mul.%f",	mipscofp3,
215 	"div.%f",	mipscofp3,
216 	"sqrt.%f",	mipscofp2,
217 	"abs.%f",	mipscofp2,
218 	"mov.%f",	mipscofp2,
219 	"neg.%f",	mipscofp2,
220 	"finstr08",	mipscoxxx,
221 	"finstr09",	mipscoxxx,
222 	"finstr0A",	mipscoxxx,
223 	"finstr0B",	mipscoxxx,
224 	"round.w.%f",	mipscofp2,
225 	"trunc.w%f",	mipscofp2,
226 	"ceil.w%f",	mipscofp2,
227 	"floor.w%f",	mipscofp2,
228 	"finstr10",	mipscoxxx,
229 	"finstr11",	mipscoxxx,
230 	"finstr12",	mipscoxxx,
231 	"finstr13",	mipscoxxx,
232 	"finstr14",	mipscoxxx,
233 	"finstr15",	mipscoxxx,
234 	"finstr16",	mipscoxxx,
235 	"finstr17",	mipscoxxx,
236 	"finstr18",	mipscoxxx,
237 	"finstr19",	mipscoxxx,
238 	"finstr1A",	mipscoxxx,
239 	"finstr1B",	mipscoxxx,
240 	"finstr1C",	mipscoxxx,
241 	"finstr1D",	mipscoxxx,
242 	"finstr1E",	mipscoxxx,
243 	"finstr1F",	mipscoxxx,
244 	"cvt.s.%f",	mipscofp2,
245 	"cvt.d.%f",	mipscofp2,
246 	"cvt.e.%f",	mipscofp2,
247 	"cvt.q.%f",	mipscofp2,
248 	"cvt.w.%f",	mipscofp2,
249 	"finstr25",	mipscoxxx,
250 	"finstr26",	mipscoxxx,
251 	"finstr27",	mipscoxxx,
252 	"finstr28",	mipscoxxx,
253 	"finstr29",	mipscoxxx,
254 	"finstr2A",	mipscoxxx,
255 	"finstr2B",	mipscoxxx,
256 	"finstr2C",	mipscoxxx,
257 	"finstr2D",	mipscoxxx,
258 	"finstr2E",	mipscoxxx,
259 	"finstr2F",	mipscoxxx,
260 	"c.f.%f",	mipscofpc,
261 	"c.un.%f",	mipscofpc,
262 	"c.eq.%f",	mipscofpc,
263 	"c.ueq.%f",	mipscofpc,
264 	"c.olt.%f",	mipscofpc,
265 	"c.ult.%f",	mipscofpc,
266 	"c.ole.%f",	mipscofpc,
267 	"c.ule.%f",	mipscofpc,
268 	"c.sf.%f",	mipscofpc,
269 	"c.ngle.%f",	mipscofpc,
270 	"c.seq.%f",	mipscofpc,
271 	"c.ngl.%f",	mipscofpc,
272 	"c.lt.%f",	mipscofpc,
273 	"c.nge.%f",	mipscofpc,
274 	"c.le.%f",	mipscofpc,
275 	"c.ngt.%f",	mipscofpc,
276 };
277 
278 static char fsub[16] = {
279 	's', 'd', 'e', 'q', 'w', '?', '?', '?',
280 	'?', '?', '?', '?', '?', '?', '?', '?'
281 };
282 
283 
284 static int
mkinstr(Instr * i,Map * map,uvlong pc)285 mkinstr(Instr *i, Map *map, uvlong pc)
286 {
287 	ulong w;
288 
289 	if (get4(map, pc, &w) < 0) {
290 		werrstr("can't read instruction: %r");
291 		return -1;
292 	}
293 	i->addr = pc;
294 	i->op = (w >> 26) & 0x3F;
295 	i->rs = (w >> 21) & 0x1F;
296 	i->rt = (w >> 16) & 0x1F;
297 	i->rd = (w >> 11) & 0x1F;
298 	i->sa = (w >> 6) & 0x1F;
299 	i->function = w & 0x3F;
300 	i->immediate = w & 0x0000FFFF;
301 	if (i->immediate & 0x8000)
302 		i->immediate |= ~0x0000FFFF;
303 	i->cofun = w & 0x01FFFFFF;
304 	i->target = w & 0x03FFFFFF;
305 	i->w0 = w;
306 	return 1;
307 }
308 
309 #pragma	varargck	argpos	bprint		2
310 
311 static void
bprint(Instr * i,char * fmt,...)312 bprint(Instr *i, char *fmt, ...)
313 {
314 	va_list arg;
315 
316 	va_start(arg, fmt);
317 	i->curr = vseprint(i->curr, i->end, fmt, arg);
318 	va_end(arg);
319 }
320 
321 static void
format(char * mnemonic,Instr * i,char * f)322 format(char *mnemonic, Instr *i, char *f)
323 {
324 	if (mnemonic)
325 		format(0, i, mnemonic);
326 	if (f == 0)
327 		return;
328 	if (i->curr < i->end)
329 		*i->curr++ = '\t';
330 	for ( ; *f && i->curr < i->end; f++) {
331 		if (*f != '%') {
332 			*i->curr++ = *f;
333 			continue;
334 		}
335 		switch (*++f) {
336 
337 		case 's':
338 			bprint(i, "%d", i->rs);
339 			break;
340 
341 		case 't':
342 			bprint(i, "%d", i->rt);
343 			break;
344 
345 		case 'd':
346 			bprint(i, "%d", i->rd);
347 			break;
348 
349 		case 'a':
350 			bprint(i, "%d", i->sa);
351 			break;
352 
353 		case 'l':
354 			if (i->rs == 30) {
355 				i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
356 				bprint(i, "(SB)");
357 			} else
358 				bprint(i, "%lx(r%d)", i->immediate, i->rs);
359 			break;
360 
361 		case 'i':
362 			bprint(i, "$%lx", i->immediate);
363 			break;
364 
365 		case 'u':
366 			*i->curr++ = '$';
367 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
368 			bprint(i, "(SB)");
369 			break;
370 
371 		case 'j':
372 			i->curr += symoff(i->curr, i->end-i->curr,
373 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
374 			bprint(i, "(SB)");
375 			break;
376 
377 		case 'b':
378 			i->curr += symoff(i->curr, i->end-i->curr,
379 				(i->immediate<<2)+i->addr+4, CANY);
380 			break;
381 
382 		case 'c':
383 			bprint(i, "%lux", i->cofun);
384 			break;
385 
386 		case 'w':
387 			bprint(i, "[%lux]", i->w0);
388 			break;
389 
390 		case 'f':
391 			*i->curr++ = fsub[i->rs & 0x0F];
392 			break;
393 
394 		case '\0':
395 			*i->curr++ = '%';
396 			return;
397 
398 		default:
399 			bprint(i, "%%%c", *f);
400 			break;
401 		}
402 	}
403 }
404 
405 static void
copz(int cop,Instr * i)406 copz(int cop, Instr *i)
407 {
408 	char *f, *m, buf[16];
409 
410 	m = buf;
411 	f = "%t,%d";
412 	switch (i->rs) {
413 
414 	case 0:
415 		sprint(buf, "mfc%d", cop);
416 		break;
417 
418 	case 2:
419 		sprint(buf, "cfc%d", cop);
420 		break;
421 
422 	case 4:
423 		sprint(buf, "mtc%d", cop);
424 		break;
425 
426 	case 6:
427 		sprint(buf, "ctc%d", cop);
428 		break;
429 
430 	case 8:
431 		f = "%b";
432 		switch (i->rt) {
433 
434 		case 0:
435 			sprint(buf, "bc%df", cop);
436 			break;
437 
438 		case 1:
439 			sprint(buf, "bc%dt", cop);
440 			break;
441 
442 		case 2:
443 			sprint(buf, "bc%dfl", cop);
444 			break;
445 
446 		case 3:
447 			sprint(buf, "bc%dtl", cop);
448 			break;
449 
450 		default:
451 			sprint(buf, "cop%d", cop);
452 			f = mipscoxxx;
453 			break;
454 		}
455 		break;
456 
457 	default:
458 		sprint(buf, "cop%d", cop);
459 		if (i->rs & 0x10)
460 			f = "function %c";
461 		else
462 			f = mipscoxxx;
463 		break;
464 	}
465 	format(m, i, f);
466 }
467 
468 static void
cop0(Instr * i)469 cop0(Instr *i)
470 {
471 	char *m = 0;
472 
473 	if (i->rs >= 0x10) {
474 		switch (i->cofun) {
475 
476 		case 1:
477 			m = "tlbr";
478 			break;
479 
480 		case 2:
481 			m = "tlbwi";
482 			break;
483 
484 		case 6:
485 			m = "tlbwr";
486 			break;
487 
488 		case 8:
489 			m = "tlbp";
490 			break;
491 
492 		case 16:
493 			m = "rfe";
494 			break;
495 
496 		case 24:
497 			m = "eret";
498 			break;
499 
500 		case 32:
501 			m = "wait";
502 			break;
503 		}
504 		if (m) {
505 			format(m, i, 0);
506 			if (i->curr < i->end)
507 				*i->curr++ = 0;
508 			return;
509 		}
510 	}
511 	copz(0, i);
512 }
513 
514 int
_mipscoinst(Map * map,uvlong pc,char * buf,int n)515 _mipscoinst(Map *map, uvlong pc, char *buf, int n)
516 {
517 	Instr i;
518 	Opcode *o;
519 	uchar op;
520 
521 	i.curr = buf;
522 	i.end = buf+n-1;
523 	if (mkinstr(&i, map, pc) < 0)
524 		return -1;
525 	switch (i.op) {
526 
527 	case 0x00:					/* SPECIAL */
528 		o = sopcodes;
529 		op = i.function;
530 		break;
531 
532 	case 0x01:					/* REGIMM */
533 		o = ropcodes;
534 		op = i.rt;
535 		break;
536 
537 	case 0x10:					/* COP0 */
538 		cop0(&i);
539 		return 4;
540 
541 	case 0x11:					/* COP1 */
542 		if (i.rs & 0x10) {
543 			o = fopcodes;
544 			op = i.function;
545 			break;
546 		}
547 		/*FALLTHROUGH*/
548 	case 0x12:					/* COP2 */
549 	case 0x13:					/* COP3 */
550 		copz(i.op-0x10, &i);
551 		return 4;
552 
553 	default:
554 		o = opcodes;
555 		op = i.op;
556 		break;
557 	}
558 	format(o[op].mnemonic, &i, o[op].mipsco);
559 	return 4;
560 }
561