mirror of
https://github.com/radareorg/radare2.git
synced 2025-01-23 22:36:27 +00:00
* Implement ldmia/stmia in armthumb_assemble
- added also: yield, wfe, wfi, sev, bkpt - fix ldr{bh} and str{bh} * Initial implementation of the arm-thumb code analysis module
This commit is contained in:
parent
284abdfb87
commit
daa5d0fd38
@ -27,7 +27,7 @@ static unsigned int disarm_branch_offset (unsigned int pc, unsigned int insoff)
|
||||
#define IS_RETURN(x) \
|
||||
((x&(ARM_DTM_I_MASK|ARM_DTM_LOAD|(1<<15))) == (ARM_DTM_I|ARM_DTM_LOAD|(1<<15)))
|
||||
|
||||
//if ( (inst & ( ARM_DTX_I_MASK | ARM_DTX_LOAD | ( ARM_DTX_RD_MASK ) ) ) == ( ARM_DTX_LOAD | ARM_DTX_I | ( ARM_PC << 12 ) ) )
|
||||
//if ( (inst & ( ARM_DTX_I_MASK | ARM_DTX_LOAD | ( ARM_DTX_RD_MASK ) ) ) == ( ARM_DTX_LOAD | ARM_DTX_I | ( ARM_PC << 12 ) ) )
|
||||
#define IS_UNKJMP(x) \
|
||||
(( (( ARM_DTX_RD_MASK ) ) ) == ( ARM_DTX_LOAD | ARM_DTX_I | ( ARM_PC << 12 ) ))
|
||||
|
||||
@ -40,10 +40,48 @@ static unsigned int disarm_branch_offset (unsigned int pc, unsigned int insoff)
|
||||
#define IS_EXITPOINT(x) \
|
||||
(IS_BRANCH (x) || IS_RETURN (x) || IS_UNKJMP (x))
|
||||
|
||||
#define API static
|
||||
#include "../../asm/arch/arm/armthumb.c"
|
||||
|
||||
static int aop_thumb(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
|
||||
ut16 *_ins = (ut16*)data;
|
||||
ut16 ins = *_ins;
|
||||
aop->length = armthumb_length (ins);
|
||||
// TODO: implement load/store analysis
|
||||
if (ins == 0xbf) {
|
||||
// TODO: add support for more NOP instructions
|
||||
aop->type = R_ANAL_OP_TYPE_NOP;
|
||||
} else
|
||||
if ( (ins & _($1111,0,0,0)) == _($1101,0,0,0) ) {
|
||||
// BNE..
|
||||
int delta = (ins & _(0,0,$1111,$1111));
|
||||
aop->type = R_ANAL_OP_TYPE_CJMP;
|
||||
aop->jump = addr+8+(delta<<1);
|
||||
aop->fail = addr+4;
|
||||
} else if ( (ins & _($1110,$1000,0,0)) == _($1110,0,0,0) ) {
|
||||
// B
|
||||
int delta = (ins & _(0,0,$1111,$1111));
|
||||
aop->type = R_ANAL_OP_TYPE_JMP;
|
||||
aop->jump = addr+8+(delta<<1);
|
||||
aop->fail = addr+4;
|
||||
} else if ( (ins & _($1111,$1111,0,0)) == _($0100,$0111,0,0) ) {
|
||||
// BLX
|
||||
aop->type = R_ANAL_OP_TYPE_UJMP;
|
||||
aop->jump = (ut32)(ins & _(0,0,$0111,$1000)) >> 3;
|
||||
aop->fail = addr+4;
|
||||
} else if ( (ins & _($1111,$1111,0,0)) == _($1011,$1110,0,0) ) {
|
||||
aop->type = R_ANAL_OP_TYPE_TRAP;
|
||||
aop->value = (ut64)(ins>>8);
|
||||
} else if ( (ins & _($1111,$1111,0,0)) == _($1101,$1111,0,0)) {
|
||||
aop->type = R_ANAL_OP_TYPE_SWI;
|
||||
aop->value = (ut64)(ins>>8);
|
||||
}
|
||||
return aop->length;
|
||||
}
|
||||
|
||||
static int aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
|
||||
unsigned int i = 0;
|
||||
unsigned int* code = (unsigned int *)data;
|
||||
unsigned int branch_dst_addr;
|
||||
ut32 branch_dst_addr, i = 0;
|
||||
ut32* code = (ut32 *)data;
|
||||
const ut8 *b = (ut8 *)data;
|
||||
|
||||
if (data == NULL)
|
||||
@ -52,14 +90,11 @@ static int aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
|
||||
memset (aop, '\0', sizeof (RAnalOp));
|
||||
aop->addr = addr;
|
||||
aop->type = R_ANAL_OP_TYPE_UNK;
|
||||
aop->length = (anal->bits==16)?2:4;
|
||||
aop->jump = aop->fail = -1;
|
||||
aop->ref = aop->value = -1;
|
||||
|
||||
if (aop == NULL)
|
||||
return aop->length;
|
||||
memset (aop, '\0', sizeof (RAnalOp));
|
||||
aop->type = R_ANAL_OP_TYPE_UNK;
|
||||
if (anal->bits==16)
|
||||
return aop_thumb(anal, aop, addr, data, len);
|
||||
aop->length = 4;
|
||||
#if 0
|
||||
fprintf(stderr, "CODE %02x %02x %02x %02x\n",
|
||||
codeA[0], codeA[1], codeA[2], codeA[3]);
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
// TODO: only lo registers accessible in thumb arm
|
||||
// TODO: add support for ldrb, ldrh, strb, strh
|
||||
|
||||
typedef struct {
|
||||
unsigned long off;
|
||||
int o;
|
||||
char op[32];
|
||||
char opstr[32];
|
||||
char *a0, *a1, *a2;
|
||||
} ArmOpcode;
|
||||
|
||||
@ -131,6 +131,23 @@ static int getreg(const char *str) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int getlist(char *op) {
|
||||
int reg, list = 0;
|
||||
char *ptr = strchr (op, '{');
|
||||
if (ptr) {
|
||||
do {
|
||||
ptr++;
|
||||
while (*ptr && *ptr == ' ') ptr++;
|
||||
reg = getreg (ptr);
|
||||
if (reg == -1)
|
||||
break;
|
||||
list |= (1<<reg);
|
||||
while (*ptr && *ptr!=',') ptr++;
|
||||
} while (*ptr && *ptr==',');
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static int getshift(const char *str) {
|
||||
if (!str) return 0;
|
||||
while (str && *str&&!atoi (str))
|
||||
@ -140,7 +157,8 @@ static int getshift(const char *str) {
|
||||
|
||||
static void arm_opcode_parse(ArmOpcode *ao, const char *str) {
|
||||
memset (ao, 0, sizeof (ArmOpcode));
|
||||
strncpy (ao->op, str, sizeof (ao->op));
|
||||
strncpy (ao->op, str, sizeof (ao->op)-1);
|
||||
strcpy (ao->opstr, str);
|
||||
ao->a0 = strchr (ao->op, ' ');
|
||||
if (ao->a0) {
|
||||
*ao->a0 = 0;
|
||||
@ -176,32 +194,35 @@ static inline int arm_opcode_cond(ArmOpcode *ao, int delta) {
|
||||
return cond;
|
||||
}
|
||||
|
||||
// str, ldr
|
||||
// TODO: group similar instructions like for non-thumb
|
||||
static int thumb_assemble(ArmOpcode *ao, const char *str) {
|
||||
// TODO: Add thumb mode
|
||||
// mov r, n = 2[r0-7][nn]
|
||||
// mov r, r = 46[7bits,7bits]
|
||||
// cmp r, n = 2[r(8-f)-8][nn]
|
||||
// cmp r, r = 45[7bits,7bits]
|
||||
// subs r, n = 3[r(8-f)-8][nn]
|
||||
//
|
||||
// and r, r = 40[7bits=r][7bits=r]
|
||||
// asrs = 41
|
||||
// tst r, r = 42[7bits,7bits]
|
||||
// orr = 43
|
||||
//
|
||||
// b[cond] n = d[cond][nn]
|
||||
// b.n = e0[nn] =
|
||||
// bx rN = 47[7bits(regidx)][7bits(ignored)]
|
||||
// bl = 4 bytes = f0[nn][????]
|
||||
// add r0, pc, n = a[r0-7][nn]
|
||||
// add r0, sp, n = a[r(8-f)-8][nn]
|
||||
// rasm2 -b 16 -a arm -e -d 2700 // movs r7, #0
|
||||
|
||||
if (!strcmp (ao->op, "ldmia")) {
|
||||
ao->o = 0xc8 + getreg (ao->a0);
|
||||
ao->o |= getlist(ao->opstr) << 8;
|
||||
} else
|
||||
if (!strcmp (ao->op, "stmia")) {
|
||||
ao->o = 0xc0 + getreg (ao->a0);
|
||||
ao->o |= getlist(ao->opstr) << 8;
|
||||
} else
|
||||
if (!strcmp (ao->op, "nop")) {
|
||||
ao->o = 0xbf;
|
||||
} else
|
||||
if (!strcmp (ao->op, "yield")) {
|
||||
ao->o = 0x10bf;
|
||||
} else
|
||||
if (!strcmp (ao->op, "wfe")) {
|
||||
ao->o = 0x20bf;
|
||||
} else
|
||||
if (!strcmp (ao->op, "wfi")) {
|
||||
ao->o = 0x30bf;
|
||||
} else
|
||||
if (!strcmp (ao->op, "sev")) {
|
||||
ao->o = 0x40bf;
|
||||
} else
|
||||
if (!strcmp (ao->op, "bkpt")) {
|
||||
ao->o = 0xbe;
|
||||
ao->o |= (0xff & getnum (ao->a0))<<8;
|
||||
} else
|
||||
if (!strcmp (ao->op, "and")) {
|
||||
ao->o = 0x40;
|
||||
ao->o |= (0xff & getreg (ao->a0)) << 8;
|
||||
@ -241,26 +262,32 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
|
||||
}
|
||||
} else
|
||||
if (!memcmp (ao->op, "ldr", 3)) {
|
||||
getrange (ao->a1);
|
||||
getrange (ao->a2);
|
||||
if (ao->op[3]=='h') {
|
||||
int a0 = getreg (ao->a0);
|
||||
int a1 = getreg (ao->a1);
|
||||
int a2 = getreg (ao->a2);
|
||||
ao->o = 0x88; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2); // XXX: handle limit
|
||||
if (a2 ==-1) {
|
||||
a2 = getnum (ao->a2)/8;
|
||||
ao->o = 0x88; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o += (7&a2);
|
||||
} else return 0;
|
||||
} else
|
||||
if (ao->op[3]=='b') {
|
||||
int a0 = getreg (ao->a0);
|
||||
int a1 = getreg (ao->a1);
|
||||
int a2 = getreg (ao->a2);
|
||||
ao->o = 0x78; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2); // XXX: handle limit
|
||||
if (a2 ==-1) {
|
||||
a2 = getnum (ao->a2)/8;
|
||||
ao->o = 0x78; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2);
|
||||
} else return 0;
|
||||
} else {
|
||||
getrange (ao->a1);
|
||||
getrange (ao->a2);
|
||||
if (!strcmp (ao->a1, "sp")) {
|
||||
// ldr r0, [sp, n] = a[r0-7][nn]
|
||||
if (getreg (ao->a2) == -1) {
|
||||
@ -285,39 +312,35 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2)<<14;
|
||||
}
|
||||
// [0379] ldrb r3, [r0, #4]
|
||||
// [0188] ldrh r1, [r0, #0]
|
||||
}
|
||||
} else
|
||||
if (!memcmp (ao->op, "str", 3)) {
|
||||
getrange (ao->a1);
|
||||
getrange (ao->a2);
|
||||
if (ao->op[3]=='h') {
|
||||
int a0 = getreg (ao->a0);
|
||||
int a1 = getreg (ao->a1);
|
||||
int a2 = getreg (ao->a2);
|
||||
ao->o = 0x80; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2); // XXX: handle limit
|
||||
if (a2 ==-1) {
|
||||
a2 = getnum (ao->a2);
|
||||
ao->o = 0x80; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&(a2>>1));
|
||||
} else return 0;
|
||||
} else
|
||||
if (ao->op[3]=='b') {
|
||||
int a0 = getreg (ao->a0);
|
||||
int a1 = getreg (ao->a1);
|
||||
int a2 = getreg (ao->a2);
|
||||
ao->o = 0x70; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2); // XXX: handle limit
|
||||
if (a2 ==-1) {
|
||||
a2 = getnum (ao->a2);
|
||||
ao->o = 0x70; // | (8+(0xf & a0));
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (7&a2);
|
||||
} else return 0;
|
||||
} else {
|
||||
// TODO
|
||||
// str r0, [sp, n] = a[r(8-f)-8][nn]
|
||||
// " strh = 9
|
||||
// " strb = 8
|
||||
// str r0, [rN, n] = 6[n*16][7bits:basereg + 7bits:destreg]
|
||||
// str r0, [rN, rN] = 50[7bits:basereg + 7bits:destreg]
|
||||
// 0: 6191 str r1, [r2, #24]
|
||||
// 2: 50d1 str r1, [r2, r3]
|
||||
getrange (ao->a1);
|
||||
getrange (ao->a2);
|
||||
if (!strcmp (ao->a1, "sp")) {
|
||||
// ldr r0, [sp, n] = a[r0-7][nn]
|
||||
if (getreg (ao->a2) == -1) {
|
||||
@ -333,22 +356,17 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
|
||||
if (!strcmp (ao->a1, "pc")) {
|
||||
return 0;
|
||||
} else {
|
||||
// str
|
||||
int a0 = getreg (ao->a0);
|
||||
int a1 = getreg (ao->a1);
|
||||
int a2 = getreg (ao->a2);
|
||||
if (a2 == -1) {
|
||||
a2 = getnum (ao->a2)>>1;
|
||||
ao->o = 0x60; // | (8+(0xf & a0));
|
||||
a2 = getnum (ao->a2);
|
||||
ao->o = 0x60;
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
if (a2<0||a2>12) {
|
||||
fprintf (stderr, "Invalid range in str\n");
|
||||
return 0;
|
||||
}
|
||||
ao->o |= (3&(a2/4))<<14; // XXX: must limit delta in 12
|
||||
ao->o |= (3&(a2/4))<<14;
|
||||
} else {
|
||||
ao->o = 0x50; // | (8+(0xf & a0));
|
||||
ao->o = 0x50;
|
||||
ao->o |= (7&a0)<<8;
|
||||
ao->o |= (7&a1)<<11;
|
||||
ao->o |= (3&a2)<<14;
|
||||
@ -389,13 +407,13 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
|
||||
}
|
||||
} else
|
||||
if (!strcmp (ao->op, "sub")) {
|
||||
// TODO
|
||||
int reg = getreg (ao->a1);
|
||||
if (reg!=-1) {
|
||||
int n = getnum (ao->a2); // TODO: add limit
|
||||
ao->o = 0x1e;
|
||||
ao->o |= (getreg (ao->a0))<<8;
|
||||
ao->o |= reg<<11;
|
||||
// TODO: ao->o |= getnum(ao->a2)<<11;
|
||||
ao->o |= n/4 | ((n%4)<<14);
|
||||
} else {
|
||||
ao->o = 0x30;
|
||||
ao->o |= 8+(getreg (ao->a0));
|
||||
@ -532,6 +550,16 @@ void display(const char *str) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
thisplay ("ldmia r1!, {r3, r4, r5}");
|
||||
thisplay ("stmia r1!, {r3, r4, r5}");
|
||||
thisplay ("bkpt 12");
|
||||
return 0;
|
||||
thisplay("sub r1, r2, 0");
|
||||
thisplay("sub r1, r2, 4");
|
||||
thisplay("sub r1, r2, 5");
|
||||
thisplay("sub r1, r2, 7");
|
||||
thisplay("sub r3, 44");
|
||||
return 0;
|
||||
#if 0
|
||||
thisplay("mov r0, 11");
|
||||
thisplay("mov r0, r2");
|
||||
@ -567,7 +595,10 @@ int main() {
|
||||
4: 8191 strh r1, [r2, #12]
|
||||
6: 7311 strb r1, [r2, #12]
|
||||
#endif
|
||||
thisplay("ldrh r1, [r2, 20]"); // aligned to 4
|
||||
thisplay("ldrh r1, [r2, 8]"); // aligned to 4
|
||||
thisplay("ldrh r1, [r3, 8]"); // aligned to 4
|
||||
thisplay("ldrh r1, [r4, 16]"); // aligned to 4
|
||||
thisplay("ldrh r1, [r2, 32]"); // aligned to 4
|
||||
thisplay("ldrb r1, [r2, 20]"); // aligned to 4
|
||||
thisplay("strh r1, [r2, 20]"); // aligned to 4
|
||||
thisplay("strb r1, [r2, 20]"); // aligned to 4
|
||||
|
@ -28,6 +28,9 @@
|
||||
#define $0011 3
|
||||
#define $0010 2
|
||||
#define _(a,b,c,d) ((a<<12)|(b<<8)|(c<<4)|(d))
|
||||
#ifndef API
|
||||
#define API
|
||||
#endif
|
||||
|
||||
#define regname(x) (x>=0&&x<16)?regNames[x]:"r?"
|
||||
static const char* regNames[] = {
|
||||
@ -78,14 +81,14 @@ static const char* compute_reg_list (unsigned list) {
|
||||
return tmpbuf;
|
||||
}
|
||||
|
||||
int armthumb_length(unsigned int ins) {
|
||||
API int armthumb_length(unsigned int ins) {
|
||||
if ((ins & _($1110,$1000,0,0)) == _($1110,0,0,0))
|
||||
if (ins & _(1,$1000,0,0))
|
||||
return 4;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int armthumb_disassemble(char *buf, unsigned long pc, unsigned int ins) {
|
||||
API int armthumb_disassemble(char *buf, unsigned long pc, unsigned int ins) {
|
||||
unsigned int delta, imm, jump, op_code, instr2 = ins >> 16;
|
||||
const char* op;
|
||||
pc += 4;
|
||||
|
Loading…
x
Reference in New Issue
Block a user