7 * Sparc64-specific debugger interface
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);
16 Machdata sparc64mach =
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 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 */
36 static char *trapname[] =
45 "instruction access exception",
46 "instruction access MMU miss",
47 "instruction access error",
49 "illegal instruction",
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 "fp exception ieee 754",
59 "internal processor error",
61 "data access exception",
62 "data access MMU miss",
64 "data access protection",
65 "mem address not aligned",
66 "LDDF mem address not aligned",
67 "STDF mem address not aligned",
69 "LDQF mem address nto aligned",
70 "STQF mem address not aligned",
78 if(tt < sizeof trapname/sizeof(char*) && trapname[tt])
81 sprint(buf, "trap instruction %ld", tt-128);
82 else if(65<=tt && tt<=79)
83 sprint(buf, "interrupt level %ld", tt-64);
86 return "async data error";
88 return "mondo interrupt";
90 return "instruction access MMU miss";
92 return "data access MMU miss";
94 return "data access protection";
100 sprint(buf, "unknown trap %ld", tt);
106 sparc64excep(Map *map, Rgetter rget)
110 tt = (*rget)(map, "TT");
114 /* Sparc disassembler and related functions */
118 void (*f)(struct instr*, char*);
122 static char FRAMENAME[] = ".frame";
124 typedef struct instr 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 */
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 */
153 static Map *mymap; /* disassembler context */
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*);
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 */
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,
194 [0x20] "TADD", add, 0, /* page 109 */
195 [0x22] "TADDCCTV", add, 0,
197 [0x04] "SUB", add, 0, /* page 110 */
198 [0x14] "SUBCC", cmp, 0,
199 [0x0C] "SUBX", add, 0,
200 [0x1C] "SUBXCC", add, 0,
202 [0x21] "TSUB", add, 0, /* page 111 */
203 [0x23] "TSUBCCTV", add, 0,
205 [0x24] "MULSCC", add, 0, /* page 112 */
207 [0x0A] "UMUL", add, 0, /* page 113 */
208 [0x0B] "SMUL", add, 0,
209 [0x1A] "UMULCC", add, 0,
210 [0x1B] "SMULCC", add, 0,
212 [0x0E] "UDIV", add, 0, /* page 115 */
213 [0x0F] "SDIV", add, 0,
214 [0x1E] "UDIVCC", add, 0,
215 [0x1F] "SDIVCC", add, 0,
217 [0x01] "AND", add, 0, /* page 106 */
218 [0x11] "ANDCC", add, 0,
219 [0x05] "ANDN", add, 0,
220 [0x15] "ANDNCC", 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,
230 [0x25] "SLL", shift, 0, /* page 107 */
231 [0x26] "SRL", shift, 0,
232 [0x27] "SRA", shift, 0,
234 [0x3C] "SAVE", add, 0, /* page 117 */
235 [0x3D] "RESTORE", add, 0,
237 [0x38] "JMPL", jmpl, 0, /* page 126 */
239 [0x39] "RETT", add, 0, /* page 127 */
241 [0x3A] "T", trap, 0, /* page 129 */
243 [0x28] "rdy", rd, 0, /* page 131 */
244 [0x29] "rdpsr", rd, 0,
245 [0x2A] "rdwim", rd, 0,
246 [0x2B] "rdtbr", rd, 0,
248 [0x30] "wry", wr, 0, /* page 133 */
249 [0x31] "wrpsr", wr, 0,
250 [0x32] "wrwim", wr, 0,
251 [0x33] "wrtbr", wr, 0,
253 [0x3B] "flush", add, 0, /* page 138 */
255 [0x34] "FPOP", fpop, 0, /* page 140 */
256 [0x35] "FPOP", fpop, 0,
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,
273 [0x20] "ldf", loadf, 0, /* page 92 */
274 [0x23] "lddf", loadf, 0,
275 [0x21] "ldfsr", loadf,0,
277 [0x30] "ldc", loadc, 0, /* page 94 */
278 [0x33] "lddc", loadc, 0,
279 [0x31] "ldcsr", loadcsr,0,
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,
290 [0x24] "stf", storef, 0, /* page 97 */
291 [0x27] "stdf", storef, 0,
292 [0x25] "stfsr", storef,0,
293 [0x26] "stdfq", storef,0,
295 [0x34] "stc", loadc, 0, /* page 99 */
296 [0x37] "stdc", loadc, 0,
297 [0x35] "stcsr", loadcsr,0,
298 [0x36] "stdcq", loadcsr,0,
300 [0x0D] "ldstub", store, 0, /* page 101 */
301 [0x1D] "ldstuba", storea, 0,
303 [0x0F] "swap", load, 0, /* page 102 */
304 [0x1F] "swapa", loada, 0,
307 #pragma varargck argpos bprint 2
308 #pragma varargck type "T" char*
310 /* convert to lower case from upper, according to dascase */
317 oa = va_arg(f->args, char*);
319 for(s=oa,t=buf; *t = *s; s++,t++)
320 if('A'<=*t && *t<='Z')
322 return fmtstrcpy(f, buf);
324 return fmtstrcpy(f, oa);
328 bprint(Instr *i, char *fmt, ...)
333 i->curr = vseprint(i->curr, i->end, fmt, arg);
338 decode(ulong pc, Instr *i)
342 if (get4(mymap, pc, &w) < 0) {
343 werrstr("can't read instruction: %r");
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;
373 mkinstr(uvlong pc, Instr *i)
377 if (decode(pc, i) < 0)
379 if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
380 if (decode(pc+4, &xi) < 0)
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);
391 if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
392 if (decode(pc+4, &xi) < 0)
394 if(i->op==2 && i->opf==1) /* FMOVS */
395 if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
404 printins(Map *map, uvlong pc, char *buf, int n)
407 void (*f)(Instr*, char*);
410 memset(&instr, 0, sizeof(instr));
413 if (mkinstr(pc, &instr) < 0)
417 f = sparc64op0[instr.op2].f;
419 (*f)(&instr, sparc64op0[instr.op2].mnemonic);
421 bprint(&instr, "unknown %lux", instr.w0);
425 bprint(&instr, "CALL\t");
426 instr.curr += symoff(instr.curr, instr.end-instr.curr,
427 pc+instr.disp30*4, CTEXT);
429 bprint(&instr, "(SB)");
433 f = sparc64op2[instr.op3].f;
435 (*f)(&instr, sparc64op2[instr.op3].mnemonic);
437 bprint(&instr, "unknown %lux", instr.w0);
441 f = sparc64op3[instr.op3].f;
443 (*f)(&instr, sparc64op3[instr.op3].mnemonic);
445 bprint(&instr, "unknown %lux", instr.w0);
449 if (instr.curr != buf)
450 bprint(&instr, "\t\t;");
451 bprint(&instr, instr.err);
457 sparc64inst(Map *map, uvlong pc, char modifier, char *buf, int n)
459 static int fmtinstalled = 0;
461 /* a modifier of 'I' toggles the dissassembler type */
464 fmtinstall('T', Tfmt);
466 if ((asstype == ASUNSPARC && modifier == 'i')
467 || (asstype == ASPARC && modifier == 'I'))
471 return printins(map, pc, buf, n);
475 sparc64das(Map *map, uvlong pc, char *buf, int n)
480 memset(&instr, 0, sizeof(instr));
483 if (mkinstr(pc, &instr) < 0)
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) {
489 instr.curr = _hexify(instr.curr, instr.w1, 7);
496 sparc64instlen(Map *map, uvlong pc)
501 if (mkinstr(pc, &i) < 0)
512 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
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);
520 offset = i->simm13-s.value;
521 if (getauto(&s, offset-4, CPARAM, &s)) {
522 bprint(i, "%s+%ld(FP)", s.name, offset);
535 if (i->rs1 == 1 && plocal(i) >= 0)
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]=='$'){
543 geta(mymap, s.value, &off1);
544 if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
545 bprint(i, "$%s(SB)", s2.name);
549 bprint(i, "%s", s.name);
551 bprint(i, "+%llux", s.value-off);
555 bprint(i, "%ux(R%d)", i->simm13, i->rs1);
559 unimp(Instr *i, char *m)
564 static char *bratab[16] = { /* page 91 */
583 static char *fbratab[16] = { /* page 91 */
602 static char *cbratab[16] = { /* page 91 */
622 bra1(Instr *i, char *m, char *tab[])
628 bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase);
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);
637 bra(Instr *i, char *m) /* page 91 */
643 fbra(Instr *i, char *m) /* page 93 */
649 cbra(Instr *i, char *m) /* page 95 */
655 trap(Instr *i, char *m) /* page 101 */
658 bprint(i, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
660 bprint(i, "%T%T\t$%ux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
664 sethi(Instr *i, char *m) /* page 89 */
668 imm = i->immdisp22<<10;
670 bprint(i, "%T\t%lux, R%d", m, imm, i->rd);
673 if(imm==0 && i->rd==0){
678 bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
681 bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
684 static char ldtab[] = {
692 moveinstr(int op3, char *m)
700 if(op3 == 0xF || op3 == 0x1F)
702 if(op3 == 0xD || op3 == 0x1D)
703 return "TAS"; /* really LDSTUB */
706 if((op3&11)==1 || (op3&11)==2)
708 sprint(buf, "MOV%c%s", c, s);
715 load(Instr *i, char *m) /* page 68 */
717 m = moveinstr(i->op3, m);
719 bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
721 bprint(i, "%s\t", m);
723 bprint(i, ", R%d", i->rd);
728 loada(Instr *i, char *m) /* page 68 */
730 m = moveinstr(i->op3, m);
732 bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
734 bprint(i, "unknown ld asi %lux", i->w0);
738 store(Instr *i, char *m) /* page 74 */
740 m = moveinstr(i->op3, m);
742 bprint(i, "%s\tR%d, (R%d+R%d)",
743 m, i->rd, i->rs1, i->rs2);
745 bprint(i, "%s\tR%d, ", m, i->rd);
751 storea(Instr *i, char *m) /* page 74 */
753 m = moveinstr(i->op3, m);
755 bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
757 bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
761 shift(Instr *i, char *m) /* page 88 */
766 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
768 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
771 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
773 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
777 bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
779 bprint(i, "%T\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
782 bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
784 bprint(i, "%T\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
789 add(Instr *i, char *m) /* page 82 */
793 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
795 if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
796 bprint(i, "MOVW\tR%d", i->rs2);
798 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
801 bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13);
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$");
810 bprint(i, "%T\t$%ux, R%d", m, i->simm13, i->rs1);
813 bprint(i, ", R%d", i->rd);
817 cmp(Instr *i, char *m)
819 if(dascase || i->rd){
824 bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
826 bprint(i, "CMP\tR%d, $%ux", i->rs1, i->simm13);
829 static char *regtab[4] = {
832 "WIM", /* XXX not any more */
837 wr(Instr *i, char *m) /* page 82 */
841 bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
843 bprint(i, "%s\tR%d, $%ux", m, i->rs1, i->simm13);
845 if(i->i && i->simm13==0)
846 bprint(i, "MOVW\tR%d", i->rs1);
848 bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
850 bprint(i, "wr\t$%ux, R%d", i->simm13, i->rs1);
852 bprint(i, ", %s", regtab[i->op3&3]);
856 rd(Instr *i, char *m) /* page 103 */
858 if(i->rs1==15 && i->rd==0){
866 bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
871 jmpl(Instr *i, char *m) /* page 82 */
875 bprint(i, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
877 bprint(i, "%T\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
879 if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
882 bprint(i, "%T\t", m);
884 bprint(i, ", R%d", i->rd);
890 loadf(Instr *i, char *m) /* page 70 */
896 else if(i->op3 == 0x21)
900 bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
902 bprint(i, "%s\t", m);
908 bprint(i, ", R%d", i->rd);
912 void storef(Instr *i, char *m) /* page 70 */
916 if(i->op3 == 0x25 || i->op3 == 0x26)
918 else if(i->op3 == 0x20)
921 bprint(i, "%s\t", m);
924 else if(i->op3 == 0x26)
927 bprint(i, "R%d, ", i->rd);
929 bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
935 void loadc(Instr *i, char *m) /* page 72 */
938 bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
940 bprint(i, "%s\t", m);
942 bprint(i, ", C%d", i->rd);
947 void loadcsr(Instr *i, char *m) /* page 72 */
950 bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
952 bprint(i, "%s\t", m);
961 } fptab1[] = { /* ignores rs1 */
962 0xC4, "FITOS", /* page 109 */
966 0xD1, "FSTOI", /* page 110 */
970 0xC9, "FSTOD", /* page 111 */
977 0x01, "FMOVS", /* page 112 */
981 0x29, "FSQRTS", /* page 113 */
991 } fptab2[] = { /* uses rs1 */
993 0x41, "FADDS", /* page 114 */
1000 0x49, "FMULS", /* page 115 */
1007 0x51, "FCMPS", /* page 116 */
1018 fpop(Instr *i, char *m) /* page 108-116 */
1022 if(dascase==0 && i->size==2){
1023 bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
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);
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);
1036 bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
1040 sparc64foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1047 if (mkinstr(pc, &i) < 0)
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 */
1055 foll[1] = pc + (i.simmdisp22<<2);
1059 if((w&0xC0000000) == 0x40000000){ /* CALL */
1060 foll[0] = pc + (i.disp30<<2);
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 */
1069 else{ /* JMPL R1+R2 */
1070 sprint(buf, "R%ld", w&0xF);
1071 r2 = (*rget)(map, buf);
1076 foll[0] = pc+i.size*4;