xref: /inferno-os/utils/libmach/kdb.c (revision 7de2b42d50e3c05cc143e7b51284009b5e185581)
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