1078 lines
22 KiB
C
1078 lines
22 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <mach.h>
|
|
|
|
/*
|
|
* Sparc64-specific debugger interface
|
|
*/
|
|
|
|
static char *sparc64excep(Map*, Rgetter);
|
|
static int sparc64foll(Map*, uvlong, Rgetter, uvlong*);
|
|
static int sparc64inst(Map*, uvlong, char, char*, int);
|
|
static int sparc64das(Map*, uvlong, char*, int);
|
|
static int sparc64instlen(Map*, uvlong);
|
|
|
|
Machdata sparc64mach =
|
|
{
|
|
{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 */
|
|
sparc64excep, /* print exception */
|
|
0, /* breakpoint fixup */
|
|
beieeesftos, /* single precision float printer */
|
|
beieeedftos, /* double precision float printer */
|
|
sparc64foll, /* following addresses */
|
|
sparc64inst, /* print instruction */
|
|
sparc64das, /* dissembler */
|
|
sparc64instlen, /* instruction size */
|
|
};
|
|
|
|
static char *trapname[] =
|
|
{
|
|
0,
|
|
"power on reset",
|
|
"watchdog reset",
|
|
"external reset",
|
|
"software reset",
|
|
"RED",
|
|
0, 0,
|
|
"instruction access exception",
|
|
"instruction access MMU miss",
|
|
"instruction access error",
|
|
0, 0, 0, 0, 0,
|
|
"illegal instruction",
|
|
"privileged opcode",
|
|
"unimplemented LDD",
|
|
"unimplemented STD",
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
"fp disabled",
|
|
"fp exception ieee 754",
|
|
"fp exception other",
|
|
0, 0, 0, 0,
|
|
"division by zero",
|
|
"internal processor error",
|
|
0, 0, 0, 0, 0, 0,
|
|
"data access exception",
|
|
"data access MMU miss",
|
|
"data access error",
|
|
"data access protection",
|
|
"mem address not aligned",
|
|
"LDDF mem address not aligned",
|
|
"STDF mem address not aligned",
|
|
"privileged action",
|
|
"LDQF mem address nto aligned",
|
|
"STQF mem address not aligned",
|
|
};
|
|
|
|
static char*
|
|
excname(ulong tt)
|
|
{
|
|
static char buf[32];
|
|
|
|
if(tt < sizeof trapname/sizeof(char*) && trapname[tt])
|
|
return trapname[tt];
|
|
if(tt >= 258)
|
|
sprint(buf, "trap instruction %ld", tt-128);
|
|
else if(65<=tt && tt<=79)
|
|
sprint(buf, "interrupt level %ld", tt-64);
|
|
else switch(tt){
|
|
case 64:
|
|
return "async data error";
|
|
case 96:
|
|
return "mondo interrupt";
|
|
case 100:
|
|
return "instruction access MMU miss";
|
|
case 104:
|
|
return "data access MMU miss";
|
|
case 108:
|
|
return "data access protection";
|
|
case 256:
|
|
return "syscall";
|
|
case 257:
|
|
return "breakpoint";
|
|
default:
|
|
sprint(buf, "unknown trap %ld", tt);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static char*
|
|
sparc64excep(Map *map, Rgetter rget)
|
|
{
|
|
long tt;
|
|
|
|
tt = (*rget)(map, "TT");
|
|
return excname(tt);
|
|
}
|
|
|
|
/* Sparc disassembler and related functions */
|
|
|
|
struct opcode {
|
|
char *mnemonic;
|
|
void (*f)(struct instr*, char*);
|
|
int flag;
|
|
};
|
|
|
|
static char FRAMENAME[] = ".frame";
|
|
|
|
typedef struct instr Instr;
|
|
|
|
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;
|
|
uvlong 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(uvlong, 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 sparc64op0[8] = {
|
|
[0] "UNIMP", unimp, 0, /* page 137 */
|
|
[2] "B", bra, 0, /* page 119 */
|
|
[4] "SETHI", sethi, 0, /* page 104 */
|
|
[6] "FB", fbra, 0, /* page 121 */
|
|
[7] "CB", cbra, 0, /* page 123 */
|
|
};
|
|
|
|
static struct opcode sparc64op2[64] = {
|
|
[0x00] "ADD", add, 0, /* page 108 */
|
|
[0x10] "ADDCC", add, 0,
|
|
[0x08] "ADDX", add, 0,
|
|
[0x18] "ADDXCC", add, 0,
|
|
|
|
[0x20] "TADD", add, 0, /* page 109 */
|
|
[0x22] "TADDCCTV", add, 0,
|
|
|
|
[0x04] "SUB", add, 0, /* page 110 */
|
|
[0x14] "SUBCC", cmp, 0,
|
|
[0x0C] "SUBX", add, 0,
|
|
[0x1C] "SUBXCC", add, 0,
|
|
|
|
[0x21] "TSUB", add, 0, /* page 111 */
|
|
[0x23] "TSUBCCTV", add, 0,
|
|
|
|
[0x24] "MULSCC", add, 0, /* page 112 */
|
|
|
|
[0x0A] "UMUL", add, 0, /* page 113 */
|
|
[0x0B] "SMUL", add, 0,
|
|
[0x1A] "UMULCC", add, 0,
|
|
[0x1B] "SMULCC", add, 0,
|
|
|
|
[0x0E] "UDIV", add, 0, /* page 115 */
|
|
[0x0F] "SDIV", add, 0,
|
|
[0x1E] "UDIVCC", add, 0,
|
|
[0x1F] "SDIVCC", add, 0,
|
|
|
|
[0x01] "AND", add, 0, /* page 106 */
|
|
[0x11] "ANDCC", add, 0,
|
|
[0x05] "ANDN", add, 0,
|
|
[0x15] "ANDNCC", add, 0,
|
|
[0x02] "OR", add, 0,
|
|
[0x12] "ORCC", add, 0,
|
|
[0x06] "ORN", add, 0,
|
|
[0x16] "ORNCC", add, 0,
|
|
[0x03] "XOR", add, 0,
|
|
[0x13] "XORCC", add, 0,
|
|
[0x07] "XORN", add, 0,
|
|
[0x17] "XORNCC", add, 0,
|
|
|
|
[0x25] "SLL", shift, 0, /* page 107 */
|
|
[0x26] "SRL", shift, 0,
|
|
[0x27] "SRA", shift, 0,
|
|
|
|
[0x3C] "SAVE", add, 0, /* page 117 */
|
|
[0x3D] "RESTORE", add, 0,
|
|
|
|
[0x38] "JMPL", jmpl, 0, /* page 126 */
|
|
|
|
[0x39] "RETT", add, 0, /* page 127 */
|
|
|
|
[0x3A] "T", trap, 0, /* page 129 */
|
|
|
|
[0x28] "rdy", rd, 0, /* page 131 */
|
|
[0x29] "rdpsr", rd, 0,
|
|
[0x2A] "rdwim", rd, 0,
|
|
[0x2B] "rdtbr", rd, 0,
|
|
|
|
[0x30] "wry", wr, 0, /* page 133 */
|
|
[0x31] "wrpsr", wr, 0,
|
|
[0x32] "wrwim", wr, 0,
|
|
[0x33] "wrtbr", wr, 0,
|
|
|
|
[0x3B] "flush", add, 0, /* page 138 */
|
|
|
|
[0x34] "FPOP", fpop, 0, /* page 140 */
|
|
[0x35] "FPOP", fpop, 0,
|
|
};
|
|
|
|
static struct opcode sparc64op3[64]={
|
|
[0x09] "ldsb", load, 0, /* page 90 */
|
|
[0x19] "ldsba", loada, 0,
|
|
[0x0A] "ldsh", load, 0,
|
|
[0x1A] "ldsha", loada, 0,
|
|
[0x01] "ldub", load, 0,
|
|
[0x11] "lduba", loada, 0,
|
|
[0x02] "lduh", load, 0,
|
|
[0x12] "lduha", loada, 0,
|
|
[0x00] "ld", load, 0,
|
|
[0x10] "lda", loada, 0,
|
|
[0x03] "ldd", load, 0,
|
|
[0x13] "ldda", loada, 0,
|
|
|
|
[0x20] "ldf", loadf, 0, /* page 92 */
|
|
[0x23] "lddf", loadf, 0,
|
|
[0x21] "ldfsr", loadf,0,
|
|
|
|
[0x30] "ldc", loadc, 0, /* page 94 */
|
|
[0x33] "lddc", loadc, 0,
|
|
[0x31] "ldcsr", loadcsr,0,
|
|
|
|
[0x05] "stb", store, 0, /* page 95 */
|
|
[0x15] "stba", storea, 0,
|
|
[0x06] "sth", store, 0,
|
|
[0x16] "stha", storea, 0,
|
|
[0x04] "st", store, 0,
|
|
[0x14] "sta", storea, 0,
|
|
[0x07] "std", store, 0,
|
|
[0x17] "stda", storea, 0,
|
|
|
|
[0x24] "stf", storef, 0, /* page 97 */
|
|
[0x27] "stdf", storef, 0,
|
|
[0x25] "stfsr", storef,0,
|
|
[0x26] "stdfq", storef,0,
|
|
|
|
[0x34] "stc", loadc, 0, /* page 99 */
|
|
[0x37] "stdc", loadc, 0,
|
|
[0x35] "stcsr", loadcsr,0,
|
|
[0x36] "stdcq", loadcsr,0,
|
|
|
|
[0x0D] "ldstub", store, 0, /* page 101 */
|
|
[0x1D] "ldstuba", storea, 0,
|
|
|
|
[0x0F] "swap", load, 0, /* page 102 */
|
|
[0x1F] "swapa", loada, 0,
|
|
};
|
|
|
|
#pragma varargck argpos bprint 2
|
|
#pragma varargck type "T" char*
|
|
|
|
/* convert to lower case from upper, according to dascase */
|
|
static int
|
|
Tfmt(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 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)
|
|
{
|
|
ulong 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(uvlong 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, uvlong 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 = sparc64op0[instr.op2].f;
|
|
if(f)
|
|
(*f)(&instr, sparc64op0[instr.op2].mnemonic);
|
|
else
|
|
bprint(&instr, "unknown %lux", instr.w0);
|
|
break;
|
|
|
|
case 1:
|
|
bprint(&instr, "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 = sparc64op2[instr.op3].f;
|
|
if(f)
|
|
(*f)(&instr, sparc64op2[instr.op3].mnemonic);
|
|
else
|
|
bprint(&instr, "unknown %lux", instr.w0);
|
|
break;
|
|
|
|
case 3:
|
|
f = sparc64op3[instr.op3].f;
|
|
if(f)
|
|
(*f)(&instr, sparc64op3[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;
|
|
}
|
|
|
|
static int
|
|
sparc64inst(Map *map, uvlong pc, char modifier, char *buf, int n)
|
|
{
|
|
static int fmtinstalled = 0;
|
|
|
|
/* a modifier of 'I' toggles the dissassembler type */
|
|
if (!fmtinstalled) {
|
|
fmtinstalled = 1;
|
|
fmtinstall('T', Tfmt);
|
|
}
|
|
if ((asstype == ASUNSPARC && modifier == 'i')
|
|
|| (asstype == ASPARC && modifier == 'I'))
|
|
dascase = 'a'-'A';
|
|
else
|
|
dascase = 0;
|
|
return printins(map, pc, buf, n);
|
|
}
|
|
|
|
static int
|
|
sparc64das(Map *map, uvlong 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
|
|
sparc64instlen(Map *map, uvlong pc)
|
|
{
|
|
Instr i;
|
|
|
|
mymap = map;
|
|
if (mkinstr(pc, &i) < 0)
|
|
return -1;
|
|
return i.size*4;
|
|
}
|
|
|
|
static int
|
|
plocal(Instr *i)
|
|
{
|
|
long 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+%lld(SP)", s.name, s.value);
|
|
return 1;
|
|
}
|
|
} else {
|
|
offset = i->simm13-s.value;
|
|
if (getauto(&s, offset-4, CPARAM, &s)) {
|
|
bprint(i, "%s+%ld(FP)", s.name, offset);
|
|
return 1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
address(Instr *i)
|
|
{
|
|
Symbol s, s2;
|
|
uvlong 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;
|
|
geta(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, "+%llux", s.value-off);
|
|
bprint(i, "(SB)");
|
|
return;
|
|
}
|
|
bprint(i, "%ux(R%d)", i->simm13, i->rs1);
|
|
}
|
|
|
|
static void
|
|
unimp(Instr *i, char *m)
|
|
{
|
|
bprint(i, "%T", m);
|
|
}
|
|
|
|
static char *bratab[16] = { /* page 91 */
|
|
[0X8] "A",
|
|
[0X0] "N",
|
|
[0X9] "NE",
|
|
[0X1] "E",
|
|
[0XA] "G",
|
|
[0X2] "LE",
|
|
[0XB] "GE",
|
|
[0X3] "L",
|
|
[0XC] "GU",
|
|
[0X4] "LEU",
|
|
[0XD] "CC",
|
|
[0X5] "CS",
|
|
[0XE] "POS",
|
|
[0X6] "NEG",
|
|
[0XF] "VC",
|
|
[0X7] "VS",
|
|
};
|
|
|
|
static char *fbratab[16] = { /* page 91 */
|
|
[0X8] "A",
|
|
[0X0] "N",
|
|
[0X7] "U",
|
|
[0X6] "G",
|
|
[0X5] "UG",
|
|
[0X4] "L",
|
|
[0X3] "UL",
|
|
[0X2] "LG",
|
|
[0X1] "NE",
|
|
[0X9] "E",
|
|
[0XA] "UE",
|
|
[0XB] "GE",
|
|
[0XC] "UGE",
|
|
[0XD] "LE",
|
|
[0XE] "ULE",
|
|
[0XF] "O",
|
|
};
|
|
|
|
static char *cbratab[16] = { /* page 91 */
|
|
[0X8] "A",
|
|
[0X0] "N",
|
|
[0X7] "3",
|
|
[0X6] "2",
|
|
[0X5] "23",
|
|
[0X4] "1",
|
|
[0X3] "13",
|
|
[0X2] "12",
|
|
[0X1] "123",
|
|
[0X9] "0",
|
|
[0XA] "03",
|
|
[0XB] "02",
|
|
[0XC] "023",
|
|
[0XD] "01",
|
|
[0XE] "013",
|
|
[0XF] "012",
|
|
};
|
|
|
|
static void
|
|
bra1(Instr *i, char *m, char *tab[])
|
|
{
|
|
long imm;
|
|
|
|
imm = i->simmdisp22;
|
|
if(i->a)
|
|
bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase);
|
|
else
|
|
bprint(i, "%T%T\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, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
|
|
else
|
|
bprint(i, "%T%T\t$%ux+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, "%T\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, "%T\tR%d, R%d", m, i->rs1, i->rs2);
|
|
else
|
|
bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
|
|
else
|
|
if(dascase)
|
|
bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
|
|
else
|
|
bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
|
|
}else{
|
|
if(i->rs1 == i->rd)
|
|
if(dascase)
|
|
bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
|
|
else
|
|
bprint(i, "%T\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
|
|
else
|
|
if(dascase)
|
|
bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
|
|
else
|
|
bprint(i, "%T\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, "%T\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, "%T\tR%d, R%d", m, i->rs2, i->rs1);
|
|
}else{
|
|
if(dascase)
|
|
bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13);
|
|
else
|
|
if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
|
|
bprint(i, "MOVW\t$%ux", 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, "%T\t$%ux, 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, $%ux", i->rs1, i->simm13);
|
|
}
|
|
|
|
static char *regtab[4] = {
|
|
"Y",
|
|
"PSTATE",
|
|
"WIM", /* XXX not any more */
|
|
"TT",
|
|
};
|
|
|
|
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, $%ux", 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$%ux, 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, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
|
|
else
|
|
bprint(i, "%T\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, "%T\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, "%T\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, "%T\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
|
|
return;
|
|
}
|
|
bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
|
|
}
|
|
|
|
static int
|
|
sparc64foll(Map *map, uvlong pc, Rgetter rget, uvlong *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;
|
|
}
|