1337 lines
26 KiB
C
1337 lines
26 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <mach.h>
|
|
|
|
static int debug = 0;
|
|
|
|
#define BITS(a, b) ((1<<(b+1))-(1<<a))
|
|
|
|
#define LSR(v, s) ((ulong)(v) >> (s))
|
|
#define ASR(v, s) ((long)(v) >> (s))
|
|
#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
|
|
|
|
|
|
|
|
typedef struct Instr Instr;
|
|
struct Instr
|
|
{
|
|
Map *map;
|
|
ulong w;
|
|
uvlong addr;
|
|
uchar op; /* super opcode */
|
|
|
|
uchar cond; /* bits 28-31 */
|
|
uchar store; /* bit 20 */
|
|
|
|
uchar rd; /* bits 12-15 */
|
|
uchar rn; /* bits 16-19 */
|
|
uchar rs; /* bits 0-11 (shifter operand) */
|
|
|
|
long imm; /* rotated imm */
|
|
char* curr; /* fill point in buffer */
|
|
char* end; /* end of buffer */
|
|
char* err; /* error message */
|
|
};
|
|
|
|
typedef struct Opcode Opcode;
|
|
struct Opcode
|
|
{
|
|
char* o;
|
|
void (*fmt)(Opcode*, Instr*);
|
|
uvlong (*foll)(Map*, Rgetter, Instr*, uvlong);
|
|
char* a;
|
|
};
|
|
|
|
static void format(char*, Instr*, char*);
|
|
static char FRAMENAME[] = ".frame";
|
|
|
|
/*
|
|
* Arm-specific debugger interface
|
|
*/
|
|
|
|
static char *armexcep(Map*, Rgetter);
|
|
static int armfoll(Map*, uvlong, Rgetter, uvlong*);
|
|
static int arminst(Map*, uvlong, char, char*, int);
|
|
static int armdas(Map*, uvlong, char*, int);
|
|
static int arminstlen(Map*, uvlong);
|
|
|
|
/*
|
|
* Debugger interface
|
|
*/
|
|
Machdata armmach =
|
|
{
|
|
{0x70, 0x00, 0x20, 0xE1}, /* break point */ /* E1200070 */
|
|
4, /* break point size */
|
|
|
|
leswab, /* short to local byte order */
|
|
leswal, /* long to local byte order */
|
|
leswav, /* long to local byte order */
|
|
risctrace, /* C traceback */
|
|
riscframe, /* Frame finder */
|
|
armexcep, /* print exception */
|
|
0, /* breakpoint fixup */
|
|
0, /* single precision float printer */
|
|
0, /* double precision float printer */
|
|
armfoll, /* following addresses */
|
|
arminst, /* print instruction */
|
|
armdas, /* dissembler */
|
|
arminstlen, /* instruction size */
|
|
};
|
|
|
|
static char*
|
|
armexcep(Map *map, Rgetter rget)
|
|
{
|
|
uvlong c;
|
|
|
|
c = (*rget)(map, "TYPE");
|
|
switch ((int)c&0x1f) {
|
|
case 0x11:
|
|
return "Fiq interrupt";
|
|
case 0x12:
|
|
return "Mirq interrupt";
|
|
case 0x13:
|
|
return "SVC/SWI Exception";
|
|
case 0x17:
|
|
return "Prefetch Abort/Breakpoint";
|
|
case 0x18:
|
|
return "Data Abort";
|
|
case 0x1b:
|
|
return "Undefined instruction/Breakpoint";
|
|
case 0x1f:
|
|
return "Sys trap";
|
|
default:
|
|
return "Undefined trap";
|
|
}
|
|
}
|
|
|
|
static
|
|
char* cond[16] =
|
|
{
|
|
"EQ", "NE", "CS", "CC",
|
|
"MI", "PL", "VS", "VC",
|
|
"HI", "LS", "GE", "LT",
|
|
"GT", "LE", 0, "NV"
|
|
};
|
|
|
|
static
|
|
char* shtype[4] =
|
|
{
|
|
"<<", ">>", "->", "@>"
|
|
};
|
|
|
|
static
|
|
char *hb[4] =
|
|
{
|
|
"???", "HU", "B", "H"
|
|
};
|
|
|
|
static
|
|
char* addsub[2] =
|
|
{
|
|
"-", "+",
|
|
};
|
|
|
|
int
|
|
armclass(long w)
|
|
{
|
|
int op, done, cp;
|
|
|
|
op = (w >> 25) & 0x7;
|
|
switch(op) {
|
|
case 0: /* data processing r,r,r */
|
|
if((w & 0x0ff00080) == 0x01200000) {
|
|
op = (w >> 4) & 0x7;
|
|
if(op == 7)
|
|
op = 124; /* bkpt */
|
|
else if (op > 0 && op < 4)
|
|
op += 124; /* bx, blx */
|
|
else
|
|
op = 92; /* unk */
|
|
break;
|
|
}
|
|
op = ((w >> 4) & 0xf);
|
|
if(op == 0x9) {
|
|
op = 48+16; /* mul, swp or *rex */
|
|
if((w & 0x0ff00fff) == 0x01900f9f) {
|
|
op = 93; /* ldrex */
|
|
break;
|
|
}
|
|
if((w & 0x0ff00ff0) == 0x01800f90) {
|
|
op = 94; /* strex */
|
|
break;
|
|
}
|
|
if(w & (1<<24)) {
|
|
op += 2;
|
|
if(w & (1<<22))
|
|
op++; /* swpb */
|
|
break;
|
|
}
|
|
if(w & (1<<23)) { /* mullu */
|
|
op = (48+24+4+4+2+2+4);
|
|
if(w & (1<<22)) /* mull */
|
|
op += 2;
|
|
}
|
|
if(w & (1<<21))
|
|
op++; /* mla */
|
|
break;
|
|
}
|
|
if((op & 0x9) == 0x9) /* ld/st byte/half s/u */
|
|
{
|
|
op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
|
|
break;
|
|
}
|
|
op = (w >> 21) & 0xf;
|
|
if(w & (1<<4))
|
|
op += 32;
|
|
else
|
|
if(w & (31<<7 | 3<<5))
|
|
op += 16;
|
|
break;
|
|
case 1: /* data processing i,r,r */
|
|
op = (48) + ((w >> 21) & 0xf);
|
|
break;
|
|
case 2: /* load/store byte/word i(r) */
|
|
if ((w & 0xffffff8f) == 0xf57ff00f) { /* barriers, clrex */
|
|
done = 1;
|
|
switch ((w >> 4) & 7) {
|
|
case 1:
|
|
op = 95; /* clrex */
|
|
break;
|
|
case 4:
|
|
op = 96; /* dsb */
|
|
break;
|
|
case 5:
|
|
op = 97; /* dmb */
|
|
break;
|
|
case 6:
|
|
op = 98; /* isb */
|
|
break;
|
|
default:
|
|
done = 0;
|
|
break;
|
|
}
|
|
if (done)
|
|
break;
|
|
}
|
|
op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
|
|
break;
|
|
case 3: /* load/store byte/word (r)(r) */
|
|
op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
|
|
break;
|
|
case 4: /* block data transfer (r)(r) */
|
|
if ((w & 0xfe50ffff) == 0xf8100a00) { /* v7 RFE */
|
|
op = 99;
|
|
break;
|
|
}
|
|
op = (48+24+4+4) + ((w >> 20) & 0x1);
|
|
break;
|
|
case 5: /* branch / branch link */
|
|
op = (48+24+4+4+2) + ((w >> 24) & 0x1);
|
|
break;
|
|
case 7: /* coprocessor crap */
|
|
cp = (w >> 8) & 0xF;
|
|
if(cp == 10 || cp == 11){ /* vfp */
|
|
if((w >> 4) & 0x1){
|
|
/* vfp register transfer */
|
|
switch((w >> 21) & 0x7){
|
|
case 0:
|
|
op = 118 + ((w >> 20) & 0x1);
|
|
break;
|
|
case 7:
|
|
op = 118+2 + ((w >> 20) & 0x1);
|
|
break;
|
|
default:
|
|
op = (48+24+4+4+2+2+4+4);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
/* vfp data processing */
|
|
if(((w >> 23) & 0x1) == 0){
|
|
op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1);
|
|
break;
|
|
}
|
|
switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){
|
|
case 0:
|
|
op = 108;
|
|
break;
|
|
case 7:
|
|
if(((w >> 19) & 0x1) == 0){
|
|
if(((w >> 17) & 0x1) == 0)
|
|
op = 109 + ((w >> 16) & 0x4) +
|
|
((w >> 15) & 0x2) +
|
|
((w >> 7) & 0x1);
|
|
else if(((w >> 16) & 0x7) == 0x7)
|
|
op = 117;
|
|
}
|
|
else
|
|
switch((w >> 16) & 0x7){
|
|
case 0:
|
|
case 4:
|
|
case 5:
|
|
op = 117;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if(op == 7)
|
|
op = (48+24+4+4+2+2+4+4);
|
|
break;
|
|
}
|
|
op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
|
|
break;
|
|
case 6: /* vfp load / store */
|
|
if(((w >> 21) &0x9) == 0x8){
|
|
op = 122 + ((w >> 20) & 0x1);
|
|
break;
|
|
}
|
|
/* fall through */
|
|
default:
|
|
op = (48+24+4+4+2+2+4+4);
|
|
break;
|
|
}
|
|
return op;
|
|
}
|
|
|
|
static int
|
|
decode(Map *map, uvlong pc, Instr *i)
|
|
{
|
|
ulong w;
|
|
|
|
if(get4(map, pc, &w) < 0) {
|
|
werrstr("can't read instruction: %r");
|
|
return -1;
|
|
}
|
|
i->w = w;
|
|
i->addr = pc;
|
|
i->cond = (w >> 28) & 0xF;
|
|
i->op = armclass(w);
|
|
i->map = map;
|
|
return 1;
|
|
}
|
|
|
|
#pragma varargck argpos bprint 2
|
|
|
|
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
|
|
plocal(Instr *i)
|
|
{
|
|
char *reg;
|
|
Symbol s;
|
|
char *fn;
|
|
int class;
|
|
int offset;
|
|
|
|
if(!findsym(i->addr, CTEXT, &s)) {
|
|
if(debug)fprint(2,"fn not found @%llux: %r\n", i->addr);
|
|
return 0;
|
|
}
|
|
fn = s.name;
|
|
if (!findlocal(&s, FRAMENAME, &s)) {
|
|
if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
|
|
return 0;
|
|
}
|
|
if(s.value > i->imm) {
|
|
class = CAUTO;
|
|
offset = s.value-i->imm;
|
|
reg = "(SP)";
|
|
} else {
|
|
class = CPARAM;
|
|
offset = i->imm-s.value-4;
|
|
reg = "(FP)";
|
|
}
|
|
if(!getauto(&s, offset, class, &s)) {
|
|
if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
|
|
class == CAUTO ? " auto" : "param", offset);
|
|
return 0;
|
|
}
|
|
bprint(i, "%s%c%lld%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Print value v as name[+offset]
|
|
*/
|
|
static int
|
|
gsymoff(char *buf, int n, ulong v, int space)
|
|
{
|
|
Symbol s;
|
|
int r;
|
|
long delta;
|
|
|
|
r = delta = 0; /* to shut compiler up */
|
|
if (v) {
|
|
r = findsym(v, space, &s);
|
|
if (r)
|
|
delta = v-s.value;
|
|
if (delta < 0)
|
|
delta = -delta;
|
|
}
|
|
if (v == 0 || r == 0 || delta >= 4096)
|
|
return snprint(buf, n, "#%lux", v);
|
|
if (strcmp(s.name, ".string") == 0)
|
|
return snprint(buf, n, "#%lux", v);
|
|
if (!delta)
|
|
return snprint(buf, n, "%s", s.name);
|
|
if (s.type != 't' && s.type != 'T')
|
|
return snprint(buf, n, "%s+%llux", s.name, v-s.value);
|
|
else
|
|
return snprint(buf, n, "#%lux", v);
|
|
}
|
|
|
|
static void
|
|
armdps(Opcode *o, Instr *i)
|
|
{
|
|
i->store = (i->w >> 20) & 1;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
i->rs = (i->w >> 0) & 0xf;
|
|
if(i->rn == 15 && i->rs == 0) {
|
|
if(i->op == 8) {
|
|
format("MOVW", i,"CPSR, R%d");
|
|
return;
|
|
} else
|
|
if(i->op == 10) {
|
|
format("MOVW", i,"SPSR, R%d");
|
|
return;
|
|
}
|
|
} else
|
|
if(i->rn == 9 && i->rd == 15) {
|
|
if(i->op == 9) {
|
|
format("MOVW", i, "R%s, CPSR");
|
|
return;
|
|
} else
|
|
if(i->op == 11) {
|
|
format("MOVW", i, "R%s, SPSR");
|
|
return;
|
|
}
|
|
}
|
|
if(i->rd == 15) {
|
|
if(i->op == 120) {
|
|
format("MOVW", i, "PSR, %x");
|
|
return;
|
|
} else
|
|
if(i->op == 121) {
|
|
format("MOVW", i, "%x, PSR");
|
|
return;
|
|
}
|
|
}
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armdpi(Opcode *o, Instr *i)
|
|
{
|
|
ulong v;
|
|
int c;
|
|
|
|
v = (i->w >> 0) & 0xff;
|
|
c = (i->w >> 8) & 0xf;
|
|
while(c) {
|
|
v = (v<<30) | (v>>2);
|
|
c--;
|
|
}
|
|
i->imm = v;
|
|
i->store = (i->w >> 20) & 1;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
i->rs = i->w&0x0f;
|
|
|
|
/* RET is encoded as ADD #0,R14,R15 */
|
|
if((i->w & 0x0fffffff) == 0x028ef000){
|
|
format("RET%C", i, "");
|
|
return;
|
|
}
|
|
if((i->w & 0x0ff0ffff) == 0x0280f000){
|
|
format("B%C", i, "0(R%n)");
|
|
return;
|
|
}
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armsdti(Opcode *o, Instr *i)
|
|
{
|
|
ulong v;
|
|
|
|
v = i->w & 0xfff;
|
|
if(!(i->w & (1<<23)))
|
|
v = -v;
|
|
i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
|
|
i->imm = v;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
/* RET is encoded as LW.P x,R13,R15 */
|
|
if ((i->w & 0x0ffff000) == 0x049df000)
|
|
{
|
|
format("RET%C%p", i, "%I");
|
|
return;
|
|
}
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armvstdi(Opcode *o, Instr *i)
|
|
{
|
|
ulong v;
|
|
|
|
v = (i->w & 0xff) << 2;
|
|
if(!(i->w & (1<<23)))
|
|
v = -v;
|
|
i->imm = v;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
/* arm V4 ld/st halfword, signed byte */
|
|
static void
|
|
armhwby(Opcode *o, Instr *i)
|
|
{
|
|
i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
|
|
i->imm = (i->w & 0xf) | ((i->w >> 4) & 0xf0);
|
|
if (!(i->w & (1 << 23)))
|
|
i->imm = - i->imm;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
i->rs = (i->w >> 0) & 0xf;
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armsdts(Opcode *o, Instr *i)
|
|
{
|
|
i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
|
|
i->rs = (i->w >> 0) & 0xf;
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armbdt(Opcode *o, Instr *i)
|
|
{
|
|
i->store = (i->w >> 21) & 0x3; /* S & W bits */
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->imm = i->w & 0xffff;
|
|
if(i->w == 0xe8fd8000)
|
|
format("RFE", i, "");
|
|
else
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armund(Opcode *o, Instr *i)
|
|
{
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armcdt(Opcode *o, Instr *i)
|
|
{
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armunk(Opcode *o, Instr *i)
|
|
{
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armb(Opcode *o, Instr *i)
|
|
{
|
|
ulong v;
|
|
|
|
v = i->w & 0xffffff;
|
|
if(v & 0x800000)
|
|
v |= ~0xffffff;
|
|
i->imm = (v<<2) + i->addr + 8;
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armbpt(Opcode *o, Instr *i)
|
|
{
|
|
i->imm = ((i->w >> 4) & 0xfff0) | (i->w &0xf);
|
|
format(o->o, i, o->a);
|
|
}
|
|
|
|
static void
|
|
armco(Opcode *o, Instr *i) /* coprocessor instructions */
|
|
{
|
|
int op, p, cp;
|
|
|
|
char buf[1024];
|
|
|
|
i->rn = (i->w >> 16) & 0xf;
|
|
i->rd = (i->w >> 12) & 0xf;
|
|
i->rs = i->w&0xf;
|
|
cp = (i->w >> 8) & 0xf;
|
|
p = (i->w >> 5) & 0x7;
|
|
if(i->w&(1<<4)) {
|
|
op = (i->w >> 21) & 0x07;
|
|
snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
|
|
} else {
|
|
op = (i->w >> 20) & 0x0f;
|
|
snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
|
|
}
|
|
format(o->o, i, buf);
|
|
}
|
|
|
|
static int
|
|
armcondpass(Map *map, Rgetter rget, uchar cond)
|
|
{
|
|
uvlong psr;
|
|
uchar n;
|
|
uchar z;
|
|
uchar c;
|
|
uchar v;
|
|
|
|
psr = rget(map, "PSR");
|
|
n = (psr >> 31) & 1;
|
|
z = (psr >> 30) & 1;
|
|
c = (psr >> 29) & 1;
|
|
v = (psr >> 28) & 1;
|
|
|
|
switch(cond) {
|
|
default:
|
|
case 0: return z;
|
|
case 1: return !z;
|
|
case 2: return c;
|
|
case 3: return !c;
|
|
case 4: return n;
|
|
case 5: return !n;
|
|
case 6: return v;
|
|
case 7: return !v;
|
|
case 8: return c && !z;
|
|
case 9: return !c || z;
|
|
case 10: return n == v;
|
|
case 11: return n != v;
|
|
case 12: return !z && (n == v);
|
|
case 13: return z || (n != v);
|
|
case 14: return 1;
|
|
case 15: return 0;
|
|
}
|
|
}
|
|
|
|
static ulong
|
|
armshiftval(Map *map, Rgetter rget, Instr *i)
|
|
{
|
|
if(i->w & (1 << 25)) { /* immediate */
|
|
ulong imm = i->w & BITS(0, 7);
|
|
ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
|
|
return ROR(imm, s);
|
|
} else {
|
|
char buf[8];
|
|
ulong v;
|
|
ulong s = (i->w & BITS(7,11)) >> 7;
|
|
|
|
sprint(buf, "R%ld", i->w & 0xf);
|
|
v = rget(map, buf);
|
|
|
|
switch((i->w & BITS(4, 6)) >> 4) {
|
|
default:
|
|
case 0: /* LSLIMM */
|
|
return v << s;
|
|
case 1: /* LSLREG */
|
|
sprint(buf, "R%lud", s >> 1);
|
|
s = rget(map, buf) & 0xFF;
|
|
if(s >= 32) return 0;
|
|
return v << s;
|
|
case 2: /* LSRIMM */
|
|
return LSR(v, s);
|
|
case 3: /* LSRREG */
|
|
sprint(buf, "R%ld", s >> 1);
|
|
s = rget(map, buf) & 0xFF;
|
|
if(s >= 32) return 0;
|
|
return LSR(v, s);
|
|
case 4: /* ASRIMM */
|
|
if(s == 0) {
|
|
if((v & (1U<<31)) == 0)
|
|
return 0;
|
|
return 0xFFFFFFFF;
|
|
}
|
|
return ASR(v, s);
|
|
case 5: /* ASRREG */
|
|
sprint(buf, "R%ld", s >> 1);
|
|
s = rget(map, buf) & 0xFF;
|
|
if(s >= 32) {
|
|
if((v & (1U<<31)) == 0)
|
|
return 0;
|
|
return 0xFFFFFFFF;
|
|
}
|
|
return ASR(v, s);
|
|
case 6: /* RORIMM */
|
|
if(s == 0) {
|
|
ulong c = (rget(map, "PSR") >> 29) & 1;
|
|
|
|
return (c << 31) | LSR(v, 1);
|
|
}
|
|
return ROR(v, s);
|
|
case 7: /* RORREG */
|
|
sprint(buf, "R%ld", s >> 1);
|
|
s = rget(map, buf) & 0x1F;
|
|
if(s == 0)
|
|
return v;
|
|
return ROR(v, s);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
nbits(ulong v)
|
|
{
|
|
int n = 0;
|
|
int i;
|
|
|
|
for(i=0; i < 32 ; i++) {
|
|
if(v & 1) ++n;
|
|
v >>= 1;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static ulong
|
|
armmaddr(Map *map, Rgetter rget, Instr *i)
|
|
{
|
|
ulong v;
|
|
ulong nb;
|
|
char buf[8];
|
|
ulong rn;
|
|
|
|
rn = (i->w >> 16) & 0xf;
|
|
sprint(buf,"R%ld", rn);
|
|
|
|
v = rget(map, buf);
|
|
nb = nbits(i->w & ((1 << 15) - 1));
|
|
|
|
switch((i->w >> 23) & 3) {
|
|
default:
|
|
case 0: return (v - (nb*4)) + 4;
|
|
case 1: return v;
|
|
case 2: return v - (nb*4);
|
|
case 3: return v + 4;
|
|
}
|
|
}
|
|
|
|
static uvlong
|
|
armaddr(Map *map, Rgetter rget, Instr *i)
|
|
{
|
|
char buf[8];
|
|
ulong rn;
|
|
|
|
snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf);
|
|
rn = rget(map, buf);
|
|
|
|
if((i->w & (1<<24)) == 0) /* POSTIDX */
|
|
return rn;
|
|
|
|
if((i->w & (1<<25)) == 0) { /* OFFSET */
|
|
if(i->w & (1U<<23))
|
|
return rn + (i->w & BITS(0,11));
|
|
return rn - (i->w & BITS(0,11));
|
|
} else { /* REGOFF */
|
|
ulong index = 0;
|
|
uchar c;
|
|
uchar rm;
|
|
|
|
sprint(buf, "R%ld", i->w & 0xf);
|
|
rm = rget(map, buf);
|
|
|
|
switch((i->w & BITS(5,6)) >> 5) {
|
|
case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
|
|
case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
|
|
case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
|
|
case 3:
|
|
if((i->w & BITS(7,11)) == 0) {
|
|
c = (rget(map, "PSR") >> 29) & 1;
|
|
index = c << 31 | LSR(rm, 1);
|
|
} else {
|
|
index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
|
|
}
|
|
break;
|
|
}
|
|
if(i->w & (1<<23))
|
|
return rn + index;
|
|
return rn - index;
|
|
}
|
|
}
|
|
|
|
static uvlong
|
|
armfadd(Map *map, Rgetter rget, Instr *i, uvlong pc)
|
|
{
|
|
char buf[8];
|
|
int r;
|
|
|
|
r = (i->w >> 12) & 0xf;
|
|
if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
|
|
return pc+4;
|
|
|
|
r = (i->w >> 16) & 0xf;
|
|
sprint(buf, "R%d", r);
|
|
|
|
return rget(map, buf) + armshiftval(map, rget, i);
|
|
}
|
|
|
|
static uvlong
|
|
armfbx(Map *map, Rgetter rget, Instr *i, uvlong pc)
|
|
{
|
|
char buf[8];
|
|
int r;
|
|
|
|
if(!armcondpass(map, rget, (i->w>>28)&0xf))
|
|
return pc+4;
|
|
r = (i->w >> 0) & 0xf;
|
|
sprint(buf, "R%d", r);
|
|
return rget(map, buf);
|
|
}
|
|
|
|
static uvlong
|
|
armfmovm(Map *map, Rgetter rget, Instr *i, uvlong pc)
|
|
{
|
|
ulong v;
|
|
ulong addr;
|
|
|
|
v = i->w & 1<<15;
|
|
if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
|
|
return pc+4;
|
|
|
|
addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
|
|
if(get4(map, addr, &v) < 0) {
|
|
werrstr("can't read addr: %r");
|
|
return -1;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static uvlong
|
|
armfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc)
|
|
{
|
|
if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
|
|
return pc+4;
|
|
|
|
return pc + (((signed long)i->w << 8) >> 6) + 8;
|
|
}
|
|
|
|
static uvlong
|
|
armfmov(Map *map, Rgetter rget, Instr *i, uvlong pc)
|
|
{
|
|
ulong rd, v;
|
|
|
|
rd = (i->w >> 12) & 0xf;
|
|
if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
|
|
return pc+4;
|
|
|
|
/* LDR */
|
|
/* BUG: Needs LDH/B, too */
|
|
if(((i->w>>26)&0x3) == 1) {
|
|
if(get4(map, armaddr(map, rget, i), &v) < 0) {
|
|
werrstr("can't read instruction: %r");
|
|
return pc+4;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/* MOV */
|
|
v = armshiftval(map, rget, i);
|
|
|
|
return v;
|
|
}
|
|
|
|
static Opcode opcodes[] =
|
|
{
|
|
"AND%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"EOR%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"SUB%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"RSB%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
|
|
"ADC%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"SBC%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"RSC%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"TST%C%S", armdps, 0, "R%s,R%n",
|
|
"TEQ%C%S", armdps, 0, "R%s,R%n",
|
|
"CMP%C%S", armdps, 0, "R%s,R%n",
|
|
"CMN%C%S", armdps, 0, "R%s,R%n",
|
|
"ORR%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"MOVW%C%S", armdps, armfmov, "R%s,R%d",
|
|
"BIC%C%S", armdps, 0, "R%s,R%n,R%d",
|
|
"MVN%C%S", armdps, 0, "R%s,R%d",
|
|
|
|
/* 16 */
|
|
"AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
|
|
"ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"TST%C%S", armdps, 0, "(R%s%h%m),R%n",
|
|
"TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
|
|
"CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
|
|
"CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
|
|
"ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
|
|
"BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
|
|
"MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
|
|
|
|
/* 32 */
|
|
"AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
|
|
"ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
|
|
"TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
|
|
"CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
|
|
"CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
|
|
"ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
|
|
"BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
|
|
"MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
|
|
|
|
/* 48 */
|
|
"AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
|
|
"ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"TST%C%S", armdpi, 0, "$#%i,R%n",
|
|
"TEQ%C%S", armdpi, 0, "$#%i,R%n",
|
|
"CMP%C%S", armdpi, 0, "$#%i,R%n",
|
|
"CMN%C%S", armdpi, 0, "$#%i,R%n",
|
|
"ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
|
|
"BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
|
|
"MVN%C%S", armdpi, 0, "$#%i,R%d",
|
|
|
|
/* 48+16 */
|
|
"MUL%C%S", armdpi, 0, "R%M,R%s,R%n",
|
|
"MULA%C%S", armdpi, 0, "R%M,R%s,R%n,R%d",
|
|
"SWPW", armdpi, 0, "R%s,(R%n),R%d",
|
|
"SWPB", armdpi, 0, "R%s,(R%n),R%d",
|
|
|
|
/* 48+16+4 */
|
|
"MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%s)",
|
|
"MOV%u%C%p", armhwby, 0, "R%d,%I",
|
|
"MOV%u%C%p", armhwby, armfmov, "(R%n%UR%s),R%d",
|
|
"MOV%u%C%p", armhwby, armfmov, "%I,R%d",
|
|
|
|
/* 48+24 */
|
|
"MOVW%C%p", armsdti, 0, "R%d,%I",
|
|
"MOVB%C%p", armsdti, 0, "R%d,%I",
|
|
"MOVW%C%p", armsdti, armfmov, "%I,R%d",
|
|
"MOVBU%C%p", armsdti, armfmov, "%I,R%d",
|
|
|
|
"MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
|
|
"MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
|
|
"MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
|
|
"MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
|
|
|
|
"MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
|
|
"MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
|
|
|
|
"B%C", armb, armfbranch, "%b",
|
|
"BL%C", armb, armfbranch, "%b",
|
|
|
|
"CDP%C", armco, 0, "",
|
|
"CDP%C", armco, 0, "",
|
|
"MCR%C", armco, 0, "",
|
|
"MRC%C", armco, 0, "",
|
|
|
|
/* 48+24+4+4+2+2+4 */
|
|
"MULLU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
|
|
"MULALU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
|
|
"MULL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
|
|
"MULAL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
|
|
|
|
/* 48+24+4+4+2+2+4+4 = 92 */
|
|
"UNK", armunk, 0, "",
|
|
|
|
/* new v7 arch instructions */
|
|
/* 93 */
|
|
"LDREX", armdpi, 0, "(R%n),R%d",
|
|
"STREX", armdpi, 0, "R%s,(R%n),R%d",
|
|
"CLREX", armunk, 0, "",
|
|
|
|
/* 96 */
|
|
"DSB", armunk, 0, "",
|
|
"DMB", armunk, 0, "",
|
|
"ISB", armunk, 0, "",
|
|
|
|
/* 99 */
|
|
"RFEV7%P%a", armbdt, 0, "(R%n)",
|
|
|
|
/* 100 */
|
|
"MLA%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"MLS%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"NMLS%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"NMLA%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"MUL%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"NMUL%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"ADD%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"SUB%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
"DIV%f%C", armdps, 0, "F%s,F%n,F%d",
|
|
|
|
/* 109 */
|
|
"MOV%f%C", armdps, 0, "F%s,F%d",
|
|
"ABS%f%C", armdps, 0, "F%s,F%d",
|
|
"NEG%f%C", armdps, 0, "F%s,F%d",
|
|
"SQRT%f%C", armdps, 0, "F%s,F%d",
|
|
"CMP%f%C", armdps, 0, "F%s,F%d",
|
|
"CMPE%f%C", armdps, 0, "F%s,F%d",
|
|
"CMP%f%C", armdps, 0, "$0.0,F%d",
|
|
"CMPE%f%C", armdps, 0, "$0.0,F%d",
|
|
|
|
/* 117 */
|
|
"MOV%F%R%C", armdps, 0, "F%s,F%d",
|
|
|
|
/* 118 */
|
|
"MOVW%C", armdps, 0, "R%d,F%n",
|
|
"MOVW%C", armdps, 0, "F%n,R%d",
|
|
"MOVW%C", armdps, 0, "R%d,%x",
|
|
"MOVW%C", armdps, 0, "%x,R%d",
|
|
|
|
/* 122 */
|
|
"MOV%f%C", armvstdi, 0, "F%d,%I",
|
|
"MOV%f%C", armvstdi, 0, "%I,F%d",
|
|
|
|
/* 124 */
|
|
"BKPT%C", armbpt, 0, "$#%i",
|
|
"BX%C", armdps, armfbx, "(R%s)",
|
|
"BXJ%C", armdps, armfbx, "(R%s)",
|
|
"BLX%C", armdps, armfbx, "(R%s)",
|
|
};
|
|
|
|
static void
|
|
gaddr(Instr *i)
|
|
{
|
|
*i->curr++ = '$';
|
|
i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
|
|
}
|
|
|
|
static char *mode[] = { 0, "IA", "DB", "IB" };
|
|
static char *pw[] = { "P", "PW", 0, "W" };
|
|
static char *sw[] = { 0, "W", "S", "SW" };
|
|
|
|
static void
|
|
format(char *mnemonic, Instr *i, char *f)
|
|
{
|
|
int j, k, m, n;
|
|
int g;
|
|
char *fmt;
|
|
|
|
if(mnemonic)
|
|
format(0, i, mnemonic);
|
|
if(f == 0)
|
|
return;
|
|
if(mnemonic)
|
|
if(i->curr < i->end)
|
|
*i->curr++ = '\t';
|
|
for ( ; *f && i->curr < i->end; f++) {
|
|
if(*f != '%') {
|
|
*i->curr++ = *f;
|
|
continue;
|
|
}
|
|
switch (*++f) {
|
|
|
|
case 'C': /* .CONDITION */
|
|
if(cond[i->cond])
|
|
bprint(i, ".%s", cond[i->cond]);
|
|
break;
|
|
|
|
case 'S': /* .STORE */
|
|
if(i->store)
|
|
bprint(i, ".S");
|
|
break;
|
|
|
|
case 'P': /* P & U bits for block move */
|
|
n = (i->w >>23) & 0x3;
|
|
if (mode[n])
|
|
bprint(i, ".%s", mode[n]);
|
|
break;
|
|
|
|
case 'p': /* P & W bits for single data xfer*/
|
|
if (pw[i->store])
|
|
bprint(i, ".%s", pw[i->store]);
|
|
break;
|
|
|
|
case 'a': /* S & W bits for single data xfer*/
|
|
if (sw[i->store])
|
|
bprint(i, ".%s", sw[i->store]);
|
|
break;
|
|
|
|
case 's':
|
|
bprint(i, "%d", i->rs & 0xf);
|
|
break;
|
|
|
|
case 'M':
|
|
bprint(i, "%lud", (i->w>>8) & 0xf);
|
|
break;
|
|
|
|
case 'm':
|
|
n = (i->w>>7) & 0x1f;
|
|
if (n == 0 && (i->w & (3<<5)) != 0)
|
|
n = 32;
|
|
bprint(i, "%d", n);
|
|
break;
|
|
|
|
case 'h':
|
|
bprint(i, shtype[(i->w>>5) & 0x3]);
|
|
break;
|
|
|
|
case 'u': /* Signed/unsigned Byte/Halfword */
|
|
bprint(i, hb[(i->w>>5) & 0x3]);
|
|
break;
|
|
|
|
case 'I':
|
|
if (i->rn == 13) {
|
|
if (plocal(i))
|
|
break;
|
|
}
|
|
g = 0;
|
|
fmt = "#%lx(R%d)";
|
|
if (i->rn == 15) {
|
|
/* convert load of offset(PC) to a load immediate */
|
|
if (get4(i->map, i->addr+i->imm+8, (ulong*)&i->imm) > 0)
|
|
{
|
|
g = 1;
|
|
fmt = "";
|
|
}
|
|
}
|
|
if (mach->sb)
|
|
{
|
|
if (i->rd == 11) {
|
|
ulong nxti;
|
|
|
|
if (get4(i->map, i->addr+4, &nxti) > 0) {
|
|
if ((nxti & 0x0e0f0fff) == 0x060c000b) {
|
|
i->imm += mach->sb;
|
|
g = 1;
|
|
fmt = "-SB";
|
|
}
|
|
}
|
|
}
|
|
if (i->rn == 12)
|
|
{
|
|
i->imm += mach->sb;
|
|
g = 1;
|
|
fmt = "-SB(SB)";
|
|
}
|
|
}
|
|
if (g)
|
|
{
|
|
gaddr(i);
|
|
bprint(i, fmt, i->rn);
|
|
}
|
|
else
|
|
bprint(i, fmt, i->imm, i->rn);
|
|
break;
|
|
case 'U': /* Add/subtract from base */
|
|
bprint(i, addsub[(i->w >> 23) & 1]);
|
|
break;
|
|
|
|
case 'n':
|
|
bprint(i, "%d", i->rn);
|
|
break;
|
|
|
|
case 'd':
|
|
bprint(i, "%d", i->rd);
|
|
break;
|
|
|
|
case 'i':
|
|
bprint(i, "%lux", i->imm);
|
|
break;
|
|
|
|
case 'b':
|
|
i->curr += symoff(i->curr, i->end-i->curr,
|
|
(ulong)i->imm, CTEXT);
|
|
break;
|
|
|
|
case 'g':
|
|
i->curr += gsymoff(i->curr, i->end-i->curr,
|
|
i->imm, CANY);
|
|
break;
|
|
|
|
case 'f':
|
|
switch((i->w >> 8) & 0xF){
|
|
case 10:
|
|
bprint(i, "F");
|
|
break;
|
|
case 11:
|
|
bprint(i, "D");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'F':
|
|
switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){
|
|
case 0x0:
|
|
bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U");
|
|
break;
|
|
case 0x1:
|
|
bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U");
|
|
break;
|
|
case 0x8:
|
|
bprint(i, "FW.U");
|
|
break;
|
|
case 0x9:
|
|
bprint(i, "DW.U");
|
|
break;
|
|
case 0xA:
|
|
bprint(i, "FW");
|
|
break;
|
|
case 0xB:
|
|
bprint(i, "DW");
|
|
break;
|
|
case 0xE:
|
|
bprint(i, "FD");
|
|
break;
|
|
case 0xF:
|
|
bprint(i, "DF");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'R':
|
|
if(((i->w >> 7) & 0x1) == 0)
|
|
bprint(i, "R");
|
|
break;
|
|
|
|
case 'x':
|
|
switch(i->rn){
|
|
case 0:
|
|
bprint(i, "FPSID");
|
|
break;
|
|
case 1:
|
|
bprint(i, "FPSCR");
|
|
break;
|
|
case 2:
|
|
bprint(i, "FPEXC");
|
|
break;
|
|
default:
|
|
bprint(i, "FPS(%d)", i->rn);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
n = i->imm&0xffff;
|
|
j = 0;
|
|
k = 0;
|
|
while(n) {
|
|
m = j;
|
|
while(n&0x1) {
|
|
j++;
|
|
n >>= 1;
|
|
}
|
|
if(j != m) {
|
|
if(k)
|
|
bprint(i, ",");
|
|
if(j == m+1)
|
|
bprint(i, "R%d", m);
|
|
else
|
|
bprint(i, "R%d-R%d", m, j-1);
|
|
k = 1;
|
|
}
|
|
j++;
|
|
n >>= 1;
|
|
}
|
|
break;
|
|
|
|
case '\0':
|
|
*i->curr++ = '%';
|
|
return;
|
|
|
|
default:
|
|
bprint(i, "%%%c", *f);
|
|
break;
|
|
}
|
|
}
|
|
*i->curr = 0;
|
|
}
|
|
|
|
static int
|
|
printins(Map *map, uvlong pc, char *buf, int n)
|
|
{
|
|
Instr i;
|
|
|
|
i.curr = buf;
|
|
i.end = buf+n-1;
|
|
if(decode(map, pc, &i) < 0)
|
|
return -1;
|
|
|
|
(*opcodes[i.op].fmt)(&opcodes[i.op], &i);
|
|
return 4;
|
|
}
|
|
|
|
static int
|
|
arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
|
|
{
|
|
USED(modifier);
|
|
return printins(map, pc, buf, n);
|
|
}
|
|
|
|
static int
|
|
armdas(Map *map, uvlong pc, char *buf, int n)
|
|
{
|
|
Instr i;
|
|
|
|
i.curr = buf;
|
|
i.end = buf+n;
|
|
if(decode(map, pc, &i) < 0)
|
|
return -1;
|
|
if(i.end-i.curr > 8)
|
|
i.curr = _hexify(buf, i.w, 7);
|
|
*i.curr = 0;
|
|
return 4;
|
|
}
|
|
|
|
static int
|
|
arminstlen(Map *map, uvlong pc)
|
|
{
|
|
Instr i;
|
|
|
|
if(decode(map, pc, &i) < 0)
|
|
return -1;
|
|
return 4;
|
|
}
|
|
|
|
static int
|
|
armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
|
|
{
|
|
uvlong d;
|
|
Instr i;
|
|
|
|
if(decode(map, pc, &i) < 0)
|
|
return -1;
|
|
|
|
if(opcodes[i.op].foll) {
|
|
d = (*opcodes[i.op].foll)(map, rget, &i, pc);
|
|
if(d == -1)
|
|
return -1;
|
|
} else
|
|
d = pc+4;
|
|
|
|
foll[0] = d;
|
|
return 1;
|
|
}
|