summaryrefslogtreecommitdiff
path: root/utils/libmach/kdb.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /utils/libmach/kdb.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'utils/libmach/kdb.c')
-rw-r--r--utils/libmach/kdb.c1055
1 files changed, 1055 insertions, 0 deletions
diff --git a/utils/libmach/kdb.c b/utils/libmach/kdb.c
new file mode 100644
index 00000000..bffd5e77
--- /dev/null
+++ b/utils/libmach/kdb.c
@@ -0,0 +1,1055 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+/*
+ * Sparc-specific debugger interface
+ */
+
+static char *sparcexcep(Map*, Rgetter);
+static int sparcfoll(Map*, ulong, Rgetter, ulong*);
+static int sparcinst(Map*, ulong, char, char*, int);
+static int sparcdas(Map*, ulong, char*, int);
+static int sparcinstlen(Map*, ulong);
+
+Machdata sparcmach =
+{
+ {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */
+ 4, /* break point size */
+
+ beswab, /* convert short to local byte order */
+ beswal, /* convert long to local byte order */
+ beswav, /* convert vlong to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* frame finder */
+ sparcexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos, /* single precision float printer */
+ beieeedftos, /* double precision float printer */
+ sparcfoll, /* following addresses */
+ sparcinst, /* print instruction */
+ sparcdas, /* dissembler */
+ sparcinstlen, /* instruction size */
+};
+
+static char *trapname[] =
+{
+ "reset",
+ "instruction access exception",
+ "illegal instruction",
+ "privileged instruction",
+ "fp disabled",
+ "window overflow",
+ "window underflow",
+ "unaligned address",
+ "fp exception",
+ "data access exception",
+ "tag overflow",
+};
+
+static char*
+excname(ulong tbr)
+{
+ static char buf[32];
+
+ if(tbr < sizeof trapname/sizeof(char*))
+ return trapname[tbr];
+ if(tbr >= 130)
+ sprint(buf, "trap instruction %ld", tbr-128);
+ else if(17<=tbr && tbr<=31)
+ sprint(buf, "interrupt level %ld", tbr-16);
+ else switch(tbr){
+ case 36:
+ return "cp disabled";
+ case 40:
+ return "cp exception";
+ case 128:
+ return "syscall";
+ case 129:
+ return "breakpoint";
+ default:
+ sprint(buf, "unknown trap %ld", tbr);
+ }
+ return buf;
+}
+
+static char*
+sparcexcep(Map *map, Rgetter rget)
+{
+ long tbr;
+
+ tbr = (*rget)(map, "TBR");
+ tbr = (tbr&0xFFF)>>4;
+ return excname(tbr);
+}
+
+ /* Sparc disassembler and related functions */
+
+typedef struct instr Instr;
+
+struct opcode {
+ char *mnemonic;
+ void (*f)(Instr*, char*);
+ int flag;
+};
+
+static char FRAMENAME[] = ".frame";
+
+struct instr {
+ uchar op; /* bits 31-30 */
+ uchar rd; /* bits 29-25 */
+ uchar op2; /* bits 24-22 */
+ uchar a; /* bit 29 */
+ uchar cond; /* bits 28-25 */
+ uchar op3; /* bits 24-19 */
+ uchar rs1; /* bits 18-14 */
+ uchar i; /* bit 13 */
+ uchar asi; /* bits 12-05 */
+ uchar rs2; /* bits 04-00 */
+ short simm13; /* bits 12-00, signed */
+ ushort opf; /* bits 13-05 */
+ ulong immdisp22; /* bits 21-00 */
+ ulong simmdisp22; /* bits 21-00, signed */
+ ulong disp30; /* bits 30-00 */
+ ulong imm32; /* SETHI+ADD constant */
+ int target; /* SETHI+ADD dest reg */
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char *err; /* errmsg */
+};
+
+static Map *mymap; /* disassembler context */
+static int dascase;
+
+static int mkinstr(ulong, Instr*);
+static void bra1(Instr*, char*, char*[]);
+static void bra(Instr*, char*);
+static void fbra(Instr*, char*);
+static void cbra(Instr*, char*);
+static void unimp(Instr*, char*);
+static void fpop(Instr*, char*);
+static void shift(Instr*, char*);
+static void sethi(Instr*, char*);
+static void load(Instr*, char*);
+static void loada(Instr*, char*);
+static void store(Instr*, char*);
+static void storea(Instr*, char*);
+static void add(Instr*, char*);
+static void cmp(Instr*, char*);
+static void wr(Instr*, char*);
+static void jmpl(Instr*, char*);
+static void rd(Instr*, char*);
+static void loadf(Instr*, char*);
+static void storef(Instr*, char*);
+static void loadc(Instr*, char*);
+static void loadcsr(Instr*, char*);
+static void trap(Instr*, char*);
+
+static struct opcode sparcop0[8] = {
+ "UNIMP", unimp, 0, /* page 137 */ /* 0 */
+ "", 0, 0, /* 1 */
+ "B", bra, 0, /* page 119 */ /* 2 */
+ "", 0, 0, /* 3 */
+ "SETHI", sethi, 0, /* page 104 */ /* 4 */
+ "", 0, 0, /* 5 */
+ "FB", fbra, 0, /* page 121 */ /* 6 */
+ "CB", cbra, 0, /* page 123 */ /* 7 */
+};
+
+static struct opcode sparcop2[64] = {
+ "ADD", add, 0, /* page 108 */ /* 0x00 */
+ "AND", add, 0, /* page 106 */ /* 0x01 */
+ "OR", add, 0, /* 0x02 */
+ "XOR", add, 0, /* 0x03 */
+ "SUB", add, 0, /* page 110 */ /* 0x04 */
+ "ANDN", add, 0, /* 0x05 */
+ "ORN", add, 0, /* 0x06 */
+ "XORN", add, 0, /* 0x07 */
+ "ADDX", add, 0, /* 0x08 */
+ "", 0, 0, /* 0x09 */
+ "UMUL", add, 0, /* page 113 */ /* 0x0a */
+ "SMUL", add, 0, /* 0x0b */
+ "SUBX", add, 0, /* 0x0c */
+ "", 0, 0, /* 0x0d */
+ "UDIV", add, 0, /* page 115 */ /* 0x0e */
+ "SDIV", add, 0, /* 0x0f */
+ "ADDCC", add, 0, /* 0x10 */
+ "ANDCC", add, 0, /* 0x11 */
+ "ORCC", add, 0, /* 0x12 */
+ "XORCC", add, 0, /* 0x13 */
+ "SUBCC", cmp, 0, /* 0x14 */
+ "ANDNCC", add, 0, /* 0x15 */
+ "ORNCC", add, 0, /* 0x16 */
+ "XORNCC", add, 0, /* 0x17 */
+ "ADDXCC", add, 0, /* 0x18 */
+ "", 0, 0, /* 0x19 */
+ "UMULCC", add, 0, /* 0x1a */
+ "SMULCC", add, 0, /* 0x1b */
+ "SUBXCC", add, 0, /* 0x1c */
+ "", 0, 0, /* 0x1d */
+ "UDIVCC", add, 0, /* 0x1e */
+ "SDIVCC", add, 0, /* 0x1f */
+ "TADD", add, 0, /* page 109 */ /* 0x20 */
+ "TSUB", add, 0, /* page 111 */ /* 0x21 */
+ "TADDCCTV", add, 0, /* 0x22 */
+ "TSUBCCTV", add, 0, /* 0x23 */
+ "MULSCC", add, 0, /* page 112 */ /* 0x24 */
+ "SLL", shift, 0, /* page 107 */ /* 0x25 */
+ "SRL", shift, 0, /* 0x26 */
+ "SRA", shift, 0, /* 0x27 */
+ "rdy", rd, 0, /* page 131 */ /* 0x28 */
+ "rdpsr", rd, 0, /* 0x29 */
+ "rdwim", rd, 0, /* 0x2a */
+ "rdtbr", rd, 0, /* 0x2b */
+ "", 0, 0, /* 0x2c */
+ "", 0, 0, /* 0x2d */
+ "", 0, 0, /* 0x2e */
+ "", 0, 0, /* 0x2f */
+ "wry", wr, 0, /* page 133 */ /* 0x30 */
+ "wrpsr", wr, 0, /* 0x31 */
+ "wrwim", wr, 0, /* 0x32 */
+ "wrtbr", wr, 0, /* 0x33 */
+ "FPOP", fpop, 0, /* page 140 */ /* 0x34 */
+ "FPOP", fpop, 0, /* 0x35 */
+ "", 0, 0, /* 0x36 */
+ "", 0, 0, /* 0x37 */
+ "JMPL", jmpl, 0, /* page 126 */ /* 0x38 */
+ "RETT", add, 0, /* page 127 */ /* 0x39 */
+ "T", trap, 0, /* page 129 */ /* 0x3a */
+ "flush", add, 0, /* page 138 */ /* 0x3b */
+ "SAVE", add, 0, /* page 117 */ /* 0x3c */
+ "RESTORE", add, 0, /* 0x3d */
+};
+
+static struct opcode sparcop3[64]={
+ "ld", load, 0, /* 0x00 */
+ "ldub", load, 0, /* 0x01 */
+ "lduh", load, 0, /* 0x02 */
+ "ldd", load, 0, /* 0x03 */
+ "st", store, 0, /* 0x04 */
+ "stb", store, 0, /* page 95 */ /* 0x05 */
+ "sth", store, 0, /* 0x06 */
+ "std", store, 0, /* 0x07 */
+ "", 0, 0, /* 0x08 */
+ "ldsb", load, 0, /* page 90 */ /* 0x09 */
+ "ldsh", load, 0, /* 0x0a */
+ "", 0, 0, /* 0x0b */
+ "", 0, 0, /* 0x0c */
+ "ldstub", store, 0, /* page 101 */ /* 0x0d */
+ "", 0, 0, /* 0x0e */
+ "swap", load, 0, /* page 102 */ /* 0x0f */
+ "lda", loada, 0, /* 0x10 */
+ "lduba", loada, 0, /* 0x11 */
+ "lduha", loada, 0, /* 0x12 */
+ "ldda", loada, 0, /* 0x13 */
+ "sta", storea, 0, /* 0x14 */
+ "stba", storea, 0, /* 0x15 */
+ "stha", storea, 0, /* 0x16 */
+ "stda", storea, 0, /* 0x17 */
+ "", 0, 0, /* 0x18 */
+ "ldsba", loada, 0, /* 0x19 */
+ "ldsha", loada, 0, /* 0x1a */
+ "", 0, 0, /* 0x1b */
+ "", 0, 0, /* 0x1c */
+ "ldstuba", storea, 0, /* 0x1d */
+ "", 0, 0, /* 0x1e */
+ "swapa", loada, 0, /* 0x1f */
+ "ldf", loadf, 0, /* page 92 */ /* 0x20 */
+ "ldfsr", loadf,0, /* 0x21 */
+ "", 0, 0, /* 0x22 */
+ "lddf", loadf, 0, /* 0x23 */
+ "stf", storef, 0, /* page 97 */ /* 0x24 */
+ "stfsr", storef,0, /* 0x25 */
+ "stdfq", storef,0, /* 0x26 */
+ "stdf", storef, 0, /* 0x27 */
+ "", 0, 0, /* 0x28 */
+ "", 0, 0, /* 0x29 */
+ "", 0, 0, /* 0x2a */
+ "", 0, 0, /* 0x2b */
+ "", 0, 0, /* 0x2c */
+ "", 0, 0, /* 0x2d */
+ "", 0, 0, /* 0x2e */
+ "", 0, 0, /* 0x2f */
+ "ldc", loadc, 0, /* page 94 */ /* 0x30 */
+ "ldcsr", loadcsr,0, /* 0x31 */
+ "", 0, 0, /* 0x32 */
+ "lddc", loadc, 0, /* 0x33 */
+ "stc", loadc, 0, /* page 99 */ /* 0x34 */
+ "stcsr", loadcsr,0, /* 0x35 */
+ "stdcq", loadcsr,0, /* 0x36 */
+ "stdc", loadc, 0, /* 0x37 */
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ if (get4(mymap, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->op = (w >> 30) & 0x03;
+ i->rd = (w >> 25) & 0x1F;
+ i->op2 = (w >> 22) & 0x07;
+ i->a = (w >> 29) & 0x01;
+ i->cond = (w >> 25) & 0x0F;
+ i->op3 = (w >> 19) & 0x3F;
+ i->rs1 = (w >> 14) & 0x1F;
+ i->i = (w >> 13) & 0x01;
+ i->asi = (w >> 5) & 0xFF;
+ i->rs2 = (w >> 0) & 0x1F;
+ i->simm13 = (w >> 0) & 0x1FFF;
+ if(i->simm13 & (1<<12))
+ i->simm13 |= ~((1<<13)-1);
+ i->opf = (w >> 5) & 0x1FF;
+ i->immdisp22 = (w >> 0) & 0x3FFFFF;
+ i->simmdisp22 = i->immdisp22;
+ if(i->simmdisp22 & (1<<21))
+ i->simmdisp22 |= ~((1<<22)-1);
+ i->disp30 = (w >> 0) & 0x3FFFFFFF;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong pc, Instr *i)
+{
+ Instr xi;
+
+ if (decode(pc, i) < 0)
+ return -1;
+ if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
+ if (decode(pc+4, &xi) < 0)
+ return -1;
+ if(xi.op==2 && xi.op3==0) /* ADD */
+ if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */
+ i->imm32 = xi.simm13 + (i->immdisp22<<10);
+ i->target = xi.rd;
+ i->w1 = xi.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
+ if (decode(pc+4, &xi) < 0)
+ return -1;
+ if(i->op==2 && i->opf==1) /* FMOVS */
+ if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
+ i->w1 = xi.w0;
+ i->size++;
+ }
+ }
+ return 1;
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+ void (*f)(Instr*, char*);
+
+ mymap = map;
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ if (mkinstr(pc, &instr) < 0)
+ return -1;
+ switch(instr.op){
+ case 0:
+ f = sparcop0[instr.op2].f;
+ if(f)
+ (*f)(&instr, sparcop0[instr.op2].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+
+ case 1:
+ bprint(&instr, "%X", "CALL\t");
+ instr.curr += symoff(instr.curr, instr.end-instr.curr,
+ pc+instr.disp30*4, CTEXT);
+ if (!dascase)
+ bprint(&instr, "(SB)");
+ break;
+
+ case 2:
+ f = sparcop2[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop2[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+
+ case 3:
+ f = sparcop3[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop3[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+ }
+ if (instr.err) {
+ if (instr.curr != buf)
+ bprint(&instr, "\t\t;");
+ bprint(&instr, instr.err);
+ }
+ return instr.size*4;
+}
+
+/* convert to lower case from upper, according to dascase */
+static int
+Xconv(Fmt *f)
+{
+ char buf[128];
+ char *s, *t, *oa;
+
+ oa = va_arg(f->args, char*);
+ if(dascase){
+ for(s=oa,t=buf; *t = *s; s++,t++)
+ if('A'<=*t && *t<='Z')
+ *t += 'a'-'A';
+ return fmtstrcpy(f, buf);
+ }
+ return fmtstrcpy(f, oa);
+}
+
+static int
+sparcinst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ static int fmtinstalled = 0;
+
+ /* a modifier of 'I' toggles the dissassembler type */
+ if (!fmtinstalled) {
+ fmtinstalled = 1;
+ fmtinstall('X', Xconv);
+ }
+ if ((asstype == ASUNSPARC && modifier == 'i')
+ || (asstype == ASPARC && modifier == 'I'))
+ dascase = 'a'-'A';
+ else
+ dascase = 0;
+ return printins(map, pc, buf, n);
+}
+
+static int
+sparcdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+
+ mymap = map;
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ if (mkinstr(pc, &instr) < 0)
+ return -1;
+ if (instr.end-instr.curr > 8)
+ instr.curr = _hexify(instr.curr, instr.w0, 7);
+ if (instr.end-instr.curr > 9 && instr.size == 2) {
+ *instr.curr++ = ' ';
+ instr.curr = _hexify(instr.curr, instr.w1, 7);
+ }
+ *instr.curr = 0;
+ return instr.size*4;
+}
+
+static int
+sparcinstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ return i.size*4;
+}
+
+static int
+plocal(Instr *i)
+{
+ int offset;
+ Symbol s;
+
+ if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
+ return -1;
+ if (s.value > i->simm13) {
+ if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
+ bprint(i, "%s+%d(SP)", s.name, s.value);
+ return 1;
+ }
+ } else {
+ offset = i->simm13-s.value;
+ if (getauto(&s, offset-4, CPARAM, &s)) {
+ bprint(i, "%s+%d(FP)", s.name, offset);
+ return 1;
+ }
+ }
+ return -1;
+}
+
+static void
+address(Instr *i)
+{
+ Symbol s, s2;
+ long off, off1;
+
+ if (i->rs1 == 1 && plocal(i) >= 0)
+ return;
+ off = mach->sb+i->simm13;
+ if(i->rs1 == 2 && findsym(off, CANY, &s)
+ && s.value-off < 4096
+ && (s.class == CDATA || s.class == CTEXT)) {
+ if(off==s.value && s.name[0]=='$'){
+ off1 = 0;
+ get4(mymap, s.value, &off1);
+ if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
+ bprint(i, "$%s(SB)", s2.name);
+ return;
+ }
+ }
+ bprint(i, "%s", s.name);
+ if (s.value != off)
+ bprint(i, "+%lux", s.value-off);
+ bprint(i, "(SB)");
+ return;
+ }
+ bprint(i, "%lux(R%d)", i->simm13, i->rs1);
+}
+
+static void
+unimp(Instr *i, char *m)
+{
+ bprint(i, "%X", m);
+}
+
+static char *bratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "E", /* 0x1 */
+ "LE", /* 0x2 */
+ "L", /* 0x3 */
+ "LEU", /* 0x4 */
+ "CS", /* 0x5 */
+ "NEG", /* 0x6 */
+ "VS", /* 0x7 */
+ "A", /* 0x8 */
+ "NE", /* 0x9 */
+ "G", /* 0xa */
+ "GE", /* 0xb */
+ "GU", /* 0xc */
+ "CC", /* 0xd */
+ "POS", /* 0xe */
+ "VC", /* 0xf */
+};
+
+static char *fbratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "NE", /* 0x1 */
+ "LG", /* 0x2 */
+ "UL", /* 0x3 */
+ "L", /* 0x4 */
+ "UG", /* 0x5 */
+ "G", /* 0x6 */
+ "U", /* 0x7 */
+ "A", /* 0x8 */
+ "E", /* 0x9 */
+ "UE", /* 0xa */
+ "GE", /* 0xb */
+ "UGE", /* 0xc */
+ "LE", /* 0xd */
+ "ULE", /* 0xe */
+ "O", /* 0xf */
+};
+
+static char *cbratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "123", /* 0x1 */
+ "12", /* 0x2 */
+ "13", /* 0x3 */
+ "1", /* 0x4 */
+ "23", /* 0x5 */
+ "2", /* 0x6 */
+ "3", /* 0x7 */
+ "A", /* 0x8 */
+ "0", /* 0x9 */
+ "03", /* 0xa */
+ "02", /* 0xb */
+ "023", /* 0xc */
+ "01", /* 0xd */
+ "013", /* 0xe */
+ "012", /* 0xf */
+};
+
+static void
+bra1(Instr *i, char *m, char *tab[])
+{
+ long imm;
+
+ imm = i->simmdisp22;
+ if(i->a)
+ bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase);
+ else
+ bprint(i, "%X%X\t", m, tab[i->cond]);
+ i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
+ if (!dascase)
+ bprint(i, "(SB)");
+}
+
+static void
+bra(Instr *i, char *m) /* page 91 */
+{
+ bra1(i, m, bratab);
+}
+
+static void
+fbra(Instr *i, char *m) /* page 93 */
+{
+ bra1(i, m, fbratab);
+}
+
+static void
+cbra(Instr *i, char *m) /* page 95 */
+{
+ bra1(i, m, cbratab);
+}
+
+static void
+trap(Instr *i, char *m) /* page 101 */
+{
+ if(i->i == 0)
+ bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
+ else
+ bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
+}
+
+static void
+sethi(Instr *i, char *m) /* page 89 */
+{
+ ulong imm;
+
+ imm = i->immdisp22<<10;
+ if(dascase){
+ bprint(i, "%X\t%lux, R%d", m, imm, i->rd);
+ return;
+ }
+ if(imm==0 && i->rd==0){
+ bprint(i, "NOP");
+ return;
+ }
+ if(i->target < 0){
+ bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
+ return;
+ }
+ bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
+}
+
+static char ldtab[] = {
+ 'W',
+ 'B',
+ 'H',
+ 'D',
+};
+
+static char*
+moveinstr(int op3, char *m)
+{
+ char *s;
+ int c;
+ static char buf[8];
+
+ if(!dascase){
+ /* batshit cases */
+ if(op3 == 0xF || op3 == 0x1F)
+ return "SWAP";
+ if(op3 == 0xD || op3 == 0x1D)
+ return "TAS"; /* really LDSTUB */
+ c = ldtab[op3&3];
+ s = "";
+ if((op3&11)==1 || (op3&11)==2)
+ s="U";
+ sprint(buf, "MOV%c%s", c, s);
+ return buf;
+ }
+ return m;
+}
+
+static void
+load(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+}
+
+static void
+loada(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
+ else
+ bprint(i, "unknown ld asi %lux", i->w0);
+}
+
+static void
+store(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d)",
+ m, i->rd, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\tR%d, ", m, i->rd);
+ address(i);
+ }
+}
+
+static void
+storea(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
+ else
+ bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
+}
+
+static void
+shift(Instr *i, char *m) /* page 88 */
+{
+ if(i->i == 0){
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
+ else
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
+ else
+ bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
+ else
+ bprint(i, "%X\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
+ else
+ if(dascase)
+ bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
+ else
+ bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
+ }
+}
+
+static void
+add(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
+ bprint(i, "MOVW\tR%d", i->rs2);
+ else
+ bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
+ }else{
+ if(dascase)
+ bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13);
+ else
+ if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
+ bprint(i, "MOVW\t$%lux", i->simm13);
+ else if(i->op3==0 && i->rd && i->rs1==2){
+ /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
+ bprint(i, "MOVW\t$");
+ address(i);
+ } else
+ bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1);
+ }
+ if(i->rs1 != i->rd)
+ bprint(i, ", R%d", i->rd);
+}
+
+static void
+cmp(Instr *i, char *m)
+{
+ if(dascase || i->rd){
+ add(i, m);
+ return;
+ }
+ if(i->i == 0)
+ bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
+ else
+ bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13);
+}
+
+static char *regtab[4] = {
+ "Y",
+ "PSR",
+ "WIM",
+ "TBR",
+};
+
+static void
+wr(Instr *i, char *m) /* page 82 */
+{
+ if(dascase){
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13);
+ }else{
+ if(i->i && i->simm13==0)
+ bprint(i, "MOVW\tR%d", i->rs1);
+ else if(i->i == 0)
+ bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
+ else
+ bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1);
+ }
+ bprint(i, ", %s", regtab[i->op3&3]);
+}
+
+static void
+rd(Instr *i, char *m) /* page 103 */
+{
+ if(i->rs1==15 && i->rd==0){
+ m = "stbar";
+ if(!dascase)
+ m = "STBAR";
+ bprint(i, "%s", m);
+ }else{
+ if(!dascase)
+ m = "MOVW";
+ bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
+ }
+}
+
+static void
+jmpl(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(i->rd == 15)
+ bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
+ else
+ bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
+ bprint(i, "RETURN");
+ else{
+ bprint(i, "%X\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+ }
+}
+
+static void
+loadf(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x20)
+ m = "FMOVF";
+ else if(i->op3 == 0x21)
+ m = "MOVW";
+ }
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ }
+ if(i->op3 == 0x21)
+ bprint(i, ", FSR");
+ else
+ bprint(i, ", R%d", i->rd);
+}
+
+static
+void storef(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x25 || i->op3 == 0x26)
+ m = "MOVW";
+ else if(i->op3 == 0x20)
+ m = "FMOVF";
+ }
+ bprint(i, "%s\t", m);
+ if(i->op3 == 0x25)
+ bprint(i, "FSR, ");
+ else if(i->op3 == 0x26)
+ bprint(i, "FQ, ");
+ else
+ bprint(i, "R%d, ", i->rd);
+ if(i->i == 0)
+ bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
+ else
+ address(i);
+}
+
+static
+void loadc(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", C%d", i->rd);
+ }
+}
+
+static
+void loadcsr(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", CSR");
+ }
+}
+
+static struct{
+ int opf;
+ char *name;
+} fptab1[] = { /* ignores rs1 */
+ 0xC4, "FITOS", /* page 109 */
+ 0xC8, "FITOD",
+ 0xCC, "FITOX",
+
+ 0xD1, "FSTOI", /* page 110 */
+ 0xD2, "FDTOI",
+ 0xD3, "FXTOI",
+
+ 0xC9, "FSTOD", /* page 111 */
+ 0xCD, "FSTOX",
+ 0xC6, "FDTOS",
+ 0xCE, "FDTOX",
+ 0xC7, "FXTOS",
+ 0xCB, "FXTOD",
+
+ 0x01, "FMOVS", /* page 112 */
+ 0x05, "FNEGS",
+ 0x09, "FABSS",
+
+ 0x29, "FSQRTS", /* page 113 */
+ 0x2A, "FSQRTD",
+ 0x2B, "FSQRTX",
+
+ 0, 0,
+};
+
+static struct{
+ int opf;
+ char *name;
+} fptab2[] = { /* uses rs1 */
+
+ 0x41, "FADDS", /* page 114 */
+ 0x42, "FADDD",
+ 0x43, "FADDX",
+ 0x45, "FSUBS",
+ 0x46, "FSUBD",
+ 0x47, "FSUBX",
+
+ 0x49, "FMULS", /* page 115 */
+ 0x4A, "FMULD",
+ 0x4B, "FMULX",
+ 0x4D, "FDIVS",
+ 0x4E, "FDIVD",
+ 0x4F, "FDIVX",
+
+ 0x51, "FCMPS", /* page 116 */
+ 0x52, "FCMPD",
+ 0x53, "FCMPX",
+ 0x55, "FCMPES",
+ 0x56, "FCMPED",
+ 0x57, "FCMPEX",
+
+ 0, 0
+};
+
+static void
+fpop(Instr *i, char *m) /* page 108-116 */
+{
+ int j;
+
+ if(dascase==0 && i->size==2){
+ bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab1[j].name; j++)
+ if(fptab1[j].opf == i->opf){
+ bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab2[j].name; j++)
+ if(fptab2[j].opf == i->opf){
+ bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
+ return;
+ }
+ bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
+}
+
+static int
+sparcfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ ulong w, r1, r2;
+ char buf[8];
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ w = i.w0;
+ switch(w & 0xC1C00000){
+ case 0x00800000: /* branch on int cond */
+ case 0x01800000: /* branch on fp cond */
+ case 0x01C00000: /* branch on copr cond */
+ foll[0] = pc+8;
+ foll[1] = pc + (i.simmdisp22<<2);
+ return 2;
+ }
+
+ if((w&0xC0000000) == 0x40000000){ /* CALL */
+ foll[0] = pc + (i.disp30<<2);
+ return 1;
+ }
+
+ if((w&0xC1F80000) == 0x81C00000){ /* JMPL */
+ sprint(buf, "R%ld", (w>>14)&0xF);
+ r1 = (*rget)(map, buf);
+ if(w & 0x2000) /* JMPL R1+simm13 */
+ r2 = i.simm13;
+ else{ /* JMPL R1+R2 */
+ sprint(buf, "R%ld", w&0xF);
+ r2 = (*rget)(map, buf);
+ }
+ foll[0] = r1 + r2;
+ return 1;
+ }
+ foll[0] = pc+i.size*4;
+ return 1;
+}