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