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