Rewrite mips analysis module and fix rasm2 -D

Full rewrite of the MIPS code analysis module. wip
Fix infinite loop in rasm2 -D
Fix clang-analyzer.sh
Fix 'ao #' command
Use ', ' instead of ',' in mips disassembler
This commit is contained in:
pancake 2012-08-30 18:06:18 +02:00
parent 0a202fc91a
commit d843506ae1
6 changed files with 367 additions and 27 deletions

4
TODO
View File

@ -5,10 +5,8 @@
------8<-------------------8<--------------------8<-----------------8<----------
====[[ 0.9.2 ]]====
* Integrate dwarf parser with disassembler and debugger
====[[ 0.9.4 ]]====
* Integrate dwarf parser with disassembler and debugger
* Analysis: assume there's a function at the end of each function
* Event system . allow to send and read queues of messages.. thats pubsub!
* Step back .. log all state changes on every debugger stop

View File

@ -78,6 +78,7 @@ static int rasm_disasm(char *buf, ut64 offset, ut64 len, int ascii, int bin, int
while (r_asm_disassemble (a, &op, data+ret, len-ret) != -1) {
printf ("0x%08"PFMT64x" %d %12s %s\n",
a->pc, op.inst_len, op.buf_hex, op.buf_asm);
if (ret<1) break;
ret += op.inst_len;
r_asm_set_pc (a, offset+ret);
}
@ -271,7 +272,7 @@ int main(int argc, char *argv[]) {
else ret = rasm_asm (buf, offset, len, bin);
idx += ret;
offset += ret;
if (!ret) {
if (ret<1) {
eprintf ("invalid\n");
return 0;
}
@ -282,7 +283,7 @@ int main(int argc, char *argv[]) {
}
if (dis) ret = rasm_disasm (argv[optind], offset, len, ascii, bin, dis-1);
else ret = rasm_asm (argv[optind], offset, len, bin);
if (!ret) eprintf ("invalid\n");
//if (!ret) eprintf ("invalid\n");
return ret;
}
return 0;

View File

@ -6,11 +6,10 @@
#include <r_asm.h>
#include <r_anal.h>
static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *bytes, int len) {
static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b, int len) {
unsigned int opcode;
char buf[10];
int reg;
int oplen = (anal->bits==16)?2:4;
int reg, optype, oplen = (anal->bits==16)?2:4;
if (op == NULL)
return oplen;
@ -19,16 +18,306 @@ static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *bytes, int le
op->type = R_ANAL_OP_TYPE_UNK;
op->length = oplen;
r_mem_copyendian ((ut8*)&opcode, bytes, 4, anal->big_endian);
//r_mem_copyendian ((ut8*)&opcode, b, 4, !anal->big_endian);
memcpy (&opcode, b, 4);
//eprintf ("%02x %02x %02x %02x\n", b[0], b[1], b[2], b[3]);
if (opcode == 0) {
op->type = R_ANAL_OP_TYPE_NOP;
return oplen;
}
optype = (b[0]>>2);
if (optype == 0) {
#if 0
R-TYPE
======
opcode (6) rs (5) rt (5) rd (5) sa (5) function (6)
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
1111 1111 1111 1111 1111 1111 1111 1111
\_op__/\_rs__/\_rt_/ \_rd_/\_sa__/\_fun_/
| | | | | |
b[0]>>2 | (b[1]&31) | | b[3]&63
| (b[2]>>3) |
(b[0]&3)<<3)+(b[1]>>5) (b[2]&7)+(b[3]>>6)
#endif
int rs = ((b[0]&3)<<3) + (b[1]>>5);
int rt = b[1]&31;
int rd = b[2]>>3;
int sa = (b[2]&7)+(b[3]>>6);
int fun = b[3]&63;
switch (fun) {
case 0: // sll
break;
case 2: // srl
break;
case 3: // sra
break;
case 4: // sllv
break;
case 6: // srlv
break;
case 7: // srav
break;
case 9: // jalr
//eprintf ("%llx jalr\n", addr);
op->type = R_ANAL_OP_TYPE_UCALL;
break;
case 8: // jr
//eprintf ("%llx jr\n", addr);
// TODO: check return value or gtfo
op->type = R_ANAL_OP_TYPE_RET;
break;
case 12: // syscall
op->type = R_ANAL_OP_TYPE_SWI;
break;
case 13: // break
case 16: // mfhi
case 18: // mflo
case 17: // mthi
case 19: // mtlo
case 24: // mult
case 25: // multu
case 26: // div
case 27: // divu
case 32: // add
case 33: // addu
case 34: // sub
case 35: // subu
case 36: // and
case 37: // or
case 38: // xor
case 39: // nor
case 42: // slt
case 43: // sltu
break;
default:
// eprintf ("%llx %d\n", addr, optype);
break;
}
optype = 'R';
} else
if ((optype & 0x3e) == 2) {
#if 0
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
1111 1111 1111 1111 1111 1111 1111 1111
\_op__/\______address____________________/
| |
(b[0]>>2) ((b[0]&3)<<24)+(b[1]<<16)+(b[2]<<8)+b[3]
#endif
int address = ((b[0]&3)<<24)+(b[1]<<16)+(b[2]<<8)+b[3];
optype = 'J';
switch (optype) {
case 2: // j
case 3: // jal
break;
}
} else
if ((optype & 0x10) == 0x1c) {
#if 0
C-TYPE
======
opcode (6) format (5) ft (5) fs (5) fd (5) function (6)
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
1111 1111 1111 1111 1111 1111 1111 1111
\_op__/\_fmt_/\_ft_/ \_fs_/\_fd__/\_fun_/
| | | | | |
b[0]>>2 | (b[1]&31) | | b[3]&63
| (b[2]>>3) |
(b[0]&3)<<3)+(b[1]>>5) (b[2]&7)+(b[3]>>6)
#endif
int fmt = ((b[0]&3)<<3) + (b[1]>>5);
int ft = (b[1]&31);
int fs = (b[2]>>3);
int fd = (b[2]&7)+(b[3]>>6);
int fun = (b[3]&63);
optype = 'C';
switch (fun) {
case 0: // mtc1
break;
case 1: // sub.s
break;
case 2: // mul.s
break;
case 3: // div.s
break;
// ....
}
} else {
#if 0
I-TYPE
======
all opcodes but 000000 000001x and 0100xx
opcode (6) rs (5) rt (5) immediate (16)
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
1111 1111 1111 1111 1111 1111 1111 1111
\_op__/\_rs__/\_rt_/ \_______imm________/
| | | |
b[0]>>2 | (b[1]&31) |
| |
((b[0]&3)<<3)+(b[1]>>5) (b[2]<<8)+b[3]
#endif
int rs = ((b[0]&3)<<3)+(b[1]>>5);
int rt = b[1]&31;
int imm = (b[2]<<8)+b[3];
switch (optype) {
case 1: if (rt) { /* bgez */ } else { /* bltz */ }
case 4: // beq
case 5: // bne
case 6: // blez
case 7: // bgtz
// XXX: use imm here
op->type = R_ANAL_OP_TYPE_JMP;
//reg = (((opcode&0x00ff0000)>>16) + ((opcode&0xff000000)>>24));
op->jump = addr+(imm<<2)+4; //(reg<<2) + 4;
op->fail = addr+8;
break;
case 8: // addi
case 9: // addiu
case 10: // stli
case 11: // stliu
case 12: // andi
case 13: // ori
case 14: // xori
case 15: // lui
case 32: // lb
case 33: // lh
case 35: // lw
case 36: // lbu
case 37: // lhu
case 40: // sb
case 41: // sh
case 43: // sw
case 49: // lwc1
case 57: // swc1
break;
}
optype = 'I';
}
#if 0
switch (optype) {
case 'R': // register only
op->type = R_ANAL_OP_TYPE_ADD;
break;
case 'I': // immediate
op->type = R_ANAL_OP_TYPE_JMP;
break;
case 'J': // memory address jumps
op->type = R_ANAL_OP_TYPE_CALL;
break;
case 'C': // coprocessor
op->type = R_ANAL_OP_TYPE_RET;
break;
}
#endif
return oplen;
#if 0
R - all instructions that only take registers as arguments (jalr, jr)
opcode 000000
opcode (6) rs (5) rt (5) rd (5) sa (5) function (6)
add rd, rs, rt 100000
addu rd, rs, rt 100001
and rd, rs, rt 100100
break 001101
div rs, rt 011010
divu rs, rt 011011
jalr rd, rs 001001
jr rs 001000
mfhi rd 010000
mflo rd 010010
mthi rs 010001
mtlo rs 010011
mult rs, rt 011000
multu rs, rt 011001
nor rd, rs, rt 100111
or rd, rs, rt 100101
sll rd, rt, sa 000000
sllv rd, rt, rs 000100
slt rd, rs, rt 101010
sltu rd, rs, rt 101011
sra rd, rt, sa 000011
srav rd, rt, rs 000111
srl rd, rt, sa 000010
srlv rd, rt, rs 000110
sub rd, rs, rt 100010
subu rd, rs, rt 100011
syscall 001100
xor rd, rs, rt 100110
I - instructions with immediate operand, load/store/..
all opcodes but 000000 000001x and 0100xx
opcode (6) rs (5) rt (5) immediate (16)
addi rt, rs, immediate 001000
addiu rt, rs, immediate 001001
andi rt, rs, immediate 001100
beq rs, rt, label 000100
bgez rs, label 000001 rt = 00001
bgtz rs, label 000111 rt = 00000
blez rs, label 000110 rt = 00000
bltz rs, label 000001 rt = 00000
bne rs, rt, label 000101
lb rt, immediate(rs) 100000
lbu rt, immediate(rs) 100100
lh rt, immediate(rs) 100001
lhu rt, immediate(rs) 100101
lui rt, immediate 001111
lw rt, immediate(rs) 100011
lwc1 rt, immediate(rs) 110001
ori rt, rs, immediate 001101
sb rt, immediate(rs) 101000
slti rt, rs, immediate 001010
sltiu rt, rs, immediate 001011
sh rt, immediate(rs) 101001
sw rt, immediate(rs) 101011
swc1 rt, immediate(rs) 111001
xori rt, rs, immediate 001110
J - require memory address like j, jal
00001x
opcode (6) target (26)
j label 000010 coded address of label
jal label 000011 coded address of label
C - coprocessor insutrctions that use cp0, cp1, ..
0100xx
opcode (6) format (5) ft (5) fs (5) fd (5) function (6)
add.s fd, fs, ft 000000 10000
cvt.s.w fd, fs, ft 100000 10100
cvt.w.s fd, fs, ft 100100 10000
div.s fd, fs, ft 000011 10000
mfc1 ft, fs 000000 00000
mov.s fd, fs 000110 10000
mtc1 ft, fs 000000 00100
mul.s fd, fs, ft 000010 10000
sub.s fd, fs, ft 000001 10000
#endif
//eprintf ("--> %x %02x %02x\n", opcode, opcode &0xff , opcode &0x3f);
switch (opcode & 0x3f) {
// J-Type
case 2: // j
break;
// branch to register
//XXX TODO
//eprintf("UJUMP\n");
//op->type = R_ANAL_OP_TYPE_UJMP;
op->type = R_ANAL_OP_TYPE_UJMP;
break;
// R-Type
@ -46,7 +335,19 @@ static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *bytes, int le
op->fail = addr+8;
// calculate jump
break;
case 0x24: // jalx
case 0x34: // jalx
op->type = R_ANAL_OP_TYPE_UJMP;
break;
case 3: // jalr
op->type = R_ANAL_OP_TYPE_UCALL;
switch (opcode) {
case 0x03e00008:
case 0x0800e003: // jr ra
op->type = R_ANAL_OP_TYPE_RET;
break;
}
break;
case 9: // jalr
reg = opcode>>24;
if (reg<10) {
@ -87,8 +388,8 @@ static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *bytes, int le
op->type = R_ANAL_OP_TYPE_TRAP;
break;
default:
//switch((opcode<<24)&0xff) { //bytes[3]) { // TODO handle endian ?
switch((bytes[3])) {
//switch((opcode<<24)&0xff) { //b[3]) { // TODO handle endian ?
switch ((b[3])) {
case 0xc:
op->type = R_ANAL_OP_TYPE_SWI;
break;

View File

@ -531,7 +531,7 @@ set_default_mips_dis_options (struct disassemble_info *info)
/* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
and numeric FPR, CP0 register, and HWR names. */
mips_isa = ISA_MIPS3;
mips_processor = CPU_LOONGSON_2F; // R3000
mips_processor = CPU_LOONGSON_2F; // R3000
mips_gpr_names = mips_gpr_names_oldabi;
mips_fpr_names = mips_fpr_names_numeric;
mips_cp0_names = mips_cp0_names_numeric;
@ -731,6 +731,8 @@ print_insn_args (const char *d,
switch (*d)
{
case ',':
(*info->fprintf_func) (info->stream, "%c ", *d);
break;
case '(':
case ')':
case '[':
@ -1697,13 +1699,13 @@ print_mips16_insn_arg (char type,
if (smask == 3)
{
(*info->fprintf_func) (info->stream, "%s??",
need_comma ? "," : "");
need_comma ? ", " : "");
need_comma = 1;
}
else if (smask > 0)
{
(*info->fprintf_func) (info->stream, "%s%s",
need_comma ? "," : "",
need_comma ? ", " : "",
mips_gpr_names[16]);
if (smask > 1)
(*info->fprintf_func) (info->stream, "-%s",
@ -1714,7 +1716,7 @@ print_mips16_insn_arg (char type,
if (l & 1)
{
(*info->fprintf_func) (info->stream, "%s%s",
need_comma ? "," : "",
need_comma ? ", " : "",
mips_gpr_names[31]);
need_comma = 1;
}
@ -1722,7 +1724,7 @@ print_mips16_insn_arg (char type,
if (amask == 5 || amask == 6)
{
(*info->fprintf_func) (info->stream, "%s$f0",
need_comma ? "," : "");
need_comma ? ", " : "");
if (amask == 6)
(*info->fprintf_func) (info->stream, "-$f1");
}
@ -1773,11 +1775,11 @@ print_mips16_insn_arg (char type,
framesz = 128;
(*info->fprintf_func) (info->stream, "%s%d",
need_comma ? "," : "",
need_comma ? ", " : "",
framesz);
if (l & 0x40) /* $ra */
(*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
(*info->fprintf_func) (info->stream, ", %s", mips_gpr_names[31]);
nsreg = (l >> 24) & 0x7;
smask = 0;
@ -1793,7 +1795,7 @@ print_mips16_insn_arg (char type,
{
if (smask & (1 << i))
{
(*info->fprintf_func) (info->stream, ",%s",
(*info->fprintf_func) (info->stream, ", %s",
mips_gpr_names[i == 8 ? 30 : (16 + i)]);
/* Skip over string of set bits. */
for (j = i; smask & (2 << j); j++)
@ -1807,9 +1809,9 @@ print_mips16_insn_arg (char type,
/* Statics $ax - $a3. */
if (statics == 1)
(*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
(*info->fprintf_func) (info->stream, ", %s", mips_gpr_names[7]);
else if (statics > 0)
(*info->fprintf_func) (info->stream, ",%s-%s",
(*info->fprintf_func) (info->stream, ", %s-%s",
mips_gpr_names[7 - statics + 1],
mips_gpr_names[7]);
}

View File

@ -131,6 +131,44 @@ static void cmd_syscall_do(RCore *core, int num) {
r_cons_printf (")\n");
}
static const char *optypestr(int type) {
switch (type) {
case R_ANAL_OP_TYPE_NULL : return "null";
case R_ANAL_OP_TYPE_JMP : return "jmp";
case R_ANAL_OP_TYPE_UJMP : return "ujmp";
case R_ANAL_OP_TYPE_CJMP : return "cjmp";
case R_ANAL_OP_TYPE_CALL : return "call";
case R_ANAL_OP_TYPE_UCALL : return "ucall";
case R_ANAL_OP_TYPE_REP : return "rep";
case R_ANAL_OP_TYPE_RET : return "ret";
case R_ANAL_OP_TYPE_ILL : return "ill";
case R_ANAL_OP_TYPE_UNK : return "unk";
case R_ANAL_OP_TYPE_NOP : return "nop";
case R_ANAL_OP_TYPE_MOV : return "mov";
case R_ANAL_OP_TYPE_TRAP : return "trap";
case R_ANAL_OP_TYPE_SWI : return "swi";
case R_ANAL_OP_TYPE_UPUSH : return "upush";
case R_ANAL_OP_TYPE_PUSH : return "push";
case R_ANAL_OP_TYPE_POP : return "pop";
case R_ANAL_OP_TYPE_CMP : return "cmp";
case R_ANAL_OP_TYPE_ADD : return "add";
case R_ANAL_OP_TYPE_SUB : return "sub";
case R_ANAL_OP_TYPE_MUL : return "mul";
case R_ANAL_OP_TYPE_DIV : return "div";
case R_ANAL_OP_TYPE_SHR : return "shr";
case R_ANAL_OP_TYPE_SHL : return "shl";
case R_ANAL_OP_TYPE_OR : return "or";
case R_ANAL_OP_TYPE_AND : return "andr";
case R_ANAL_OP_TYPE_XOR : return "xor";
case R_ANAL_OP_TYPE_NOT : return "not";
case R_ANAL_OP_TYPE_STORE : return "store";
case R_ANAL_OP_TYPE_LOAD : return "load";
case R_ANAL_OP_TYPE_LEA : return "lea";
case R_ANAL_OP_TYPE_LEAVE : return "leave";
}
return "err";
}
static void r_core_anal_bytes (RCore *core, const ut8 *buf, int len) {
int ret, idx;
RAnalOp op;
@ -145,7 +183,7 @@ static void r_core_anal_bytes (RCore *core, const ut8 *buf, int len) {
}
r_cons_printf ("addr: 0x%08"PFMT64x"\n", core->offset+idx);
r_cons_printf ("size: %d\n", op.length);
r_cons_printf ("type: %d\n", op.type); // TODO: string
r_cons_printf ("type: %d (%s)\n", op.type, optypestr (op.type)); // TODO: string
r_cons_printf ("eob: %d\n", op.eob);
r_cons_printf ("jump: 0x%08"PFMT64x"\n", op.jump);
r_cons_printf ("fail: 0x%08"PFMT64x"\n", op.fail);

View File

@ -2,8 +2,8 @@
MAKE=make
gmake --help >/dev/null 2>&1
[ $? = 0 ] && MAKE=gmake
scan-build echo >/dev/null 2>&1
[ $? = 0 ] && MAKE=gmake
scan-build echo >/dev/null
[ $? = 0 ] || exit 1
# find root
cd `dirname $PWD/$0` ; cd ..