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