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*
excname(ulong tt)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*
sparc64excep(Map * map,Rgetter rget)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
Tfmt(Fmt * f)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
bprint(Instr * i,char * fmt,...)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
decode(ulong pc,Instr * i)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
mkinstr(uvlong pc,Instr * i)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
printins(Map * map,uvlong pc,char * buf,int n)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
sparc64inst(Map * map,uvlong pc,char modifier,char * buf,int n)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
sparc64das(Map * map,uvlong pc,char * buf,int n)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
sparc64instlen(Map * map,uvlong pc)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
plocal(Instr * i)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
address(Instr * i)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
unimp(Instr * i,char * m)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
bra1(Instr * i,char * m,char * tab[])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
bra(Instr * i,char * m)637 bra(Instr *i, char *m) /* page 91 */
638 {
639 bra1(i, m, bratab);
640 }
641
642 static void
fbra(Instr * i,char * m)643 fbra(Instr *i, char *m) /* page 93 */
644 {
645 bra1(i, m, fbratab);
646 }
647
648 static void
cbra(Instr * i,char * m)649 cbra(Instr *i, char *m) /* page 95 */
650 {
651 bra1(i, m, cbratab);
652 }
653
654 static void
trap(Instr * i,char * m)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
sethi(Instr * i,char * m)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*
moveinstr(int op3,char * m)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
load(Instr * i,char * m)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
loada(Instr * i,char * m)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
store(Instr * i,char * m)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
storea(Instr * i,char * m)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
shift(Instr * i,char * m)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
add(Instr * i,char * m)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
cmp(Instr * i,char * m)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
wr(Instr * i,char * m)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
rd(Instr * i,char * m)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
jmpl(Instr * i,char * m)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
loadf(Instr * i,char * m)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
storef(Instr * i,char * m)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
loadc(Instr * i,char * m)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
loadcsr(Instr * i,char * m)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
fpop(Instr * i,char * m)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
sparc64foll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)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 }
1079