7 * Sparc-specific debugger interface
10 static char *sparcexcep(Map*, Rgetter);
11 static int sparcfoll(Map*, uvlong, Rgetter, uvlong*);
12 static int sparcinst(Map*, uvlong, char, char*, int);
13 static int sparcdas(Map*, uvlong, char*, int);
14 static int sparcinstlen(Map*, uvlong);
18 {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */
19 4, /* break point size */
21 beswab, /* convert short to local byte order */
22 beswal, /* convert long to local byte order */
23 beswav, /* convert vlong to local byte order */
24 risctrace, /* C traceback */
25 riscframe, /* frame finder */
26 sparcexcep, /* print exception */
27 0, /* breakpoint fixup */
28 beieeesftos, /* single precision float printer */
29 beieeedftos, /* double precision float printer */
30 sparcfoll, /* following addresses */
31 sparcinst, /* print instruction */
32 sparcdas, /* dissembler */
33 sparcinstlen, /* instruction size */
36 static char *trapname[] =
39 "instruction access exception",
40 "illegal instruction",
41 "privileged instruction",
47 "data access exception",
56 if(tbr < sizeof trapname/sizeof(char*))
59 sprint(buf, "trap instruction %ld", tbr-128);
60 else if(17<=tbr && tbr<=31)
61 sprint(buf, "interrupt level %ld", tbr-16);
66 return "cp exception";
72 sprint(buf, "unknown trap %ld", tbr);
78 sparcexcep(Map *map, Rgetter rget)
82 tbr = (*rget)(map, "TBR");
87 /* Sparc disassembler and related functions */
91 void (*f)(struct instr*, char*);
95 static char FRAMENAME[] = ".frame";
97 typedef struct instr Instr;
100 uchar op; /* bits 31-30 */
101 uchar rd; /* bits 29-25 */
102 uchar op2; /* bits 24-22 */
103 uchar a; /* bit 29 */
104 uchar cond; /* bits 28-25 */
105 uchar op3; /* bits 24-19 */
106 uchar rs1; /* bits 18-14 */
107 uchar i; /* bit 13 */
108 uchar asi; /* bits 12-05 */
109 uchar rs2; /* bits 04-00 */
110 short simm13; /* bits 12-00, signed */
111 ushort opf; /* bits 13-05 */
112 ulong immdisp22; /* bits 21-00 */
113 ulong simmdisp22; /* bits 21-00, signed */
114 ulong disp30; /* bits 30-00 */
115 ulong imm32; /* SETHI+ADD constant */
116 int target; /* SETHI+ADD dest reg */
119 uvlong addr; /* pc of instruction */
120 char *curr; /* current fill level in output buffer */
121 char *end; /* end of buffer */
122 int size; /* number of longs in instr */
123 char *err; /* errmsg */
126 static Map *mymap; /* disassembler context */
129 static int mkinstr(uvlong, Instr*);
130 static void bra1(Instr*, char*, char*[]);
131 static void bra(Instr*, char*);
132 static void fbra(Instr*, char*);
133 static void cbra(Instr*, char*);
134 static void unimp(Instr*, char*);
135 static void fpop(Instr*, char*);
136 static void shift(Instr*, char*);
137 static void sethi(Instr*, char*);
138 static void load(Instr*, char*);
139 static void loada(Instr*, char*);
140 static void store(Instr*, char*);
141 static void storea(Instr*, char*);
142 static void add(Instr*, char*);
143 static void cmp(Instr*, char*);
144 static void wr(Instr*, char*);
145 static void jmpl(Instr*, char*);
146 static void rd(Instr*, char*);
147 static void loadf(Instr*, char*);
148 static void storef(Instr*, char*);
149 static void loadc(Instr*, char*);
150 static void loadcsr(Instr*, char*);
151 static void trap(Instr*, char*);
153 static struct opcode sparcop0[8] = {
154 [0] "UNIMP", unimp, 0, /* page 137 */
155 [2] "B", bra, 0, /* page 119 */
156 [4] "SETHI", sethi, 0, /* page 104 */
157 [6] "FB", fbra, 0, /* page 121 */
158 [7] "CB", cbra, 0, /* page 123 */
161 static struct opcode sparcop2[64] = {
162 [0x00] "ADD", add, 0, /* page 108 */
163 [0x10] "ADDCC", add, 0,
164 [0x08] "ADDX", add, 0,
165 [0x18] "ADDXCC", add, 0,
167 [0x20] "TADD", add, 0, /* page 109 */
168 [0x22] "TADDCCTV", add, 0,
170 [0x04] "SUB", add, 0, /* page 110 */
171 [0x14] "SUBCC", cmp, 0,
172 [0x0C] "SUBX", add, 0,
173 [0x1C] "SUBXCC", add, 0,
175 [0x21] "TSUB", add, 0, /* page 111 */
176 [0x23] "TSUBCCTV", add, 0,
178 [0x24] "MULSCC", add, 0, /* page 112 */
180 [0x0A] "UMUL", add, 0, /* page 113 */
181 [0x0B] "SMUL", add, 0,
182 [0x1A] "UMULCC", add, 0,
183 [0x1B] "SMULCC", add, 0,
185 [0x0E] "UDIV", add, 0, /* page 115 */
186 [0x0F] "SDIV", add, 0,
187 [0x1E] "UDIVCC", add, 0,
188 [0x1F] "SDIVCC", add, 0,
190 [0x01] "AND", add, 0, /* page 106 */
191 [0x11] "ANDCC", add, 0,
192 [0x05] "ANDN", add, 0,
193 [0x15] "ANDNCC", add, 0,
195 [0x12] "ORCC", add, 0,
196 [0x06] "ORN", add, 0,
197 [0x16] "ORNCC", add, 0,
198 [0x03] "XOR", add, 0,
199 [0x13] "XORCC", add, 0,
200 [0x07] "XORN", add, 0,
201 [0x17] "XORNCC", add, 0,
203 [0x25] "SLL", shift, 0, /* page 107 */
204 [0x26] "SRL", shift, 0,
205 [0x27] "SRA", shift, 0,
207 [0x3C] "SAVE", add, 0, /* page 117 */
208 [0x3D] "RESTORE", add, 0,
210 [0x38] "JMPL", jmpl, 0, /* page 126 */
212 [0x39] "RETT", add, 0, /* page 127 */
214 [0x3A] "T", trap, 0, /* page 129 */
216 [0x28] "rdy", rd, 0, /* page 131 */
217 [0x29] "rdpsr", rd, 0,
218 [0x2A] "rdwim", rd, 0,
219 [0x2B] "rdtbr", rd, 0,
221 [0x30] "wry", wr, 0, /* page 133 */
222 [0x31] "wrpsr", wr, 0,
223 [0x32] "wrwim", wr, 0,
224 [0x33] "wrtbr", wr, 0,
226 [0x3B] "flush", add, 0, /* page 138 */
228 [0x34] "FPOP", fpop, 0, /* page 140 */
229 [0x35] "FPOP", fpop, 0,
232 static struct opcode sparcop3[64]={
233 [0x09] "ldsb", load, 0, /* page 90 */
234 [0x19] "ldsba", loada, 0,
235 [0x0A] "ldsh", load, 0,
236 [0x1A] "ldsha", loada, 0,
237 [0x01] "ldub", load, 0,
238 [0x11] "lduba", loada, 0,
239 [0x02] "lduh", load, 0,
240 [0x12] "lduha", loada, 0,
241 [0x00] "ld", load, 0,
242 [0x10] "lda", loada, 0,
243 [0x03] "ldd", load, 0,
244 [0x13] "ldda", loada, 0,
246 [0x20] "ldf", loadf, 0, /* page 92 */
247 [0x23] "lddf", loadf, 0,
248 [0x21] "ldfsr", loadf,0,
250 [0x30] "ldc", loadc, 0, /* page 94 */
251 [0x33] "lddc", loadc, 0,
252 [0x31] "ldcsr", loadcsr,0,
254 [0x05] "stb", store, 0, /* page 95 */
255 [0x15] "stba", storea, 0,
256 [0x06] "sth", store, 0,
257 [0x16] "stha", storea, 0,
258 [0x04] "st", store, 0,
259 [0x14] "sta", storea, 0,
260 [0x07] "std", store, 0,
261 [0x17] "stda", storea, 0,
263 [0x24] "stf", storef, 0, /* page 97 */
264 [0x27] "stdf", storef, 0,
265 [0x25] "stfsr", storef,0,
266 [0x26] "stdfq", storef,0,
268 [0x34] "stc", loadc, 0, /* page 99 */
269 [0x37] "stdc", loadc, 0,
270 [0x35] "stcsr", loadcsr,0,
271 [0x36] "stdcq", loadcsr,0,
273 [0x0D] "ldstub", store, 0, /* page 101 */
274 [0x1D] "ldstuba", storea, 0,
276 [0x0F] "swap", load, 0, /* page 102 */
277 [0x1F] "swapa", loada, 0,
280 #pragma varargck argpos bprint 2
281 #pragma varargck type "T" char*
283 /* convert to lower case from upper, according to dascase */
290 oa = va_arg(f->args, char*);
292 for(s=oa,t=buf; *t = *s; s++,t++)
293 if('A'<=*t && *t<='Z')
295 return fmtstrcpy(f, buf);
297 return fmtstrcpy(f, oa);
301 bprint(Instr *i, char *fmt, ...)
306 i->curr = vseprint(i->curr, i->end, fmt, arg);
311 decode(uvlong pc, Instr *i)
315 if (get4(mymap, pc, &w) < 0) {
316 werrstr("can't read instruction: %r");
319 i->op = (w >> 30) & 0x03;
320 i->rd = (w >> 25) & 0x1F;
321 i->op2 = (w >> 22) & 0x07;
322 i->a = (w >> 29) & 0x01;
323 i->cond = (w >> 25) & 0x0F;
324 i->op3 = (w >> 19) & 0x3F;
325 i->rs1 = (w >> 14) & 0x1F;
326 i->i = (w >> 13) & 0x01;
327 i->asi = (w >> 5) & 0xFF;
328 i->rs2 = (w >> 0) & 0x1F;
329 i->simm13 = (w >> 0) & 0x1FFF;
330 if(i->simm13 & (1<<12))
331 i->simm13 |= ~((1<<13)-1);
332 i->opf = (w >> 5) & 0x1FF;
333 i->immdisp22 = (w >> 0) & 0x3FFFFF;
334 i->simmdisp22 = i->immdisp22;
335 if(i->simmdisp22 & (1<<21))
336 i->simmdisp22 |= ~((1<<22)-1);
337 i->disp30 = (w >> 0) & 0x3FFFFFFF;
346 mkinstr(uvlong pc, Instr *i)
350 if (decode(pc, i) < 0)
352 if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
353 if (decode(pc+4, &xi) < 0)
355 if(xi.op==2 && xi.op3==0) /* ADD */
356 if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */
357 i->imm32 = xi.simm13 + (i->immdisp22<<10);
364 if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
365 if (decode(pc+4, &xi) < 0)
367 if(i->op==2 && i->opf==1) /* FMOVS */
368 if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
377 printins(Map *map, uvlong pc, char *buf, int n)
380 void (*f)(Instr*, char*);
383 memset(&instr, 0, sizeof(instr));
386 if (mkinstr(pc, &instr) < 0)
390 f = sparcop0[instr.op2].f;
392 (*f)(&instr, sparcop0[instr.op2].mnemonic);
394 bprint(&instr, "unknown %lux", instr.w0);
398 bprint(&instr, "%T", "CALL\t");
399 instr.curr += symoff(instr.curr, instr.end-instr.curr,
400 pc+instr.disp30*4, CTEXT);
402 bprint(&instr, "(SB)");
406 f = sparcop2[instr.op3].f;
408 (*f)(&instr, sparcop2[instr.op3].mnemonic);
410 bprint(&instr, "unknown %lux", instr.w0);
414 f = sparcop3[instr.op3].f;
416 (*f)(&instr, sparcop3[instr.op3].mnemonic);
418 bprint(&instr, "unknown %lux", instr.w0);
422 if (instr.curr != buf)
423 bprint(&instr, "\t\t;");
424 bprint(&instr, instr.err);
430 sparcinst(Map *map, uvlong pc, char modifier, char *buf, int n)
432 static int fmtinstalled = 0;
434 /* a modifier of 'I' toggles the dissassembler type */
437 fmtinstall('T', Tfmt);
439 if ((asstype == ASUNSPARC && modifier == 'i')
440 || (asstype == ASPARC && modifier == 'I'))
444 return printins(map, pc, buf, n);
448 sparcdas(Map *map, uvlong pc, char *buf, int n)
453 memset(&instr, 0, sizeof(instr));
456 if (mkinstr(pc, &instr) < 0)
458 if (instr.end-instr.curr > 8)
459 instr.curr = _hexify(instr.curr, instr.w0, 7);
460 if (instr.end-instr.curr > 9 && instr.size == 2) {
462 instr.curr = _hexify(instr.curr, instr.w1, 7);
469 sparcinstlen(Map *map, uvlong pc)
474 if (mkinstr(pc, &i) < 0)
485 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
487 if (s.value > i->simm13) {
488 if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
489 bprint(i, "%s+%lld(SP)", s.name, s.value);
493 offset = i->simm13-s.value;
494 if (getauto(&s, offset-4, CPARAM, &s)) {
495 bprint(i, "%s+%d(FP)", s.name, offset);
508 if (i->rs1 == 1 && plocal(i) >= 0)
510 off = mach->sb+i->simm13;
511 if(i->rs1 == 2 && findsym(off, CANY, &s)
512 && s.value-off < 4096
513 && (s.class == CDATA || s.class == CTEXT)) {
514 if(off==s.value && s.name[0]=='$'){
516 geta(mymap, s.value, &off1);
517 if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
518 bprint(i, "$%s(SB)", s2.name);
522 bprint(i, "%s", s.name);
524 bprint(i, "+%llux", s.value-off);
528 bprint(i, "%ux(R%d)", i->simm13, i->rs1);
532 unimp(Instr *i, char *m)
537 static char *bratab[16] = { /* page 91 */
556 static char *fbratab[16] = { /* page 91 */
575 static char *cbratab[16] = { /* page 91 */
595 bra1(Instr *i, char *m, char *tab[])
601 bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase);
603 bprint(i, "%T%T\t", m, tab[i->cond]);
604 i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
610 bra(Instr *i, char *m) /* page 91 */
616 fbra(Instr *i, char *m) /* page 93 */
622 cbra(Instr *i, char *m) /* page 95 */
628 trap(Instr *i, char *m) /* page 101 */
631 bprint(i, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
633 bprint(i, "%T%T\t$%ux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
637 sethi(Instr *i, char *m) /* page 89 */
641 imm = i->immdisp22<<10;
643 bprint(i, "%T\t%lux, R%d", m, imm, i->rd);
646 if(imm==0 && i->rd==0){
651 bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
654 bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
657 static char ldtab[] = {
665 moveinstr(int op3, char *m)
673 if(op3 == 0xF || op3 == 0x1F)
675 if(op3 == 0xD || op3 == 0x1D)
676 return "TAS"; /* really LDSTUB */
679 if((op3&11)==1 || (op3&11)==2)
681 sprint(buf, "MOV%c%s", c, s);
688 load(Instr *i, char *m) /* page 68 */
690 m = moveinstr(i->op3, m);
692 bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
694 bprint(i, "%s\t", m);
696 bprint(i, ", R%d", i->rd);
701 loada(Instr *i, char *m) /* page 68 */
703 m = moveinstr(i->op3, m);
705 bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
707 bprint(i, "unknown ld asi %lux", i->w0);
711 store(Instr *i, char *m) /* page 74 */
713 m = moveinstr(i->op3, m);
715 bprint(i, "%s\tR%d, (R%d+R%d)",
716 m, i->rd, i->rs1, i->rs2);
718 bprint(i, "%s\tR%d, ", m, i->rd);
724 storea(Instr *i, char *m) /* page 74 */
726 m = moveinstr(i->op3, m);
728 bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
730 bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
734 shift(Instr *i, char *m) /* page 88 */
739 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
741 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
744 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
746 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
750 bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
752 bprint(i, "%T\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
755 bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
757 bprint(i, "%T\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
762 add(Instr *i, char *m) /* page 82 */
766 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
768 if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
769 bprint(i, "MOVW\tR%d", i->rs2);
771 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
774 bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13);
776 if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
777 bprint(i, "MOVW\t$%ux", i->simm13);
778 else if(i->op3==0 && i->rd && i->rs1==2){
779 /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
780 bprint(i, "MOVW\t$");
783 bprint(i, "%T\t$%ux, R%d", m, i->simm13, i->rs1);
786 bprint(i, ", R%d", i->rd);
790 cmp(Instr *i, char *m)
792 if(dascase || i->rd){
797 bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
799 bprint(i, "CMP\tR%d, $%ux", i->rs1, i->simm13);
802 static char *regtab[4] = {
810 wr(Instr *i, char *m) /* page 82 */
814 bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
816 bprint(i, "%s\tR%d, $%ux", m, i->rs1, i->simm13);
818 if(i->i && i->simm13==0)
819 bprint(i, "MOVW\tR%d", i->rs1);
821 bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
823 bprint(i, "wr\t$%ux, R%d", i->simm13, i->rs1);
825 bprint(i, ", %s", regtab[i->op3&3]);
829 rd(Instr *i, char *m) /* page 103 */
831 if(i->rs1==15 && i->rd==0){
839 bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
844 jmpl(Instr *i, char *m) /* page 82 */
848 bprint(i, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
850 bprint(i, "%T\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
852 if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
855 bprint(i, "%T\t", m);
857 bprint(i, ", R%d", i->rd);
863 loadf(Instr *i, char *m) /* page 70 */
869 else if(i->op3 == 0x21)
873 bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
875 bprint(i, "%s\t", m);
881 bprint(i, ", R%d", i->rd);
885 storef(Instr *i, char *m) /* page 70 */
889 if(i->op3 == 0x25 || i->op3 == 0x26)
891 else if(i->op3 == 0x20)
894 bprint(i, "%s\t", m);
897 else if(i->op3 == 0x26)
900 bprint(i, "R%d, ", i->rd);
902 bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
908 loadc(Instr *i, char *m) /* page 72 */
911 bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
913 bprint(i, "%s\t", m);
915 bprint(i, ", C%d", i->rd);
920 loadcsr(Instr *i, char *m) /* page 72 */
923 bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
925 bprint(i, "%s\t", m);
934 } fptab1[] = { /* ignores rs1 */
935 0xC4, "FITOS", /* page 109 */
939 0xD1, "FSTOI", /* page 110 */
943 0xC9, "FSTOD", /* page 111 */
950 0x01, "FMOVS", /* page 112 */
954 0x29, "FSQRTS", /* page 113 */
964 } fptab2[] = { /* uses rs1 */
966 0x41, "FADDS", /* page 114 */
973 0x49, "FMULS", /* page 115 */
980 0x51, "FCMPS", /* page 116 */
991 fpop(Instr *i, char *m) /* page 108-116 */
995 if(dascase==0 && i->size==2){
996 bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
999 for(j=0; fptab1[j].name; j++)
1000 if(fptab1[j].opf == i->opf){
1001 bprint(i, "%T\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
1004 for(j=0; fptab2[j].name; j++)
1005 if(fptab2[j].opf == i->opf){
1006 bprint(i, "%T\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
1009 bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
1013 sparcfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1020 if (mkinstr(pc, &i) < 0)
1023 switch(w & 0xC1C00000){
1024 case 0x00800000: /* branch on int cond */
1025 case 0x01800000: /* branch on fp cond */
1026 case 0x01C00000: /* branch on copr cond */
1028 foll[1] = pc + (i.simmdisp22<<2);
1032 if((w&0xC0000000) == 0x40000000){ /* CALL */
1033 foll[0] = pc + (i.disp30<<2);
1037 if((w&0xC1F80000) == 0x81C00000){ /* JMPL */
1038 sprint(buf, "R%ld", (w>>14)&0xF);
1039 r1 = (*rget)(map, buf);
1040 if(w & 0x2000) /* JMPL R1+simm13 */
1042 else{ /* JMPL R1+R2 */
1043 sprint(buf, "R%ld", w&0xF);
1044 r2 = (*rget)(map, buf);
1049 foll[0] = pc+i.size*4;