]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/udb.c
marshal(1): fix example: upas/mail -> mail (thanks fulton)
[plan9front.git] / sys / src / libmach / udb.c
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*
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*
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
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
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
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
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
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
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
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
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
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
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
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
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
637 bra(Instr *i, char *m)                  /* page 91 */
638 {
639         bra1(i, m, bratab);
640 }
641
642 static void
643 fbra(Instr *i, char *m)                 /* page 93 */
644 {
645         bra1(i, m, fbratab);
646 }
647
648 static void
649 cbra(Instr *i, char *m)                 /* page 95 */
650 {
651         bra1(i, m, cbratab);
652 }
653
654 static void
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
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*
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }