xref: /plan9/sys/src/libmach/kdb.c (revision 1bd2810994d48c5034925d24ca0b90739454b582)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 /*
7  * Sparc-specific debugger interface
8  */
9 
10 static	char	*sparcexcep(Map*, Rgetter);
11 static	int	sparcfoll(Map*, uvlong, Rgetter, uvlong*);
12 static	int	sparcinst(Map*, uvlong, char, char*, int);
13 static	int	sparcdas(Map*, uvlong, char*, int);
14 static	int	sparcinstlen(Map*, uvlong);
15 
16 Machdata sparcmach =
17 {
18 	{0x91, 0xd0, 0x20, 0x01},	/* breakpoint: TA $1 */
19 	4,			/* break point size */
20 
21 	beswab,			/* convert short to local byte order */
22 	beswal,			/* convert long to local byte order */
23 	beswav,			/* convert vlong to local byte order */
24 	risctrace,		/* C traceback */
25 	riscframe,		/* frame finder */
26 	sparcexcep,		/* print exception */
27 	0,			/* breakpoint fixup */
28 	beieeesftos,		/* single precision float printer */
29 	beieeedftos,		/* double precision float printer */
30 	sparcfoll,		/* following addresses */
31 	sparcinst,		/* print instruction */
32 	sparcdas,		/* dissembler */
33 	sparcinstlen,		/* instruction size */
34 };
35 
36 static char *trapname[] =
37 {
38 	"reset",
39 	"instruction access exception",
40 	"illegal instruction",
41 	"privileged instruction",
42 	"fp disabled",
43 	"window overflow",
44 	"window underflow",
45 	"unaligned address",
46 	"fp exception",
47 	"data access exception",
48 	"tag overflow",
49 };
50 
51 static char*
excname(ulong tbr)52 excname(ulong tbr)
53 {
54 	static char buf[32];
55 
56 	if(tbr < sizeof trapname/sizeof(char*))
57 		return trapname[tbr];
58 	if(tbr >= 130)
59 		sprint(buf, "trap instruction %ld", tbr-128);
60 	else if(17<=tbr && tbr<=31)
61 		sprint(buf, "interrupt level %ld", tbr-16);
62 	else switch(tbr){
63 	case 36:
64 		return "cp disabled";
65 	case 40:
66 		return "cp exception";
67 	case 128:
68 		return "syscall";
69 	case 129:
70 		return "breakpoint";
71 	default:
72 		sprint(buf, "unknown trap %ld", tbr);
73 	}
74 	return buf;
75 }
76 
77 static char*
sparcexcep(Map * map,Rgetter rget)78 sparcexcep(Map *map, Rgetter rget)
79 {
80 	long tbr;
81 
82 	tbr = (*rget)(map, "TBR");
83 	tbr = (tbr&0xFFF)>>4;
84 	return excname(tbr);
85 }
86 
87 	/* Sparc disassembler and related functions */
88 
89 struct opcode {
90 	char	*mnemonic;
91 	void	(*f)(struct instr*, char*);
92 	int	flag;
93 };
94 
95 static	char FRAMENAME[] = ".frame";
96 
97 typedef struct instr Instr;
98 
99 struct instr {
100 	uchar	op;		/* bits 31-30 */
101 	uchar	rd;		/* bits 29-25 */
102 	uchar	op2;		/* bits 24-22 */
103 	uchar	a;		/* bit  29    */
104 	uchar	cond;		/* bits 28-25 */
105 	uchar	op3;		/* bits 24-19 */
106 	uchar	rs1;		/* bits 18-14 */
107 	uchar	i;		/* bit  13    */
108 	uchar	asi;		/* bits 12-05 */
109 	uchar	rs2;		/* bits 04-00 */
110 	short	simm13;		/* bits 12-00, signed */
111 	ushort	opf;		/* bits 13-05 */
112 	ulong	immdisp22;	/* bits 21-00 */
113 	ulong	simmdisp22;	/* bits 21-00, signed */
114 	ulong	disp30;		/* bits 30-00 */
115 	ulong	imm32;		/* SETHI+ADD constant */
116 	int	target;		/* SETHI+ADD dest reg */
117 	long	w0;
118 	long	w1;
119 	uvlong	addr;		/* pc of instruction */
120 	char	*curr;		/* current fill level in output buffer */
121 	char	*end;		/* end of buffer */
122 	int 	size;		/* number of longs in instr */
123 	char	*err;		/* errmsg */
124 };
125 
126 static	Map	*mymap;		/* disassembler context */
127 static	int	dascase;
128 
129 static int	mkinstr(uvlong, Instr*);
130 static void	bra1(Instr*, char*, char*[]);
131 static void	bra(Instr*, char*);
132 static void	fbra(Instr*, char*);
133 static void	cbra(Instr*, char*);
134 static void	unimp(Instr*, char*);
135 static void	fpop(Instr*, char*);
136 static void	shift(Instr*, char*);
137 static void	sethi(Instr*, char*);
138 static void	load(Instr*, char*);
139 static void	loada(Instr*, char*);
140 static void	store(Instr*, char*);
141 static void	storea(Instr*, char*);
142 static void	add(Instr*, char*);
143 static void	cmp(Instr*, char*);
144 static void	wr(Instr*, char*);
145 static void	jmpl(Instr*, char*);
146 static void	rd(Instr*, char*);
147 static void	loadf(Instr*, char*);
148 static void	storef(Instr*, char*);
149 static void	loadc(Instr*, char*);
150 static void	loadcsr(Instr*, char*);
151 static void	trap(Instr*, char*);
152 
153 static struct opcode sparcop0[8] = {
154 	[0]	"UNIMP",	unimp,	0,	/* page 137 */
155 	[2]	"B",		bra,	0,	/* page 119 */
156 	[4]	"SETHI",	sethi,	0,	/* page 104 */
157 	[6]	"FB",		fbra,	0,	/* page 121 */
158 	[7]	"CB",		cbra,	0,	/* page 123 */
159 };
160 
161 static struct opcode sparcop2[64] = {
162 	[0x00]	"ADD",		add,	0,	/* page 108 */
163 	[0x10]	"ADDCC",	add,	0,
164 	[0x08]	"ADDX",		add,	0,
165 	[0x18]	"ADDXCC",	add,	0,
166 
167 	[0x20]	"TADD",		add,	0,	/* page 109 */
168 	[0x22]	"TADDCCTV",	add,	0,
169 
170 	[0x04]	"SUB",		add,	0,	/* page 110 */
171 	[0x14]	"SUBCC",	cmp,	0,
172 	[0x0C]	"SUBX",		add,	0,
173 	[0x1C]	"SUBXCC",	add,	0,
174 
175 	[0x21]	"TSUB",		add,	0,	/* page 111 */
176 	[0x23]	"TSUBCCTV",	add,	0,
177 
178 	[0x24]	"MULSCC",	add,	0,	/* page 112 */
179 
180 	[0x0A]	"UMUL",		add,	0,	/* page 113 */
181 	[0x0B]	"SMUL",		add,	0,
182 	[0x1A]	"UMULCC",	add,	0,
183 	[0x1B]	"SMULCC",	add,	0,
184 
185 	[0x0E]	"UDIV",		add,	0,	/* page 115 */
186 	[0x0F]	"SDIV",		add,	0,
187 	[0x1E]	"UDIVCC",	add,	0,
188 	[0x1F]	"SDIVCC",	add,	0,
189 
190 	[0x01]	"AND",		add,	0,	/* page 106 */
191 	[0x11]	"ANDCC",	add,	0,
192 	[0x05]	"ANDN",		add,	0,
193 	[0x15]	"ANDNCC",	add,	0,
194 	[0x02]	"OR",		add,	0,
195 	[0x12]	"ORCC",		add,	0,
196 	[0x06]	"ORN",		add,	0,
197 	[0x16]	"ORNCC",	add,	0,
198 	[0x03]	"XOR",		add,	0,
199 	[0x13]	"XORCC",	add,	0,
200 	[0x07]	"XORN",		add,	0,
201 	[0x17]	"XORNCC",	add,	0,
202 
203 	[0x25]	"SLL",		shift,	0,	/* page 107 */
204 	[0x26]	"SRL",		shift,	0,
205 	[0x27]	"SRA",		shift,	0,
206 
207 	[0x3C]	"SAVE",		add,	0,	/* page 117 */
208 	[0x3D]	"RESTORE",	add,	0,
209 
210 	[0x38]	"JMPL",		jmpl,	0,	/* page 126 */
211 
212 	[0x39]	"RETT",		add,	0,	/* page 127 */
213 
214 	[0x3A]	"T",		trap,	0,	/* page 129 */
215 
216 	[0x28]	"rdy",		rd,	0,	/* page 131 */
217 	[0x29]	"rdpsr",	rd,	0,
218 	[0x2A]	"rdwim",	rd,	0,
219 	[0x2B]	"rdtbr",	rd,	0,
220 
221 	[0x30]	"wry",		wr,	0,	/* page 133 */
222 	[0x31]	"wrpsr",	wr,	0,
223 	[0x32]	"wrwim",	wr,	0,
224 	[0x33]	"wrtbr",	wr,	0,
225 
226 	[0x3B]	"flush",	add,	0,	/* page 138 */
227 
228 	[0x34]	"FPOP",		fpop,	0,	/* page 140 */
229 	[0x35]	"FPOP",		fpop,	0,
230 };
231 
232 static struct opcode sparcop3[64]={
233 	[0x09]	"ldsb",		load,	0,	/* page 90 */
234 	[0x19]	"ldsba",	loada,	0,
235 	[0x0A]	"ldsh",		load,	0,
236 	[0x1A]	"ldsha",	loada,	0,
237 	[0x01]	"ldub",		load,	0,
238 	[0x11]	"lduba",	loada,	0,
239 	[0x02]	"lduh",		load,	0,
240 	[0x12]	"lduha",	loada,	0,
241 	[0x00]	"ld",		load,	0,
242 	[0x10]	"lda",		loada,	0,
243 	[0x03]	"ldd",		load,	0,
244 	[0x13]	"ldda",		loada,	0,
245 
246 	[0x20]	"ldf",		loadf,	0,	/* page 92 */
247 	[0x23]	"lddf",		loadf,	0,
248 	[0x21]	"ldfsr",	loadf,0,
249 
250 	[0x30]	"ldc",		loadc,	0,	/* page 94 */
251 	[0x33]	"lddc",		loadc,	0,
252 	[0x31]	"ldcsr",	loadcsr,0,
253 
254 	[0x05]	"stb",		store,	0,	/* page 95 */
255 	[0x15]	"stba",		storea,	0,
256 	[0x06]	"sth",		store,	0,
257 	[0x16]	"stha",		storea,	0,
258 	[0x04]	"st",		store,	0,
259 	[0x14]	"sta",		storea,	0,
260 	[0x07]	"std",		store,	0,
261 	[0x17]	"stda",		storea,	0,
262 
263 	[0x24]	"stf",		storef,	0,	/* page 97 */
264 	[0x27]	"stdf",		storef,	0,
265 	[0x25]	"stfsr",	storef,0,
266 	[0x26]	"stdfq",	storef,0,
267 
268 	[0x34]	"stc",		loadc,	0,	/* page 99 */
269 	[0x37]	"stdc",		loadc,	0,
270 	[0x35]	"stcsr",	loadcsr,0,
271 	[0x36]	"stdcq",	loadcsr,0,
272 
273 	[0x0D]	"ldstub",	store,	0,	/* page 101 */
274 	[0x1D]	"ldstuba",	storea,	0,
275 
276 	[0x0F]	"swap",		load,	0,	/* page 102 */
277 	[0x1F]	"swapa",	loada,	0,
278 };
279 
280 #pragma	varargck	argpos	bprint	2
281 #pragma	varargck	type	"T"	char*
282 
283 /* convert to lower case from upper, according to dascase */
284 static int
Tfmt(Fmt * f)285 Tfmt(Fmt *f)
286 {
287 	char buf[128];
288 	char *s, *t, *oa;
289 
290 	oa = va_arg(f->args, char*);
291 	if(dascase){
292 		for(s=oa,t=buf; *t = *s; s++,t++)
293 			if('A'<=*t && *t<='Z')
294 				*t += 'a'-'A';
295 		return fmtstrcpy(f, buf);
296 	}
297 	return fmtstrcpy(f, oa);
298 }
299 
300 static void
bprint(Instr * i,char * fmt,...)301 bprint(Instr *i, char *fmt, ...)
302 {
303 	va_list arg;
304 
305 	va_start(arg, fmt);
306 	i->curr = vseprint(i->curr, i->end, fmt, arg);
307 	va_end(arg);
308 }
309 
310 static int
decode(uvlong pc,Instr * i)311 decode(uvlong pc, Instr *i)
312 {
313 	ulong w;
314 
315 	if (get4(mymap, pc, &w) < 0) {
316 		werrstr("can't read instruction: %r");
317 		return -1;
318 	}
319 	i->op = (w >> 30) & 0x03;
320 	i->rd = (w >> 25) & 0x1F;
321 	i->op2 = (w >> 22) & 0x07;
322 	i->a = (w >> 29) & 0x01;
323 	i->cond = (w >> 25) & 0x0F;
324 	i->op3 = (w >> 19) & 0x3F;
325 	i->rs1 = (w >> 14) & 0x1F;
326 	i->i = (w >> 13) & 0x01;
327 	i->asi = (w >> 5) & 0xFF;
328 	i->rs2 = (w >> 0) & 0x1F;
329 	i->simm13 = (w >> 0) & 0x1FFF;
330 	if(i->simm13 & (1<<12))
331 		i->simm13 |= ~((1<<13)-1);
332 	i->opf = (w >> 5) & 0x1FF;
333 	i->immdisp22 = (w >> 0) & 0x3FFFFF;
334 	i->simmdisp22 = i->immdisp22;
335 	if(i->simmdisp22 & (1<<21))
336 		i->simmdisp22 |= ~((1<<22)-1);
337 	i->disp30 = (w >> 0) & 0x3FFFFFFF;
338 	i->w0 = w;
339 	i->target = -1;
340 	i->addr = pc;
341 	i->size = 1;
342 	return 1;
343 }
344 
345 static int
mkinstr(uvlong pc,Instr * i)346 mkinstr(uvlong pc, Instr *i)
347 {
348 	Instr xi;
349 
350 	if (decode(pc, i) < 0)
351 		return -1;
352 	if(i->op==0 && i->op2==4 && !dascase){	/* SETHI */
353 		if (decode(pc+4, &xi) < 0)
354 			return -1;
355 		if(xi.op==2 && xi.op3==0)		/* ADD */
356 		if(xi.i == 1 && xi.rs1 == i->rd){	/* immediate to same reg */
357 			i->imm32 = xi.simm13 + (i->immdisp22<<10);
358 			i->target = xi.rd;
359 			i->w1 = xi.w0;
360 			i->size++;
361 			return 1;
362 		}
363 	}
364 	if(i->op==2 && i->opf==1 && !dascase){	/* FMOVS */
365 		if (decode(pc+4, &xi) < 0)
366 			return -1;
367 		if(i->op==2 && i->opf==1)		/* FMOVS */
368 		if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){	/* next pair */
369 			i->w1 = xi.w0;
370 			i->size++;
371 		}
372 	}
373 	return 1;
374 }
375 
376 static int
printins(Map * map,uvlong pc,char * buf,int n)377 printins(Map *map, uvlong pc, char *buf, int n)
378 {
379 	Instr instr;
380 	void (*f)(Instr*, char*);
381 
382 	mymap = map;
383 	memset(&instr, 0, sizeof(instr));
384 	instr.curr = buf;
385 	instr.end = buf+n-1;
386 	if (mkinstr(pc, &instr) < 0)
387 		return -1;
388 	switch(instr.op){
389 	case 0:
390 		f = sparcop0[instr.op2].f;
391 		if(f)
392 			(*f)(&instr, sparcop0[instr.op2].mnemonic);
393 		else
394 			bprint(&instr, "unknown %lux", instr.w0);
395 		break;
396 
397 	case 1:
398 		bprint(&instr, "%T", "CALL\t");
399 		instr.curr += symoff(instr.curr, instr.end-instr.curr,
400 					pc+instr.disp30*4, CTEXT);
401 		if (!dascase)
402 			bprint(&instr, "(SB)");
403 		break;
404 
405 	case 2:
406 		f = sparcop2[instr.op3].f;
407 		if(f)
408 			(*f)(&instr, sparcop2[instr.op3].mnemonic);
409 		else
410 			bprint(&instr, "unknown %lux", instr.w0);
411 		break;
412 
413 	case 3:
414 		f = sparcop3[instr.op3].f;
415 		if(f)
416 			(*f)(&instr, sparcop3[instr.op3].mnemonic);
417 		else
418 			bprint(&instr, "unknown %lux", instr.w0);
419 		break;
420 	}
421 	if (instr.err) {
422 		if (instr.curr != buf)
423 			bprint(&instr, "\t\t;");
424 		bprint(&instr, instr.err);
425 	}
426 	return instr.size*4;
427 }
428 
429 static int
sparcinst(Map * map,uvlong pc,char modifier,char * buf,int n)430 sparcinst(Map *map, uvlong pc, char modifier, char *buf, int n)
431 {
432 	static int fmtinstalled = 0;
433 
434 		/* a modifier of 'I' toggles the dissassembler type */
435 	if (!fmtinstalled) {
436 		fmtinstalled = 1;
437 		fmtinstall('T', Tfmt);
438 	}
439 	if ((asstype == ASUNSPARC && modifier == 'i')
440 		|| (asstype == ASPARC && modifier == 'I'))
441 		dascase = 'a'-'A';
442 	else
443 		dascase = 0;
444 	return printins(map, pc, buf, n);
445 }
446 
447 static int
sparcdas(Map * map,uvlong pc,char * buf,int n)448 sparcdas(Map *map, uvlong pc, char *buf, int n)
449 {
450 	Instr instr;
451 
452 	mymap = map;
453 	memset(&instr, 0, sizeof(instr));
454 	instr.curr = buf;
455 	instr.end = buf+n-1;
456 	if (mkinstr(pc, &instr) < 0)
457 		return -1;
458 	if (instr.end-instr.curr > 8)
459 		instr.curr = _hexify(instr.curr, instr.w0, 7);
460 	if (instr.end-instr.curr > 9 && instr.size == 2) {
461 		*instr.curr++ = ' ';
462 		instr.curr = _hexify(instr.curr, instr.w1, 7);
463 	}
464 	*instr.curr = 0;
465 	return instr.size*4;
466 }
467 
468 static int
sparcinstlen(Map * map,uvlong pc)469 sparcinstlen(Map *map, uvlong pc)
470 {
471 	Instr i;
472 
473 	mymap = map;
474 	if (mkinstr(pc, &i) < 0)
475 		return -1;
476 	return i.size*4;
477 }
478 
479 static int
plocal(Instr * i)480 plocal(Instr *i)
481 {
482 	int offset;
483 	Symbol s;
484 
485 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
486 		return -1;
487 	if (s.value > i->simm13) {
488 		if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
489 			bprint(i, "%s+%lld(SP)", s.name, s.value);
490 			return 1;
491 		}
492 	} else {
493 		offset = i->simm13-s.value;
494 		if (getauto(&s, offset-4, CPARAM, &s)) {
495 			bprint(i, "%s+%d(FP)", s.name, offset);
496 			return 1;
497 		}
498 	}
499 	return -1;
500 }
501 
502 static void
address(Instr * i)503 address(Instr *i)
504 {
505 	Symbol s, s2;
506 	uvlong off, off1;
507 
508 	if (i->rs1 == 1 && plocal(i) >= 0)
509 		return;
510 	off = mach->sb+i->simm13;
511 	if(i->rs1 == 2	&& findsym(off, CANY, &s)
512 			&& s.value-off < 4096
513 			&& (s.class == CDATA || s.class == CTEXT)) {
514 		if(off==s.value && s.name[0]=='$'){
515 			off1 = 0;
516 			geta(mymap, s.value, &off1);
517 			if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
518 				bprint(i, "$%s(SB)", s2.name);
519 				return;
520 			}
521 		}
522 		bprint(i, "%s", s.name);
523 		if (s.value != off)
524 			bprint(i, "+%llux", s.value-off);
525 		bprint(i, "(SB)");
526 		return;
527 	}
528 	bprint(i, "%ux(R%d)", i->simm13, i->rs1);
529 }
530 
531 static void
unimp(Instr * i,char * m)532 unimp(Instr *i, char *m)
533 {
534 	bprint(i, "%T", m);
535 }
536 
537 static char	*bratab[16] = {	/* page 91 */
538 	[0X8]	"A",
539 	[0X0]	"N",
540 	[0X9]	"NE",
541 	[0X1]	"E",
542 	[0XA]	"G",
543 	[0X2]	"LE",
544 	[0XB]	"GE",
545 	[0X3]	"L",
546 	[0XC]	"GU",
547 	[0X4]	"LEU",
548 	[0XD]	"CC",
549 	[0X5]	"CS",
550 	[0XE]	"POS",
551 	[0X6]	"NEG",
552 	[0XF]	"VC",
553 	[0X7]	"VS",
554 };
555 
556 static char	*fbratab[16] = {	/* page 91 */
557 	[0X8]	"A",
558 	[0X0]	"N",
559 	[0X7]	"U",
560 	[0X6]	"G",
561 	[0X5]	"UG",
562 	[0X4]	"L",
563 	[0X3]	"UL",
564 	[0X2]	"LG",
565 	[0X1]	"NE",
566 	[0X9]	"E",
567 	[0XA]	"UE",
568 	[0XB]	"GE",
569 	[0XC]	"UGE",
570 	[0XD]	"LE",
571 	[0XE]	"ULE",
572 	[0XF]	"O",
573 };
574 
575 static char	*cbratab[16] = {	/* page 91 */
576 	[0X8]	"A",
577 	[0X0]	"N",
578 	[0X7]	"3",
579 	[0X6]	"2",
580 	[0X5]	"23",
581 	[0X4]	"1",
582 	[0X3]	"13",
583 	[0X2]	"12",
584 	[0X1]	"123",
585 	[0X9]	"0",
586 	[0XA]	"03",
587 	[0XB]	"02",
588 	[0XC]	"023",
589 	[0XD]	"01",
590 	[0XE]	"013",
591 	[0XF]	"012",
592 };
593 
594 static void
bra1(Instr * i,char * m,char * tab[])595 bra1(Instr *i, char *m, char *tab[])
596 {
597 	long imm;
598 
599 	imm = i->simmdisp22;
600 	if(i->a)
601 		bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase);
602 	else
603 		bprint(i, "%T%T\t", m, tab[i->cond]);
604 	i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
605 	if (!dascase)
606 		bprint(i, "(SB)");
607 }
608 
609 static void
bra(Instr * i,char * m)610 bra(Instr *i, char *m)			/* page 91 */
611 {
612 	bra1(i, m, bratab);
613 }
614 
615 static void
fbra(Instr * i,char * m)616 fbra(Instr *i, char *m)			/* page 93 */
617 {
618 	bra1(i, m, fbratab);
619 }
620 
621 static void
cbra(Instr * i,char * m)622 cbra(Instr *i, char *m)			/* page 95 */
623 {
624 	bra1(i, m, cbratab);
625 }
626 
627 static void
trap(Instr * i,char * m)628 trap(Instr *i, char *m)			/* page 101 */
629 {
630 	if(i->i == 0)
631 		bprint(i, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
632 	else
633 		bprint(i, "%T%T\t$%ux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
634 }
635 
636 static void
sethi(Instr * i,char * m)637 sethi(Instr *i, char *m)		/* page 89 */
638 {
639 	ulong imm;
640 
641 	imm = i->immdisp22<<10;
642 	if(dascase){
643 		bprint(i, "%T\t%lux, R%d", m, imm, i->rd);
644 		return;
645 	}
646 	if(imm==0 && i->rd==0){
647 		bprint(i, "NOP");
648 		return;
649 	}
650 	if(i->target < 0){
651 		bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
652 		return;
653 	}
654 	bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
655 }
656 
657 static char ldtab[] = {
658 	'W',
659 	'B',
660 	'H',
661 	'D',
662 };
663 
664 static char*
moveinstr(int op3,char * m)665 moveinstr(int op3, char *m)
666 {
667 	char *s;
668 	int c;
669 	static char buf[8];
670 
671 	if(!dascase){
672 		/* batshit cases */
673 		if(op3 == 0xF || op3 == 0x1F)
674 			return "SWAP";
675 		if(op3 == 0xD || op3 == 0x1D)
676 			return "TAS";	/* really LDSTUB */
677 		c = ldtab[op3&3];
678 		s = "";
679 		if((op3&11)==1 || (op3&11)==2)
680 			s="U";
681 		sprint(buf, "MOV%c%s", c, s);
682 		return buf;
683 	}
684 	return m;
685 }
686 
687 static void
load(Instr * i,char * m)688 load(Instr *i, char *m)			/* page 68 */
689 {
690 	m = moveinstr(i->op3, m);
691 	if(i->i == 0)
692 		bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
693 	else{
694 		bprint(i, "%s\t", m);
695 		address(i);
696 		bprint(i, ", R%d", i->rd);
697 	}
698 }
699 
700 static void
loada(Instr * i,char * m)701 loada(Instr *i, char *m)		/* page 68 */
702 {
703 	m = moveinstr(i->op3, m);
704 	if(i->i == 0)
705 		bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
706 	else
707 		bprint(i, "unknown ld asi %lux", i->w0);
708 }
709 
710 static void
store(Instr * i,char * m)711 store(Instr *i, char *m)		/* page 74 */
712 {
713 	m = moveinstr(i->op3, m);
714 	if(i->i == 0)
715 		bprint(i, "%s\tR%d, (R%d+R%d)",
716 				m, i->rd, i->rs1, i->rs2);
717 	else{
718 		bprint(i, "%s\tR%d, ", m, i->rd);
719 		address(i);
720 	}
721 }
722 
723 static void
storea(Instr * i,char * m)724 storea(Instr *i, char *m)		/* page 74 */
725 {
726 	m = moveinstr(i->op3, m);
727 	if(i->i == 0)
728 		bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
729 	else
730 		bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
731 }
732 
733 static void
shift(Instr * i,char * m)734 shift(Instr *i, char *m)	/* page 88 */
735 {
736 	if(i->i == 0){
737 		if(i->rs1 == i->rd)
738 			if(dascase)
739 				bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
740 			else
741 				bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
742 		else
743 			if(dascase)
744 				bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
745 			else
746 				bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
747 	}else{
748 		if(i->rs1 == i->rd)
749 			if(dascase)
750 				bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
751 			else
752 				bprint(i, "%T\tR%d, $%d", m,  i->rs1, i->simm13&0x1F);
753 		else
754 			if(dascase)
755 				bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
756 			else
757 				bprint(i, "%T\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
758 	}
759 }
760 
761 static void
add(Instr * i,char * m)762 add(Instr *i, char *m)	/* page 82 */
763 {
764 	if(i->i == 0){
765 		if(dascase)
766 			bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
767 		else
768 			if(i->op3==2 && i->rs1==0 && i->rd)  /* OR R2, R0, R1 */
769 				bprint(i, "MOVW\tR%d", i->rs2);
770 			else
771 				bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
772 	}else{
773 		if(dascase)
774 			bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13);
775 		else
776 			if(i->op3==0 && i->rd && i->rs1==0)	/* ADD $x, R0, R1 */
777 				bprint(i, "MOVW\t$%ux", i->simm13);
778 			else if(i->op3==0 && i->rd && i->rs1==2){
779 				/* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
780 				bprint(i, "MOVW\t$");
781 				address(i);
782 			} else
783 				bprint(i, "%T\t$%ux, R%d", m, i->simm13, i->rs1);
784 	}
785 	if(i->rs1 != i->rd)
786 		bprint(i, ", R%d", i->rd);
787 }
788 
789 static void
cmp(Instr * i,char * m)790 cmp(Instr *i, char *m)
791 {
792 	if(dascase || i->rd){
793 		add(i, m);
794 		return;
795 	}
796 	if(i->i == 0)
797 		bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
798 	else
799 		bprint(i, "CMP\tR%d, $%ux", i->rs1, i->simm13);
800 }
801 
802 static char *regtab[4] = {
803 	"Y",
804 	"PSR",
805 	"WIM",
806 	"TBR",
807 };
808 
809 static void
wr(Instr * i,char * m)810 wr(Instr *i, char *m)		/* page 82 */
811 {
812 	if(dascase){
813 		if(i->i == 0)
814 			bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
815 		else
816 			bprint(i, "%s\tR%d, $%ux", m, i->rs1, i->simm13);
817 	}else{
818 		if(i->i && i->simm13==0)
819 			bprint(i, "MOVW\tR%d", i->rs1);
820 		else if(i->i == 0)
821 			bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
822 		else
823 			bprint(i, "wr\t$%ux, R%d", i->simm13, i->rs1);
824 	}
825 	bprint(i, ", %s", regtab[i->op3&3]);
826 }
827 
828 static void
rd(Instr * i,char * m)829 rd(Instr *i, char *m)		/* page 103 */
830 {
831 	if(i->rs1==15 && i->rd==0){
832 		m = "stbar";
833 		if(!dascase)
834 			m = "STBAR";
835 		bprint(i, "%s", m);
836 	}else{
837 		if(!dascase)
838 			m = "MOVW";
839 		bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
840 	}
841 }
842 
843 static void
jmpl(Instr * i,char * m)844 jmpl(Instr *i, char *m)		/* page 82 */
845 {
846 	if(i->i == 0){
847 		if(i->rd == 15)
848 			bprint(i, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
849 		else
850 			bprint(i, "%T\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
851 	}else{
852 		if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
853 			bprint(i, "RETURN");
854 		else{
855 			bprint(i, "%T\t", m);
856 			address(i);
857 			bprint(i, ", R%d", i->rd);
858 		}
859 	}
860 }
861 
862 static void
loadf(Instr * i,char * m)863 loadf(Instr *i, char *m)		/* page 70 */
864 {
865 	if(!dascase){
866 		m = "FMOVD";
867 		if(i->op3 == 0x20)
868 			m = "FMOVF";
869 		else if(i->op3 == 0x21)
870 			m = "MOVW";
871 	}
872 	if(i->i == 0)
873 		bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
874 	else{
875 		bprint(i, "%s\t", m);
876 		address(i);
877 	}
878 	if(i->op3 == 0x21)
879 		bprint(i, ", FSR");
880 	else
881 		bprint(i, ", R%d", i->rd);
882 }
883 
884 static void
storef(Instr * i,char * m)885 storef(Instr *i, char *m)		/* page 70 */
886 {
887 	if(!dascase){
888 		m = "FMOVD";
889 		if(i->op3 == 0x25 || i->op3 == 0x26)
890 			m = "MOVW";
891 		else if(i->op3 == 0x20)
892 			m = "FMOVF";
893 	}
894 	bprint(i, "%s\t", m);
895 	if(i->op3 == 0x25)
896 		bprint(i, "FSR, ");
897 	else if(i->op3 == 0x26)
898 		bprint(i, "FQ, ");
899 	else
900 		bprint(i, "R%d, ", i->rd);
901 	if(i->i == 0)
902 		bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
903 	else
904 		address(i);
905 }
906 
907 static void
loadc(Instr * i,char * m)908 loadc(Instr *i, char *m)			/* page 72 */
909 {
910 	if(i->i == 0)
911 		bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
912 	else{
913 		bprint(i, "%s\t", m);
914 		address(i);
915 		bprint(i, ", C%d", i->rd);
916 	}
917 }
918 
919 static void
loadcsr(Instr * i,char * m)920 loadcsr(Instr *i, char *m)			/* page 72 */
921 {
922 	if(i->i == 0)
923 		bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
924 	else{
925 		bprint(i, "%s\t", m);
926 		address(i);
927 		bprint(i, ", CSR");
928 	}
929 }
930 
931 static struct{
932 	int	opf;
933 	char	*name;
934 } fptab1[] = {			/* ignores rs1 */
935 	0xC4,	"FITOS",	/* page 109 */
936 	0xC8,	"FITOD",
937 	0xCC,	"FITOX",
938 
939 	0xD1,	"FSTOI",	/* page 110 */
940 	0xD2,	"FDTOI",
941 	0xD3,	"FXTOI",
942 
943 	0xC9,	"FSTOD",	/* page 111 */
944 	0xCD,	"FSTOX",
945 	0xC6,	"FDTOS",
946 	0xCE,	"FDTOX",
947 	0xC7,	"FXTOS",
948 	0xCB,	"FXTOD",
949 
950 	0x01,	"FMOVS",	/* page 112 */
951 	0x05,	"FNEGS",
952 	0x09,	"FABSS",
953 
954 	0x29,	"FSQRTS", 	/* page 113 */
955 	0x2A,	"FSQRTD",
956 	0x2B,	"FSQRTX",
957 
958 	0,	0,
959 };
960 
961 static struct{
962 	int	opf;
963 	char	*name;
964 } fptab2[] = {			/* uses rs1 */
965 
966 	0x41,	"FADDS",	/* page 114 */
967 	0x42,	"FADDD",
968 	0x43,	"FADDX",
969 	0x45,	"FSUBS",
970 	0x46,	"FSUBD",
971 	0x47,	"FSUBX",
972 
973 	0x49,	"FMULS",	/* page 115 */
974 	0x4A,	"FMULD",
975 	0x4B,	"FMULX",
976 	0x4D,	"FDIVS",
977 	0x4E,	"FDIVD",
978 	0x4F,	"FDIVX",
979 
980 	0x51,	"FCMPS",	/* page 116 */
981 	0x52,	"FCMPD",
982 	0x53,	"FCMPX",
983 	0x55,	"FCMPES",
984 	0x56,	"FCMPED",
985 	0x57,	"FCMPEX",
986 
987 	0, 0
988 };
989 
990 static void
fpop(Instr * i,char * m)991 fpop(Instr *i, char *m)	/* page 108-116 */
992 {
993 	int j;
994 
995 	if(dascase==0 && i->size==2){
996 		bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
997 		return;
998 	}
999 	for(j=0; fptab1[j].name; j++)
1000 		if(fptab1[j].opf == i->opf){
1001 			bprint(i, "%T\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
1002 			return;
1003 		}
1004 	for(j=0; fptab2[j].name; j++)
1005 		if(fptab2[j].opf == i->opf){
1006 			bprint(i, "%T\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
1007 			return;
1008 		}
1009 	bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
1010 }
1011 
1012 static int
sparcfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)1013 sparcfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1014 {
1015 	ulong w, r1, r2;
1016 	char buf[8];
1017 	Instr i;
1018 
1019 	mymap = map;
1020 	if (mkinstr(pc, &i) < 0)
1021 		return -1;
1022 	w = i.w0;
1023 	switch(w & 0xC1C00000){
1024 	case 0x00800000:		/* branch on int cond */
1025 	case 0x01800000:		/* branch on fp cond */
1026 	case 0x01C00000:		/* branch on copr cond */
1027 		foll[0] = pc+8;
1028 		foll[1] = pc + (i.simmdisp22<<2);
1029 		return 2;
1030 	}
1031 
1032 	if((w&0xC0000000) == 0x40000000){	/* CALL */
1033 		foll[0] = pc + (i.disp30<<2);
1034 		return 1;
1035 	}
1036 
1037 	if((w&0xC1F80000) == 0x81C00000){	/* JMPL */
1038 		sprint(buf, "R%ld", (w>>14)&0xF);
1039 		r1 = (*rget)(map, buf);
1040 		if(w & 0x2000)			/* JMPL R1+simm13 */
1041 			r2 = i.simm13;
1042 		else{				/* JMPL R1+R2 */
1043 			sprint(buf, "R%ld", w&0xF);
1044 			r2 = (*rget)(map, buf);
1045 		}
1046 		foll[0] = r1 + r2;
1047 		return 1;
1048 	}
1049 	foll[0] = pc+i.size*4;
1050 	return 1;
1051 }
1052