Exemple #1
0
static void parse_localvar (RParse *p, char *newstr, size_t newstr_len, const char *var, const char *reg, char sign, char *ireg, bool att) {
	RStrBuf *sb = r_strbuf_new ("");
	if (att) {
		if (p->localvar_only) {
			if (ireg) {
				r_strbuf_setf (sb, "(%%%s)", ireg);
			}
			snprintf (newstr, newstr_len - 1, "%s%s", var, r_strbuf_get (sb));
		} else {
			if (ireg) {
				r_strbuf_setf (sb, ", %%%s", ireg);
			}
			snprintf (newstr, newstr_len - 1, "%s(%%%s%s)", var, reg, r_strbuf_get (sb));
		}
	} else {
		if (ireg) {
			r_strbuf_setf (sb, " + %s", ireg);
		}
		if (p->localvar_only) {
			snprintf (newstr, newstr_len - 1, "[%s%s]", var, r_strbuf_get (sb));
		} else {
			snprintf (newstr, newstr_len - 1, "[%s%s %c %s]", reg, r_strbuf_get (sb), sign, var);
		}
	}
	r_strbuf_free (sb);
}
Exemple #2
0
static void _6502_anal_esil_push(RAnalOp *op, ut8 data0) {
	// case 0x08: // php
	// case 0x48: // pha
	char *reg = (data0==0x08) ? "flags" : "a";
	// stack is on page one: sp + 0x100
	r_strbuf_setf (&op->esil, "%s,sp,0x100,+,=[1],sp,--=", reg);
}
Exemple #3
0
static void _6502_anal_esil_ccall(RAnalOp *op, ut8 data0)
{
	char *flag;
	switch(data0) {
	case 0x10: // bpl $ffff
		flag = "N,!";
		break;
	case 0x30: // bmi $ffff
		flag = "N";
		break;
	case 0x50: // bvc $ffff
		flag = "V,!";
		break;
	case 0x70: // bvs $ffff
		flag = "V";
		break;
	case 0x90: // bcc $ffff
		flag = "C,!";
		break;
	case 0xb0: // bcs $ffff
		flag = "C";
		break;
	case 0xd0: // bne $ffff
		flag = "Z,!";
		break;
	case 0xf0: // beq $ffff
		flag = "Z";
		break;
	default:
		// FIXME: should not happen
		flag = "unk";
		break;
	}
	r_strbuf_setf (&op->esil, "%s,?{,0x%04x,pc,=,}", flag, (op->jump & 0xffff));
}
Exemple #4
0
static void _6502_anal_esil_pop(RAnalOp *op, ut8 data0) {
	// case 0x28: // plp
	// case 0x68: // pla
	char *reg = (data0==0x28) ? "flags" : "a";
	// stack is on page one: sp + 0x100
	r_strbuf_setf (&op->esil, "sp,++=,sp,0x100,+,[1],%s,=", reg);

	if (data0==0x68) _6502_anal_update_flags (op, _6502_FLAGS_NZ);
}
Exemple #5
0
static int bf_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	ut64 dst = 0LL;
	if (op == NULL)
		return 1;
	/* Ayeeee! What's inside op? Do we have an initialized RAnalOp? Are we going to have a leak here? :-( */
	memset (op, 0, sizeof (RAnalOp)); /* We need to refactorize this. Something like r_anal_op_init would be more appropiate */
	r_strbuf_init (&op->esil);
	op->size = 1;
	switch (buf[0]) {
	case '[': op->type = R_ANAL_OP_TYPE_CJMP;
		  op->fail = addr+1;
		  {
			 const ut8 *p = buf + 1;
			 int lev = 0, i = 1;
			 while (*p && i<len) {
				 if (*p == '[')
					 lev++;
				 if (*p == ']') {
					 lev--;
					 if (lev==-1) {
						 dst = addr + (size_t)(p-buf);
						 op->jump = dst;
						 r_strbuf_setf (&op->esil,
							"if (!*ptr) pc=0x%"PFMT64x, dst);
						 break;
					 }
				 }
				 p++;
				i++;
			 }
		  }
	// ?1[ptr],pc=${NEW_PC
	break;
	case ']': op->type = R_ANAL_OP_TYPE_UJMP; break;
	case '>': op->type = R_ANAL_OP_TYPE_ADD;
		r_strbuf_set (&op->esil, "ptr++");
		break;
	case '<': op->type = R_ANAL_OP_TYPE_SUB;
		r_strbuf_set (&op->esil, "ptr--");
		break;
	case '+': op->type = R_ANAL_OP_TYPE_ADD;
		r_strbuf_set (&op->esil, "*ptr++");
		break;
	case '-': op->type = R_ANAL_OP_TYPE_SUB;
		r_strbuf_set (&op->esil, "*ptr--");
		break;
	case '.': op->type = R_ANAL_OP_TYPE_STORE;
		r_strbuf_set (&op->esil, "=*ptr");
		break;
	case ',': op->type = R_ANAL_OP_TYPE_LOAD; break;
	case 0x00:
	case 0xff:
		op->type = R_ANAL_OP_TYPE_TRAP; break;
	default: op->type = R_ANAL_OP_TYPE_NOP; break;
	}
	return op->size;
}
Exemple #6
0
static int bcl_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	int i;
	char cache[256] = {0};
	ut64 dst = 0LL;
	if (op == NULL)
		return 1;
	int base = *buf & 3;
	memset (op, 0, sizeof (RAnalOp));
	r_strbuf_init (&op->esil);
	op->size = 1;
	if (*buf == 0) {
		op->type = R_ANAL_OP_TYPE_NOP;
		return 0;
	}
	switch (base) {
	case 0:
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->jump = addr + findpair (addr, buf, len, 3);
		op->fail = addr + 1;
		r_strbuf_setf (&op->esil, "A,++=");
		break;
	case 1:
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->jump = addr + findpair(addr, buf, len, 2);
		op->fail = addr + 1;
		r_strbuf_setf (&op->esil, "C,++=");
		break;
	case 2:
		op->type = R_ANAL_OP_TYPE_CMP;
		r_strbuf_setf (&op->esil, "G,++=");
		break;
	case 3:
		op->type = R_ANAL_OP_TYPE_MOV;
		r_strbuf_setf (&op->esil, "T,++=");
		break;
	}
	return op->size;
}
Exemple #7
0
static inline void mk_reg_str(const char *regname, int delta, bool sign, bool att, char *ireg, char *dest, int len) {
	RStrBuf *sb = r_strbuf_new ("");
	if (att) {
		if (ireg) {
			r_strbuf_setf (sb, ", %%%s", ireg);
		}
		if (delta < 10) {
			snprintf (dest, len - 1, "%s%d(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb));
		} else {
			snprintf (dest, len - 1, "%s0x%x(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb));
		}
	} else {
		if (ireg) {
			r_strbuf_setf (sb, " + %s", ireg);
		}
		if (delta < 10) {
			snprintf (dest, len - 1, "[%s%s %c %d]", regname, r_strbuf_get (sb), sign ? '+':'-', delta);
		} else {
			snprintf (dest, len - 1, "[%s%s %c 0x%x]", regname, r_strbuf_get (sb), sign ? '+':'-', delta);
		}
	}
	r_strbuf_free (sb);
}
Exemple #8
0
// inc register
static void _6502_anal_esil_inc_reg(RAnalOp *op, ut8 data0, char* sign)
{
	char* reg = NULL;

	switch(data0) {
	case 0xe8: // inx
	case 0xca: // dex
		reg = "x";
		break;
	case 0xc8: // iny
	case 0x88: // dey
		reg = "y";
		break;
	}
	r_strbuf_setf (&op->esil, "%s,%s%s=", reg, sign, sign);
	_6502_anal_update_flags (op, _6502_FLAGS_NZ);
}
Exemple #9
0
static void _6502_anal_esil_mov(RAnalOp *op, ut8 data0) {
	const char* src="unk";
	const char* dst="unk";
	switch(data0) {
	case 0xaa: // tax
		src="a";
		dst="x";
		break;
	case 0x8a: // txa
		src="x";
		dst="a";
		break;
	case 0xa8: // tay
		src="a";
		dst="y";
		break;
	case 0x98: // tya
		src="y";
		dst="a";
		break;
	case 0x9a: // txs
		src="x";
		dst="sp";
		break;
	case 0xba: // tsx
		src="sp";
		dst="x";
		break;
	default:
		// FIXME: should not happen
		break;
	}
	r_strbuf_setf (&op->esil, "%s,%s,=",src,dst);

	// don't update NZ on txs
	if (data0 != 0x9a) _6502_anal_update_flags (op, _6502_FLAGS_NZ);
}
Exemple #10
0
static void _6502_anal_esil_flags(RAnalOp *op, ut8 data0) {
	int enabled=0;
	char flag ='u';
	switch(data0) {
	case 0x78: // sei
		enabled = 1;
		flag = 'I';
		break;
	case 0x58: // cli
		enabled = 0;
		flag = 'I';
		break;
	case 0x38: // sec
		enabled = 1;
		flag = 'C';
		break;
	case 0x18: // clc
		enabled = 0;
		flag = 'C';
		break;
	case 0xf8: // sed
		enabled = 1;
		flag = 'D';
		break;
	case 0xd8: // cld
		enabled = 0;
		flag = 'D';
		break;
	case 0xb8: // clv
		enabled = 0;
		flag = 'V';
		break;
		break;
	}
	r_strbuf_setf (&op->esil, "%d,%c,=", enabled, flag);
}
Exemple #11
0
static int bf_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	ut64 dst = 0LL;
	if (op == NULL)
		return 1;
	/* Ayeeee! What's inside op? Do we have an initialized RAnalOp? Are we going to have a leak here? :-( */
	memset (op, 0, sizeof (RAnalOp)); /* We need to refactorize this. Something like r_anal_op_init would be more appropiate */
	r_strbuf_init (&op->esil);
	op->size = 1;
	switch (buf[0]) {
	case '[': op->type = R_ANAL_OP_TYPE_CJMP;
		  op->fail = addr+1;
		  {
			 const ut8 *p = buf + 1;
			 int lev = 0, i = 1;
			 while (*p && i<len) {
				 if (*p == '[')
					 lev++;
				 if (*p == ']') {
					 lev--;
					 if (lev==-1) {
						 dst = addr + (size_t)(p-buf);
						 dst ++;
						 op->jump = dst;
						 r_strbuf_setf (&op->esil,
							 "pc,brk,=[1],brk,++=,"
							 "ptr,[1],!,?{,0x%"PFMT64x",pc,=,}", dst);
						 break;
					 }
				 }
				 p++;
				i++;
			 }
		  }
	// ?1[ptr],pc=${NEW_PC
	break;
	case ']': op->type = R_ANAL_OP_TYPE_UJMP;
		// XXX This is wrong esil
		r_strbuf_set (&op->esil, "brk,--=,brk,[1],pc,=");
		break;
	case '>': op->type = R_ANAL_OP_TYPE_ADD;
		r_strbuf_set (&op->esil, "ptr,++=");
		break;
	case '<': op->type = R_ANAL_OP_TYPE_SUB;
		r_strbuf_set (&op->esil, "ptr,--=");
		break;
	case '+':
		op->size = countChar (buf, len, '+');
		op->type = R_ANAL_OP_TYPE_ADD;
		r_strbuf_setf (&op->esil, "ptr,[1],%d,+,ptr,=[1]", op->size);
		break;
	case '-':
		op->type = R_ANAL_OP_TYPE_SUB;
		op->size = countChar (buf, len, '-');
		r_strbuf_setf (&op->esil, "ptr,[1],%d,-,ptr,=[1]", op->size);
		break;
	case '.':
		// print element in stack to screen
		op->type = R_ANAL_OP_TYPE_STORE;
		r_strbuf_set (&op->esil, "ptr,[1],scr,=[1],scr,++=");
		break;
	case ',':
		op->type = R_ANAL_OP_TYPE_LOAD;
		r_strbuf_set (&op->esil, "kbd,[1],ptr,=[1],kbd,++=");
		break;
	case 0x00:
	case 0xff:
		op->type = R_ANAL_OP_TYPE_TRAP;
		break;
	default:
		op->type = R_ANAL_OP_TYPE_NOP;
		r_strbuf_set (&op->esil, ",");
		break;
	}
	return op->size;
}
Exemple #12
0
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
	char str[32][32];
	r_strbuf_init (&op->esil);
	r_strbuf_set (&op->esil, "");
	if (insn)
	switch (insn->id) {
	case MIPS_INS_NOP:
		r_strbuf_setf (&op->esil, ",");
		break;
	case MIPS_INS_SW:
		r_strbuf_appendf (&op->esil, "%s,%s,=[4]",
			ARG(0), ARG(1));
		break;
	case MIPS_INS_SWC1:
	case MIPS_INS_SWC2:
		r_strbuf_setf (&op->esil, "%s,$", ARG(1));
		break;
	case MIPS_INS_SB:
		r_strbuf_appendf (&op->esil, "%s,%s,=[1]",
			ARG(0), ARG(1));
		break;
	case MIPS_INS_CMP:
	case MIPS_INS_CMPU:
	case MIPS_INS_CMPGU:
	case MIPS_INS_CMPGDU:
	case MIPS_INS_CMPI:
		r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0));
		break;
	case MIPS_INS_SHRAV:
	case MIPS_INS_SHRAV_R:
	case MIPS_INS_SHRA:
	case MIPS_INS_SHRA_R:
	case MIPS_INS_SRA:
		r_strbuf_appendf (&op->esil, "%s,%s,>>,31,%s,>>,?{,32,%s,-,%s,1,<<,1,-,<<,}{,0,},|,%s,=,",
				ARG(2), ARG(1), ARG(1), ARG(2), ARG(2), ARG(0));
		break;
	case MIPS_INS_SHRL:
		// suffix 'S' forces conditional flag to be updated
	case MIPS_INS_SRLV:
	case MIPS_INS_SRL:
		r_strbuf_appendf (&op->esil, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0));
		break;
	case MIPS_INS_SLLV:
	case MIPS_INS_SLL:
		r_strbuf_appendf (&op->esil, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0));
		break;
	case MIPS_INS_BAL:
	case MIPS_INS_JAL:
	case MIPS_INS_JALR:
	case MIPS_INS_JALRS:
	case MIPS_INS_JALRC:
	case MIPS_INS_BLTZAL: // Branch on less than zero and link
		r_strbuf_appendf (&op->esil, "pc,8,+,ra,=,%s,pc,=", ARG(0));
		break;
	case MIPS_INS_JR:
	case MIPS_INS_JRC:
	case MIPS_INS_J:
		// jump to address with conditional
		r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0));
		break;
	case MIPS_INS_B: // ???
	case MIPS_INS_BZ:
	case MIPS_INS_BGTZ:
	case MIPS_INS_BGTZC:
	case MIPS_INS_BGTZALC:
	case MIPS_INS_BGEZ:
	case MIPS_INS_BGEZC:
	case MIPS_INS_BGEZAL: // Branch on less than zero and link
	case MIPS_INS_BGEZALC:
		r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0));
		break;
	case MIPS_INS_BNE:  // bne $s, $t, offset 
	case MIPS_INS_BNEZ:
		r_strbuf_appendf (&op->esil, "%s,%s,==,!,?{,%s,pc,=,}",
			ARG(0), ARG(1), ARG(2));
		break;
	case MIPS_INS_BEQ:
	case MIPS_INS_BEQZ:
	case MIPS_INS_BEQZC:
	case MIPS_INS_BEQZALC:
		r_strbuf_appendf (&op->esil, "%s,%s,==,?{,%s,pc,=,}",
			ARG(0), ARG(1), ARG(2));
		break;
	case MIPS_INS_BTEQZ:
	case MIPS_INS_BTNEZ:
		r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0));
		break;
	case MIPS_INS_MOV:
	case MIPS_INS_MOVE:
	case MIPS_INS_MOVF:
	case MIPS_INS_MOVT:
	case MIPS_INS_MOVZ:
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0));
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		break;
	case MIPS_INS_FSUB:
	case MIPS_INS_SUB:
		if (REG(0)[0]!='z'){
			r_strbuf_appendf(&op->esil, "%s,%s,>,?{,$$,}{,%s,%s,-,%s,=",ARG(2), ARG(1), ARG(1), ARG(2), ARG(0));
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		break;
	case MIPS_INS_SUBU:
	case MIPS_INS_NEGU:
	case MIPS_INS_DSUB:
	case MIPS_INS_DSUBU:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=",
			arg1, arg2, arg0);
		}
		break;
	/** signed -- sets overflow flag */
	case MIPS_INS_ADD:
		{
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "32,%s,%s,+,>>,0,>,?{,$$,}{,%s,%s,+,%s,=,}",
					ARG(2), ARG(1), ARG(2), ARG(1), ARG(0));
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		}
		break;
	case MIPS_INS_ADDI:
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "32,%s,0xffffffff,&,%s,+,>>,0,>,?{,$$,}{,%s,%s,+,%s,=,}",
					ARG(2), ARG(1), ARG(2), ARG(1), ARG(0));
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		break;
	case MIPS_INS_DADD:
	case MIPS_INS_DADDI:
	/** unsigned */
	case MIPS_INS_ADDU:
	case MIPS_INS_ADDIU:
	case MIPS_INS_DADDIU:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=",
					arg2, arg1, arg0);
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		}
		break;
	case MIPS_INS_LI:
		r_strbuf_appendf (&op->esil, "0x%"PFMT64x",%s,=", IMM(1), ARG(0));
		break;
	case MIPS_INS_LUI:
		r_strbuf_appendf (&op->esil, "0x%"PFMT64x"0000,%s,=", IMM(1), ARG(0));
		break;
	case MIPS_INS_LB:
	case MIPS_INS_LBU:
		//one of these is wrong
		r_strbuf_appendf (&op->esil, "%s,[1],%s,=",
			ARG(1), REG(0));
		break;
	case MIPS_INS_LW:
	case MIPS_INS_LWC1:
	case MIPS_INS_LWC2:
	case MIPS_INS_LWL:
	case MIPS_INS_LWR:
	case MIPS_INS_LWU:
	case MIPS_INS_LWX:
	case MIPS_INS_LH:
	case MIPS_INS_LHX:
	case MIPS_INS_LL:
	case MIPS_INS_LLD:
	case MIPS_INS_LD:
	case MIPS_INS_LDI:
	case MIPS_INS_LDL:
	case MIPS_INS_LDC1:
	case MIPS_INS_LDC2:
		r_strbuf_appendf (&op->esil, "%s,[4],%s,=",
			ARG(1), REG(0));
		break;
	case MIPS_INS_AND:
	case MIPS_INS_ANDI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		r_strbuf_appendf (&op->esil, "%s,%s,&,%s,=",
			arg2, arg1, arg0);
		}
		break;
	case MIPS_INS_OR:
	case MIPS_INS_ORI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "%s,%s,|,%s,=",
				arg2, arg1, arg0);
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		}
		break;
	case MIPS_INS_XOR:
	case MIPS_INS_XORI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "%s,%s,^,%s,=",
				arg2, arg1, arg0);
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		}
		break;
	case MIPS_INS_NOR:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		if (REG(0)[0]!='z'){
			r_strbuf_appendf (&op->esil, "%s,%s,|,0xffffffff,^,%s,=",
				arg2, arg1, arg0);
		} else {
			r_strbuf_appendf (&op->esil, ",");
		}
		}
		break;
	case MIPS_INS_SLTU:
		r_strbuf_appendf (&op->esil, "%s,%s,<,%s,=", ARG(1), ARG(2), ARG(0));
		break;
	case MIPS_INS_SLTIU:
		{
		r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,<,?{%s,1,=,}{,%s,0,=,}",
					ARG(1), ARG(2), ARG(0), ARG(0));
		}
		break;
	}
	return 0;
}
Exemple #13
0
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
	char str[8][32];
	int i;
	r_strbuf_init (&op->esil);
	r_strbuf_set (&op->esil, "");

	if (insn) {
		// caching operands
		for (i=0; i<insn->detail->mips.op_count && i<8; i++) {
			*str[i]=0;
			ARG (i);
		}
	}

	if (insn)
	switch (insn->id) {
	case MIPS_INS_NOP:
		r_strbuf_setf (&op->esil, ",");
		break;
	case MIPS_INS_BREAK:
		r_strbuf_setf (&op->esil, "%s,%s,TRAP", ARG (0), ARG (0));
		break;
	case MIPS_INS_SW:
	case MIPS_INS_SWL:
	case MIPS_INS_SWR:
		r_strbuf_appendf (&op->esil, "%s,%s,=[4]",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_SH:
		r_strbuf_appendf (&op->esil, "%s,%s,=[2]",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_SWC1:
	case MIPS_INS_SWC2:
		r_strbuf_setf (&op->esil, "%s,$", ARG (1));
		break;
	case MIPS_INS_SB:
		r_strbuf_appendf (&op->esil, "%s,%s,=[1]",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_CMP:
	case MIPS_INS_CMPU:
	case MIPS_INS_CMPGU:
	case MIPS_INS_CMPGDU:
	case MIPS_INS_CMPI:
		r_strbuf_appendf (&op->esil, "%s,%s,==", ARG (1), ARG (0));
		break;
	case MIPS_INS_SHRAV:
	case MIPS_INS_SHRAV_R:
	case MIPS_INS_SHRA:
	case MIPS_INS_SHRA_R:
	case MIPS_INS_SRA:
		r_strbuf_appendf (&op->esil, "%s,%s,>>,31,%s,>>,?{,32,%s,-,%s,1,<<,1,-,<<,}{,0,},|,%s,=,",
			ARG (2), ARG (1), ARG (1), ARG (2), ARG (2), ARG (0));
		break;
	case MIPS_INS_SHRL:
		// suffix 'S' forces conditional flag to be updated
	case MIPS_INS_SRLV:
	case MIPS_INS_SRL:
		r_strbuf_appendf (&op->esil, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0));
		break;
	case MIPS_INS_SLLV:
	case MIPS_INS_SLL:
		r_strbuf_appendf (&op->esil, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0));
		break;
	case MIPS_INS_BAL:
	case MIPS_INS_JAL:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_D ("%s"), ARG (0));
		break;
	case MIPS_INS_JALR:
	case MIPS_INS_JALRS:
		if (OPCOUNT () < 2) {
			r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_D ("%s"), ARG (0));
		} else {
			PROTECT_ZERO () {
				r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_DR ("%s","%s"), ARG (0), ARG (1));
			}
		}
		break;
	case MIPS_INS_JALRC: // no delay
		if (OPCOUNT () < 2) {
			r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_ND ("%s"), ARG (0));
		} else {
			PROTECT_ZERO () {
				r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_NDR ("%s","%s"), ARG (0), ARG (1));
			}
		}
		break;
	case MIPS_INS_JRADDIUSP:
		// increment stackpointer in X and jump to %ra
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%d,sp,+=,"ES_J ("ra"), ARG (0));
		break;
	case MIPS_INS_JR:
	case MIPS_INS_JRC:
	case MIPS_INS_J:
	case MIPS_INS_B: // ???
		// jump to address with conditional
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_J ("%s"), ARG (0));
		break;
	case MIPS_INS_BNE:  // bne $s, $t, offset
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,%s,==,$z,!,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1), ARG (2));
		break;
	case MIPS_INS_BEQ:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,%s,==,$z,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1), ARG (2));
		break;
	case MIPS_INS_BZ:
	case MIPS_INS_BEQZ:
	case MIPS_INS_BEQZC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BNEZ:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,!,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BEQZALC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,?{,"ES_CALL_ND ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BLEZ:
	case MIPS_INS_BLEZC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,"ES_J ("%s")",BREAK,},",
			ARG (0), ARG (1));
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BGEZ:
	case MIPS_INS_BGEZC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BGEZAL:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_D ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BGEZALC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_ND ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BGTZALC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,BREAK,},", ARG(0));
		r_strbuf_appendf (&op->esil, "0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_ND ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BLTZAL:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_D ("%s")",}", ARG(0), ARG(1));
		break;
	case MIPS_INS_BLTZ:
	case MIPS_INS_BLTZC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}",
			ARG (0), ARG (1));
		break;
	case MIPS_INS_BGTZ:
	case MIPS_INS_BGTZC:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,BREAK,},", ARG (0));
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J("%s")",}",
			ARG (0), ARG (1));		
		break;
	case MIPS_INS_BTEQZ:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,t,==,$z,?{,"ES_J ("%s")",}", ARG (0));
		break;
	case MIPS_INS_BTNEZ:
		r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,t,==,$z,!,?{,"ES_J ("%s")",}", ARG (0));
		break;
	case MIPS_INS_MOV:
	case MIPS_INS_MOVE:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "%s,%s,=", ARG (1), REG (0));
		}
		break;
	case MIPS_INS_MOVZ:
	case MIPS_INS_MOVF:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "0,%s,==,$z,?{,%s,%s,=,}",
				ARG (2), ARG (1), REG (0));
		}
		break;
	case MIPS_INS_MOVT:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "1,%s,==,$z,?{,%s,%s,=,}",
				ARG (2), ARG (1), REG (0));
		}
		break;
	case MIPS_INS_FSUB:
	case MIPS_INS_SUB:
		PROTECT_ZERO () {
			r_strbuf_appendf(&op->esil, "%s,%s,-,%s,=",
				ARG (1), ARG (2), ARG (0));
			//r_strbuf_appendf(&op->esil, "%s,%s,>,?{,1,TRAP,}{,%s,%s,-,%s,=",
			//	ARG (1), ARG (2), ARG (1), ARG (2), ARG (0));
		}
		break;
	case MIPS_INS_SUBU:
	case MIPS_INS_DSUB:
	case MIPS_INS_DSUBU:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=",
			arg2, arg1, arg0);
		}
		break;
	case MIPS_INS_NEG:
	case MIPS_INS_NEGU:
		r_strbuf_appendf (&op->esil, "%s,0,-,%s,=,",
			ARG (1), ARG (0));
		break;

	/** signed -- sets overflow flag */
	case MIPS_INS_ADD:
		{
		PROTECT_ZERO () {
			r_strbuf_appendf(&op->esil, "%s,%s,-,%s,=",
				ARG (1), ARG (2), ARG (0));
#if 0
			r_strbuf_appendf (&op->esil,
				"0,32,%s,%s,+,>>,>,?{,1,TRAP,}{,%s,%s,+,%s,=,}",
				ARG(2), ARG(1), ARG(2), ARG(1), ARG(0));
#endif
		}
		}
		break;
	case MIPS_INS_ADDI:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "0,32,%s,0xffffffff,&,%s,+,>>,>,?{,1,TRAP,}{,%s,%s,+,%s,=,}",
				ARG(2), ARG(1), ARG(2), ARG(1), ARG(0));
		}
		break;
	case MIPS_INS_DADD:
	case MIPS_INS_DADDI:
	/** unsigned */
	case MIPS_INS_ADDU:
	case MIPS_INS_ADDIU:
	case MIPS_INS_DADDIU:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		PROTECT_ZERO () {
			if (*arg2 == '-') {
				r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=",
						arg2+1, arg1, arg0);
			} else {
				r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=",
						arg2, arg1, arg0);
			}
		}
		}
		break;
	case MIPS_INS_LI:
		r_strbuf_appendf (&op->esil, "0x%"PFMT64x",%s,=", IMM(1), ARG(0));
		break;
	case MIPS_INS_LUI:
		r_strbuf_appendf (&op->esil, "0x%"PFMT64x"0000,%s,=", IMM(1), ARG(0));
		break;
	case MIPS_INS_LB:
	case MIPS_INS_LBU:
		//one of these is wrong
		ESIL_LOAD ("1");
		break;
	case MIPS_INS_LW:
	case MIPS_INS_LWC1:
	case MIPS_INS_LWC2:
	case MIPS_INS_LWL:
	case MIPS_INS_LWR:
	case MIPS_INS_LWU:
	case MIPS_INS_LL:
	case MIPS_INS_LLD:
	case MIPS_INS_LD:
	case MIPS_INS_LDI:
	case MIPS_INS_LDL:
	case MIPS_INS_LDC1:
	case MIPS_INS_LDC2:
		ESIL_LOAD ("4");
		break;

	case MIPS_INS_LWX:
	case MIPS_INS_LH:
	case MIPS_INS_LHU:
	case MIPS_INS_LHX:
		ESIL_LOAD ("2");
		break;

	case MIPS_INS_AND:
	case MIPS_INS_ANDI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		r_strbuf_appendf (&op->esil, "%s,%s,&,%s,=",
			arg2, arg1, arg0);
		}
		break;
	case MIPS_INS_OR:
	case MIPS_INS_ORI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "%s,%s,|,%s,=",
				arg2, arg1, arg0);
		}
		}
		break;
	case MIPS_INS_XOR:
	case MIPS_INS_XORI:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "%s,%s,^,%s,=",
				arg2, arg1, arg0);
		}
		}
		break;
	case MIPS_INS_NOR:
		{
		const char *arg0 = ARG(0);
		const char *arg1 = ARG(1);
		const char *arg2 = ARG(2);
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "%s,%s,|,0xffffffff,^,%s,=",
				arg2, arg1, arg0);
		}
		}
		break;
	case MIPS_INS_SLT:
	case MIPS_INS_SLTI:
		if (OPCOUNT () < 3) {
			r_strbuf_appendf (&op->esil,
				ES_IS_NEGATIVE ("%s")","
				ES_IS_NEGATIVE ("%s")","
				"==,$z,?{,"
					"%s,%s,<,t,=,"
				"}{,"
					"%s,%s,>=,t,=,"
				"}",

				ARG (1),
				ARG (0),
				ARG (1), ARG (0),
				ARG (1), ARG (0));
		} else {
			r_strbuf_appendf (&op->esil,
				ES_IS_NEGATIVE ("%s")","
				ES_IS_NEGATIVE ("%s")","
				"==,$z,?{,"
					"%s,%s,<,%s,=,"
				"}{,"
					"%s,%s,>=,%s,=,"
				"}",

				ARG (2),
				ARG (1),
				ARG (2), ARG (1), ARG (0),
				ARG (2), ARG (1), ARG (0));
		}
		break;
	case MIPS_INS_SLTU:
	case MIPS_INS_SLTIU:
		if (OPCOUNT () < 3) {
			r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,t,=",
				ARG (1), ARG (0));
		} else {
			r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,%s,=",
				ARG (2), ARG (1), ARG (0));
		}
		break;
	case MIPS_INS_MULT:
	case MIPS_INS_MULTU:
		r_strbuf_appendf (&op->esil,
			"%s,%s,*,0xffffffff,&,lo,=,"
			ES_SIGN_EXT64 ("lo")
			",32,%s,%s,*,>>,0xffffffff,&,hi,=,"
			ES_SIGN_EXT64 ("hi"),

			ARG (0), ARG (1), ARG (0), ARG (1));
		break;
	case MIPS_INS_MFLO:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "lo,%s,=", REG (0));
		}
		break;
	case MIPS_INS_MFHI:
		PROTECT_ZERO () {
			r_strbuf_appendf (&op->esil, "hi,%s,=", REG (0));
		}
		break;
	case MIPS_INS_MTLO:
		r_strbuf_appendf (&op->esil, "%s,lo,=,"ES_SIGN_EXT64 ("lo"), REG (0));
		break;
	case MIPS_INS_MTHI:
		r_strbuf_appendf (&op->esil, "%s,hi,=,"ES_SIGN_EXT64 ("hi"), REG (0));
		break;
#if 0
	// could not test div
	case MIPS_INS_DIV:
	case MIPS_INS_DIVU:
	case MIPS_INS_DDIV:
	case MIPS_INS_DDIVU:
		PROTECT_ZERO () {
			// 32 bit needs sign extend
			r_strbuf_appendf (&op->esil, "%s,%s,/,lo,=,%s,%s,%%,hi,=", REG(1), REG(0), REG(1), REG(0));
		}
		break;
#endif
	default:
		return -1;
	}
	return 0;
}
static int baleful_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	const ut8  *r   = 0;
	const ut8  *r0  = 0;
	const ut8  *r1  = 0;
	const ut8  *p   = 0;
	const ut32 *imm = 0;
	const ut32 *imm1 = 0;
	const ut8 p0[16];
	const ut8 p1[16];
	const ut8 p2[16];
	const ut8 p3[16];

	if (op == NULL)
		return 1;
	memset (op, 0, sizeof (RAnalOp));
	op->type = R_ANAL_OP_TYPE_NULL;
	op->delay = 0;
	op->jump = op->fail = -1;
	op->ptr = op->val = -1;
	op->refptr = 0;
	r_strbuf_init (&op->esil);
	switch (buf[0]) {
	case 2: // 8 8 11 5  ADD +
		op->type = R_ANAL_OP_TYPE_ADD;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,+,%s,=",p2,p1,p0);
		break;
	case 3: // 8 8 11 5  SUB -
		op->type = R_ANAL_OP_TYPE_SUB;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,-,%s,=",p2,p1,p0);
		break;
	case 4: // 8 8 11 5  MUL *
		op->type = R_ANAL_OP_TYPE_MUL;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,*,%s,=",p2,p1,p0);
		break;
	case 6: // 8 8 11 5  XOR ^
		op->type = R_ANAL_OP_TYPE_XOR;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,^,%s,=",p2,p1,p0);
		break;
	case 9: // 8 8 11 5  AND &
		op->type = R_ANAL_OP_TYPE_AND;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,&,%s,=",p2,p1,p0);
		break;
	case 10: // 8 8 11 5 OR |
		op->type = R_ANAL_OP_TYPE_OR;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,|,%s,=",p2,p1,p0);
		break;
	case 12: // 8 8 11 5 ROL <<<<
		op->type = R_ANAL_OP_TYPE_ROL;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,<<<<,%s,=",p2,p1,p0);
		break;
	case 13: // 8 8 11 5 ROR >>>>
		op->type = R_ANAL_OP_TYPE_ROR;
		op->size = getp(buf,p0,p1,p2,p3,0);
		r_strbuf_setf (&op->esil, "%s,%s,>>>>,%s,=",p2,p1,p0);
		break;
	case 25: //          ++
		op->type = R_ANAL_OP_TYPE_ADD;
		op->size = getp(buf,p0,p1,p2,p3,6);	
		r_strbuf_setf (&op->esil, "%s,++,=",p1);
		break;
	case 26: //          --
		op->type = R_ANAL_OP_TYPE_SUB;
		op->size = getp(buf,p0,p1,p2,p3,6);	
		r_strbuf_setf (&op->esil, "%s,--,=",p1);
		break;
		////////////////////////////////////////// SPECIAL DIV/MOD ////////////////////////////////
	case 5: // 9 9 12 6  DIV
		op->type = R_ANAL_OP_TYPE_DIV;
		op->size = getp(buf,p0,p1,p2,p3,1);
		r_strbuf_setf (&op->esil, "%s,%s,/,%s,=,%s,%s,%%,%s,=",p2,p1,p0,p2,p1,p3);
		break;
		////////////////////////////////// MOVS ///////////////////////////////////////////////////
	case 24: //7 4       MOV
		op->type = R_ANAL_OP_TYPE_MOV;
		op->size = getp(buf,p0,p1,p2,p3,3);	
		r_strbuf_setf (&op->esil, "%s,%s,=",p2,p1);
		break;
	case 27: //          MOV r,[r]
		r  = buf + 1;
		r1 = buf + 2;
		op->type = R_ANAL_OP_TYPE_MOV;
		op->size = 3;
		r_strbuf_setf (&op->esil, "r_%02x,[4],r_%02x,=",*r1,*r);
		break;
	case 28://           MOV [r],r1
		r  = buf + 1;
		r1 = buf + 2;
		op->type = R_ANAL_OP_TYPE_MOV;
		op->size = 3;
		r_strbuf_setf (&op->esil, "r_%02x,r_%02x,=[4]",*r1,*r);
		break;
		///////////////////////////////// JUMPS /////////////////////////////////////////////////
	case 14: //5         JMP
		imm  = (ut32 *)(buf + 1);
		op->type = R_ANAL_OP_TYPE_JMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil,"%s,pc,=",p1);
		break;
	case 16: //5         JZ
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "zf,?{,%s,pc,=,}",p1);	
		break;
	case 21: //5         JNZ
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "zf,!,?{,%s,pc,=,}",p1);	
		break;
	case 17: //5         JS
		op->type = R_ANAL_OP_TYPE_CJMP;		
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "sf,?{,%s,pc,=,}",p1);			
		break;
	case 20: //5         JNS
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "sf,!,?{,%s,pc,=,}",p1);			  							
		break;
	case 19: //5         JG
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "gf,?{,%s,pc,=,}",p1);	
		break;
	case 18: //5         JBE
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil, "gf,!,?{,%s,pc,=,}",p1);	
		break;
		////////////////////////////////   EFLAGS WRITER  ///////////////////////////////////////////////////////////
		// http://www.read.seas.harvard.edu/~kohler/class/aosref/i386/appc.htm
		//http://sourceforge.net/p/fake86/code/ci/master/tree/src/fake86/cpu.c
	case 22: // 7 7 10 4 AND
		op->type = R_ANAL_OP_TYPE_AND;
		op->size = getp(buf,p0,p1,p2,p3,2);
		break;
	case 23: // 7 7 10 4 CMP 
		op->type = R_ANAL_OP_TYPE_SUB;
		op->size = getp(buf,p0,p1,p2,p3,2);		
		r_strbuf_setf(&op->esil,"0,sf,=,%s,%s,<,sf,=,0,zf,=,%s,%s,==,%%z,zf,=,0,gf,=,%s,%s,>,gf,=",p1,p2,p1,p2,p1,p2); 
		//"0,sf,=,%s,%s,<,sf,="      //SF 
		//"0,zf,=,%s,%s,==,%%z,zf,=" //ZF
		//"0,gf,=,%s,%s,>,gf,="      //GF
		break;	  
		/////////////////////////////////////// STACK ////////////////////////////////////////////////////////////     
	case 30: //6 3       PUSH
		p = buf + 1;
		op->type = R_ANAL_OP_TYPE_PUSH;
		op->size = getp(buf,p0,p1,p2,p3,4);	
		r_strbuf_setf(&op->esil,"%s,stk,=[4],4,stk,+=",p1);
		break;
	case 31: //          POP
		op->type = R_ANAL_OP_TYPE_POP;
		op->size = getp(buf,p0,p1,p2,p3,6);	
		r_strbuf_setf(&op->esil,"4,stk,-=,stk,[4],%s,=",p1);
		break;
	case 15: //5         CALL
		imm = (ut32 *)(buf + 1);
		op->type = R_ANAL_OP_TYPE_CALL;
		op->size = getp(buf,p0,p1,p2,p3,5);	
		r_strbuf_setf(&op->esil,"%04x,pc,+,stk,=[4],4,stk,+=,%s,pc,=",op->size,p1);
		break;
	case 1:  //          RET
		op->type = R_ANAL_OP_TYPE_RET;
		op->size = 1;
		r_strbuf_setf(&op->esil,"4,stk,-=,stk,[4],pc,=");
		break;
		///////////////////////////////////////////////////////////////////////////////////////////////////////////
	case 11:
		r_strbuf_setf (&op->esil, "regX = regY==0");
		op->size = 3;
		break;	
	case 7:
		r_strbuf_setf (&op->esil, "regX = NEG regY");
		op->size = 3;
		break;
	case 8:
		r_strbuf_setf (&op->esil, "regX = NOT regY");
		op->size = 3;
		break;
		///////////////////////////////////////////////////////////////////////////////////////////////////////////
	case 32: //          SYSCALL
		p = buf + 1;
		op->type = R_ANAL_OP_TYPE_CALL;
		op->size = 2;
		r_strbuf_setf (&op->esil, "%x,$",*p);
		/*if (*p==0)
		  r_strbuf_setf (&op->esil, "apicall: putchar()");
		  else
		  r_strbuf_setf (&op->esil, "apicall: %02x",*p);*/

		break;  
	case 29://           VMEND 
		op->type = R_ANAL_OP_TYPE_NOP;
		op->size = 1;
		r_strbuf_setf (&op->esil, "end virtual");
		break;
	case 0://            NOP
	default:
		op->type = R_ANAL_OP_TYPE_NOP;
		op->size = 1;
		r_strbuf_setf (&op->esil, "nop");
		break;
	}
	return op->size;
}
Exemple #15
0
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
	int i;
	char str[32][32];
	r_strbuf_init (&op->esil);
	r_strbuf_set (&op->esil, "");
	switch (insn->detail->arm.cc) {
	case ARM_CC_AL:
		// no condition
		break;
	case ARM_CC_EQ:
		r_strbuf_setf (&op->esil, "zf,0,?,");
		break;
	case ARM_CC_NE:
		r_strbuf_setf (&op->esil, "zf,!,0,?,");
		break;
	case ARM_CC_GT:
	case ARM_CC_LE:
		break;
	}
	// TODO: PREFIX CONDITIONAL
	switch (insn->id) {
	case ARM_INS_PUSH:
		// TODO: increment stack
	case ARM_INS_STM:
		for (i=1; i<insn->detail->arm.op_count; i++) {
			r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4],",
				REG (i), ARG (0), i*4);
		}
		break;
	case ARM_INS_POP:
		// TODO: decrement stack
	case ARM_INS_LDM:
		for (i=1; i<insn->detail->arm.op_count; i++) {
			r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=",
				ARG (0), i*4, REG (i));
		}
		break;
	case ARM_INS_CMP:
		r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0));
		break;
	case ARM_INS_LSL:
		// suffix 'S' forces conditional flag to be updated
		r_strbuf_appendf (&op->esil, "%s,%s,<<=", ARG(1), ARG(0));
		break;
	case ARM_INS_LSR:
		// suffix 'S' forces conditional flag to be updated
		r_strbuf_appendf (&op->esil, "%s,%s,>>=", ARG(1), ARG(0));
		break;
	case ARM_INS_B:
	case ARM_INS_BL:
	case ARM_INS_BLX:
		r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0));
		break;
	case ARM_INS_MOV:
	case ARM_INS_MOVS:
		r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0));
		break;
	case ARM_INS_SSUB16:
	case ARM_INS_SSUB8:
	case ARM_INS_SUB:
		r_strbuf_appendf (&op->esil, "%s,%s,-=", ARG(1), ARG(0));
		break;
	case ARM_INS_SADD16:
	case ARM_INS_SADD8:
	case ARM_INS_ADD:
		r_strbuf_appendf (&op->esil, "%s,%s,+=", ARG(1), ARG(0));
		break;
	case ARM_INS_LDR:
		r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=",
			MEMBASE(1), MEMDISP(1), REG(0));
		break;
	case ARM_INS_LDRB:
		r_strbuf_appendf (&op->esil, "%s,%d,+,[1],%s,=",
			MEMBASE(1), MEMDISP(1), REG(0));
		break;
	}
	return 0;
}
Exemple #16
0
static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	short ofst;
	int imm = 0, d, r, k;
	ut8 kbuf[4];
	ut16 ins = AVR_SOFTCAST (buf[0], buf[1]);
	char *arg, str[32];
	if (op == NULL) {
		return 2;
	}
	memset (op, '\0', sizeof (RAnalOp));
	op->type = R_ANAL_OP_TYPE_UNK;
	op->ptr = UT64_MAX;
	op->val = UT64_MAX;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->refptr = 0;
	op->nopcode = 1; // Necessary??
	op->size = avrdis (str, addr, buf, len);
	r_strbuf_init (&op->esil);
	arg = strchr (str, ' ');
	if (arg) {
		arg++;
		imm = (int)r_num_get (NULL, arg);
	}
	op->delay = 0;
	op->type = R_ANAL_OP_TYPE_UNK;
	if (!strncmp (str, "st", 2)) {
		op->type = R_ANAL_OP_TYPE_STORE;
	} else if (str[0] == 'l') {
		op->type = R_ANAL_OP_TYPE_LOAD;
	} else if (str[0] == 's') {
		op->type = R_ANAL_OP_TYPE_SUB;
	} else if (!strncmp (str, "inv", 3)) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else if (!strncmp (str, "ser ", 4)) {
		op->type = R_ANAL_OP_TYPE_MOV;
	} else if (!strncmp (str, "and", 3)) {
		op->type = R_ANAL_OP_TYPE_AND;
	} else if (!strncmp (str, "mul", 3)) {
		op->type = R_ANAL_OP_TYPE_MUL;
	} else if (!strncmp (str, "out ", 4)) {
		op->type = R_ANAL_OP_TYPE_IO;
		op->type2 = 1;
		op->val = imm;
	} else if (!strncmp (str, "in ", 3)) {
		op->type = R_ANAL_OP_TYPE_IO;
		op->type2 = 0;
		op->val = imm;
	} else if (!strncmp (str, "push ", 5)) {
		op->type = R_ANAL_OP_TYPE_PUSH;
	}
	if (ins == 0) {
		op->type = R_ANAL_OP_TYPE_NOP;
		op->cycles = 1;
	}
	if (buf[1] == 1) {			//MOVW
		d = (buf[0] & 0xf0) >> 3;
		r = (buf[0] & 0x0f) << 1;
		op->type = R_ANAL_OP_TYPE_MOV;
		op->cycles = 1;
		r_strbuf_setf (&op->esil, "r%d,r%d,=,r%d,r%d,=", r, d, r+1, d+1);
	}
Exemple #17
0
// analyzes the wasm opcode.
static int wasm_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	WasmOp wop = {{0}};
	RAnalHint *hint = NULL;
	memset (op, '\0', sizeof (RAnalOp));
	int ret = wasm_dis (&wop, data, len);
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->size = ret;
	op->addr = addr;
	op->sign = true;
	op->type = R_ANAL_OP_TYPE_UNK;
	switch (wop.type) {
		case WASM_TYPE_OP_CORE:
			op->id = wop.op.core;
			break;
		case WASM_TYPE_OP_ATOMIC:
			op->id = (0xfe << 8) | wop.op.atomic;
			break;
	}

	if (!wop.txt || !strncmp (wop.txt, "invalid", 7)) {
		op->type = R_ANAL_OP_TYPE_ILL;
		free (wop.txt);
		return -1;
	}

	if (addr_old == addr && (wop.type != WASM_TYPE_OP_CORE || wop.op.core != WASM_OP_END)) {
		goto anal_end;
	}

	switch (wop.type) {
	case WASM_TYPE_OP_CORE:
		switch (wop.op.core) {
		/* Calls here are using index instead of address */
		case WASM_OP_LOOP:
			op->type = R_ANAL_OP_TYPE_NOP;
			if (!(hint = r_anal_hint_get (anal, addr))) {
				scope_hint--;
				r_anal_hint_set_opcode (anal, scope_hint, "loop");
				r_anal_hint_set_jump (anal, scope_hint, addr);
			}
			break;
		case WASM_OP_BLOCK:
			op->type = R_ANAL_OP_TYPE_NOP;
			if (!(hint = r_anal_hint_get (anal, addr))) {
				scope_hint--;
				r_anal_hint_set_opcode (anal, scope_hint, "block");
				r_anal_hint_set_jump (anal, scope_hint, addr);
			}
			break;
		case WASM_OP_IF:
			if (!(hint = r_anal_hint_get (anal, addr))) {
				scope_hint--;
				r_anal_hint_set_opcode (anal, scope_hint, "if");
				r_anal_hint_set_jump (anal, scope_hint, addr);
				if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, 0, true)) {
					op->fail = addr + op->size;
				}
			} else {
				op->type = R_ANAL_OP_TYPE_CJMP;
				op->jump = hint->jump;
				op->fail = addr + op->size;
			}
			break;
		case WASM_OP_ELSE:
			// get if and set hint.
			if (!(hint = r_anal_hint_get (anal, addr))) {
				advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, 0, true);
			} else {
				op->type = R_ANAL_OP_TYPE_JMP;
				op->jump = hint->jump;
			}
			break;
		case WASM_OP_BR:
			{
				RAnalHint *hint2 = NULL;
				ut32 val;
				read_u32_leb128 (data + 1, data + len, &val);
				if ((hint2 = r_anal_hint_get (anal, addr)) && hint2->jump != UT64_MAX) {
					op->type = R_ANAL_OP_TYPE_JMP;
					op->jump = hint2->jump;
				} else if ((hint = r_anal_hint_get (anal, scope_hint))) {
					if (hint->opcode && !strncmp ("loop", hint->opcode, 4)) {
						op->type = R_ANAL_OP_TYPE_JMP;
						op->jump = hint->jump;
						r_anal_hint_set_jump (anal, addr, op->jump);
					} else {
						if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, val, false)) {
							r_anal_hint_set_jump (anal, addr, op->jump);
						}
					}
				} else {
					if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, val, false)) {
						eprintf ("[wasm] cannot find jump type for br (using block type)\n");
						r_anal_hint_set_jump (anal, addr, op->jump);
					} else {
						eprintf ("[wasm] cannot find jump for br\n");
					}
				}
				r_anal_hint_free (hint2);
			}
			break;
		case WASM_OP_BRIF:
			{
				RAnalHint *hint2 = NULL;
				ut32 val;
				read_u32_leb128 (data + 1, data + len, &val);
				if ((hint2 = r_anal_hint_get (anal, addr)) && hint2->jump != UT64_MAX) {
					op->type = R_ANAL_OP_TYPE_CJMP;
					op->jump = hint2->jump;
					op->fail = addr + op->size;
				} else if ((hint = r_anal_hint_get (anal, scope_hint))) {
					if (hint->opcode && !strncmp ("loop", hint->opcode, 4)) {
						op->fail = addr + op->size;
						op->jump = hint->jump;
						r_anal_hint_set_jump (anal, addr, op->jump);
					} else {
						if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, val, false)) {
							op->fail = addr + op->size;
							r_anal_hint_set_jump (anal, addr, op->jump);
						}
					}
				} else {
					if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, val, false)) {
						eprintf ("[wasm] cannot find jump type for br_if (using block type)\n");
						op->fail = addr + op->size;
						r_anal_hint_set_jump (anal, addr, op->jump);
					} else {
						eprintf ("[wasm] cannot find jump for br_if\n");
					}
				}
				r_anal_hint_free (hint2);
			}
			break;
		case WASM_OP_END:
			{
				op->type = R_ANAL_OP_TYPE_NOP;
				if (scope_hint < UT64_MAX) {
					hint = r_anal_hint_get (anal, scope_hint);
					if (hint && !strncmp ("loop", hint->opcode, 4)) {
						r_anal_hint_set_jump (anal, addr, op->jump);
						r_anal_hint_set_jump (anal, op->jump, addr);
					} else if (hint && !strncmp ("block", hint->opcode, 5)) {
						// if/else/block
						r_anal_hint_set_jump (anal, hint->jump, addr);
						r_anal_hint_set_jump (anal, addr, UT64_MAX);
					}
					if (hint) {
						r_anal_hint_set_opcode (anal, scope_hint, "invalid");
						r_anal_hint_set_jump (anal, scope_hint, UT64_MAX);
						r_anal_hint_del (anal, scope_hint, 1);
						scope_hint++;
					} else {
						// all wasm routines ends with an end.
						op->eob = true;
						op->type = R_ANAL_OP_TYPE_RET;
						scope_hint = UT64_MAX;
					}
				} else {
					if (!(hint = r_anal_hint_get (anal, addr))) {
						// all wasm routines ends with an end.
						op->eob = true;
						op->type = R_ANAL_OP_TYPE_RET;
					}
				}
			}
			break;
		case WASM_OP_I32REMS:
		case WASM_OP_I32REMU:
			op->type = R_ANAL_OP_TYPE_MOD;
			break;
		case WASM_OP_GETLOCAL:
		case WASM_OP_I32LOAD:
		case WASM_OP_I64LOAD:
		case WASM_OP_F32LOAD:
		case WASM_OP_F64LOAD:
		case WASM_OP_I32LOAD8S:
		case WASM_OP_I32LOAD8U:
		case WASM_OP_I32LOAD16S:
		case WASM_OP_I32LOAD16U:
		case WASM_OP_I64LOAD8S:
		case WASM_OP_I64LOAD8U:
		case WASM_OP_I64LOAD16S:
		case WASM_OP_I64LOAD16U:
		case WASM_OP_I64LOAD32S:
		case WASM_OP_I64LOAD32U:
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case WASM_OP_SETLOCAL:
		case WASM_OP_TEELOCAL:
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case WASM_OP_I32EQZ:
		case WASM_OP_I32EQ:
		case WASM_OP_I32NE:
		case WASM_OP_I32LTS:
		case WASM_OP_I32LTU:
		case WASM_OP_I32GTS:
		case WASM_OP_I32GTU:
		case WASM_OP_I32LES:
		case WASM_OP_I32LEU:
		case WASM_OP_I32GES:
		case WASM_OP_I32GEU:
		case WASM_OP_I64EQZ:
		case WASM_OP_I64EQ:
		case WASM_OP_I64NE:
		case WASM_OP_I64LTS:
		case WASM_OP_I64LTU:
		case WASM_OP_I64GTS:
		case WASM_OP_I64GTU:
		case WASM_OP_I64LES:
		case WASM_OP_I64LEU:
		case WASM_OP_I64GES:
		case WASM_OP_I64GEU:
		case WASM_OP_F32EQ:
		case WASM_OP_F32NE:
		case WASM_OP_F32LT:
		case WASM_OP_F32GT:
		case WASM_OP_F32LE:
		case WASM_OP_F32GE:
		case WASM_OP_F64EQ:
		case WASM_OP_F64NE:
		case WASM_OP_F64LT:
		case WASM_OP_F64GT:
		case WASM_OP_F64LE:
		case WASM_OP_F64GE:
			op->type = R_ANAL_OP_TYPE_CMP;
			break;
		case WASM_OP_I64OR:
		case WASM_OP_I32OR:
			op->type = R_ANAL_OP_TYPE_OR;
			break;
		case WASM_OP_I64XOR:
		case WASM_OP_I32XOR:
			op->type = R_ANAL_OP_TYPE_XOR;
			break;
		case WASM_OP_I32CONST:
		case WASM_OP_I64CONST:
		case WASM_OP_F32CONST:
		case WASM_OP_F64CONST:
			op->type = R_ANAL_OP_TYPE_MOV;
			{
				ut8 arg = data[1];
				r_strbuf_setf (&op->esil, "4,sp,-=,%d,sp,=[4]", arg);
			}
			break;
		case WASM_OP_I64ADD:
		case WASM_OP_I32ADD:
		case WASM_OP_F32ADD:
		case WASM_OP_F64ADD:
			op->type = R_ANAL_OP_TYPE_ADD;
			break;
		case WASM_OP_I64SUB:
		case WASM_OP_I32SUB:
		case WASM_OP_F32SUB:
		case WASM_OP_F64SUB:
			op->type = R_ANAL_OP_TYPE_SUB;
			break;
		case WASM_OP_NOP:
			op->type = R_ANAL_OP_TYPE_NOP;
			r_strbuf_setf (&op->esil, "");
			break;
		case WASM_OP_CALL:
		case WASM_OP_CALLINDIRECT:
			op->type = R_ANAL_OP_TYPE_CALL;
			op->jump = get_cf_offset (anal, data, len);
			op->fail = addr + op->size;
			if (op->jump != UT64_MAX) {
				op->ptr = op->jump;
			}
			r_strbuf_setf (&op->esil, "4,sp,-=,0x%"PFMT64x",sp,=[4],0x%"PFMT64x",pc,=", op->fail, op->jump);
			break;
		case WASM_OP_RETURN:
			// should be ret, but if there the analisys is stopped.
			op->type = R_ANAL_OP_TYPE_CRET;
		default:
			break;
		}
		break;
	case WASM_TYPE_OP_ATOMIC:
		switch (wop.op.atomic) {
		case WASM_OP_I32ATOMICLOAD:
		case WASM_OP_I64ATOMICLOAD:
		case WASM_OP_I32ATOMICLOAD8U:
		case WASM_OP_I32ATOMICLOAD16U:
		case WASM_OP_I64ATOMICLOAD8U:
		case WASM_OP_I64ATOMICLOAD16U:
		case WASM_OP_I64ATOMICLOAD32U:
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case WASM_OP_I32ATOMICSTORE:
		case WASM_OP_I64ATOMICSTORE:
		case WASM_OP_I32ATOMICSTORE8:
		case WASM_OP_I32ATOMICSTORE16:
		case WASM_OP_I64ATOMICSTORE8:
		case WASM_OP_I64ATOMICSTORE16:
		case WASM_OP_I64ATOMICSTORE32:
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case WASM_OP_I32ATOMICRMWADD:
		case WASM_OP_I64ATOMICRMWADD:
		case WASM_OP_I32ATOMICRMW8UADD:
		case WASM_OP_I32ATOMICRMW16UADD:
		case WASM_OP_I64ATOMICRMW8UADD:
		case WASM_OP_I64ATOMICRMW16UADD:
		case WASM_OP_I64ATOMICRMW32UADD:
			op->type = R_ANAL_OP_TYPE_ADD;
			break;
		case WASM_OP_I32ATOMICRMW8USUB:
		case WASM_OP_I32ATOMICRMW16USUB:
		case WASM_OP_I32ATOMICRMWSUB:
		case WASM_OP_I64ATOMICRMW8USUB:
		case WASM_OP_I64ATOMICRMW16USUB:
		case WASM_OP_I64ATOMICRMW32USUB:
		case WASM_OP_I64ATOMICRMWSUB:
			op->type = R_ANAL_OP_TYPE_SUB;
			break;
		case WASM_OP_I32ATOMICRMWAND:
		case WASM_OP_I64ATOMICRMWAND:
		case WASM_OP_I32ATOMICRMW8UAND:
		case WASM_OP_I32ATOMICRMW16UAND:
		case WASM_OP_I64ATOMICRMW8UAND:
		case WASM_OP_I64ATOMICRMW16UAND:
		case WASM_OP_I64ATOMICRMW32UAND:
			op->type = R_ANAL_OP_TYPE_AND;
			break;
		case WASM_OP_I32ATOMICRMWOR:
		case WASM_OP_I64ATOMICRMWOR:
		case WASM_OP_I32ATOMICRMW8UOR:
		case WASM_OP_I32ATOMICRMW16UOR:
		case WASM_OP_I64ATOMICRMW8UOR:
		case WASM_OP_I64ATOMICRMW16UOR:
		case WASM_OP_I64ATOMICRMW32UOR:
			op->type = R_ANAL_OP_TYPE_OR;
			break;
		case WASM_OP_I32ATOMICRMWXOR:
		case WASM_OP_I64ATOMICRMWXOR:
		case WASM_OP_I32ATOMICRMW8UXOR:
		case WASM_OP_I32ATOMICRMW16UXOR:
		case WASM_OP_I64ATOMICRMW8UXOR:
		case WASM_OP_I64ATOMICRMW16UXOR:
		case WASM_OP_I64ATOMICRMW32UXOR:
			op->type = R_ANAL_OP_TYPE_XOR;
			break;
		case WASM_OP_I32ATOMICRMWXCHG:
		case WASM_OP_I64ATOMICRMWXCHG:
		case WASM_OP_I32ATOMICRMW8UXCHG:
		case WASM_OP_I32ATOMICRMW16UXCHG:
		case WASM_OP_I64ATOMICRMW8UXCHG:
		case WASM_OP_I64ATOMICRMW16UXCHG:
		case WASM_OP_I64ATOMICRMW32UXCHG:
			op->type = R_ANAL_OP_TYPE_XCHG;
			break;
		default:
			break;
		}
	default:
		break;
	}

anal_end:
	addr_old = addr;
	free (wop.txt);
	r_anal_hint_free (hint);
	return op->size;
}
Exemple #18
0
// analyzes the wasm opcode.
static int wasm_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	ut64 addr2 = UT64_MAX;
	int i;
	WasmOp wop = {0};
	memset (op, '\0', sizeof (RAnalOp));
	int ret = wasm_dis (&wop, data, len);
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->size = ret;
	op->addr = addr;
	op->sign = true;
	op->type = R_ANAL_OP_TYPE_UNK;
	op->id = wop.op;

	if (!wop.txt || !strncmp (wop.txt, "invalid", 7)) {
		op->type = R_ANAL_OP_TYPE_ILL;
		wasm_stack_ptr = 0;
		free (wop.txt);
		return -1;
	}
	if (wasm_stack_ptr >= WASM_STACK_SIZE) {
		wasm_stack_ptr = 0;
		op->type = R_ANAL_OP_TYPE_NULL;
		free (wop.txt);
		return -1;
	}
	switch (wop.op) {
	/* Calls here are using index instead of address */
	case WASM_OP_LOOP:
		addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true);
		op->type = R_ANAL_OP_TYPE_NOP;
		if (addr2 != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (loop)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = addr;
			wasm_stack[wasm_stack_ptr].end = addr2;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		//op->fail = addr + op->size;
		break;
	case WASM_OP_BLOCK:
		op->type = R_ANAL_OP_TYPE_NOP;
		addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true);
		if (addr2 != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (block)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = UT64_MAX;
			wasm_stack[wasm_stack_ptr].end = addr2;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		break;
	case WASM_OP_IF:
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false);
		op->fail = addr + op->size;
		if (op->jump != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (if)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = UT64_MAX;
			wasm_stack[wasm_stack_ptr].end = op->fail;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		break;
	case WASM_OP_ELSE:
		op->type = R_ANAL_OP_TYPE_JMP;
		op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false);
		break;
	case WASM_OP_I32REMS:
	case WASM_OP_I32REMU:
		op->type = R_ANAL_OP_TYPE_MOD;
		break;
	case WASM_OP_END:
		//eprintf("0x%016x < stack %u (end)\n", addr, wasm_stack_ptr);
		if (wasm_stack_ptr > 0) {
			op->type = R_ANAL_OP_TYPE_NOP;
			if (addr != UT64_MAX) {
				for (i = wasm_stack_ptr - 1; i > 0; i--) {
					if (wasm_stack[i].end == addr && wasm_stack[i].loop != UT64_MAX) {
						op->type = R_ANAL_OP_TYPE_CJMP;
						op->jump = wasm_stack[i].loop;
						op->fail = addr + op->size;
						break;
					}
				}
			}
			wasm_stack_ptr--;
		} else {
			// all wasm routines ends with an end.
			op->eob = true;
			op->type = R_ANAL_OP_TYPE_RET;
		}
		break;
	case WASM_OP_GETLOCAL:
	case WASM_OP_I32LOAD:
	case WASM_OP_I64LOAD:
	case WASM_OP_F32LOAD:
	case WASM_OP_F64LOAD:
	case WASM_OP_I32LOAD8S:
	case WASM_OP_I32LOAD8U:
	case WASM_OP_I32LOAD16S:
	case WASM_OP_I32LOAD16U:
	case WASM_OP_I64LOAD8S:
	case WASM_OP_I64LOAD8U:
	case WASM_OP_I64LOAD16S:
	case WASM_OP_I64LOAD16U:
	case WASM_OP_I64LOAD32S:
	case WASM_OP_I64LOAD32U:
		op->type = R_ANAL_OP_TYPE_LOAD;
		break;
	case WASM_OP_SETLOCAL:
	case WASM_OP_TEELOCAL:
		op->type = R_ANAL_OP_TYPE_STORE;
		break;
	case WASM_OP_I32EQZ:
	case WASM_OP_I32EQ:
	case WASM_OP_I32NE:
	case WASM_OP_I32LTS:
	case WASM_OP_I32LTU:
	case WASM_OP_I32GTS:
	case WASM_OP_I32GTU:
	case WASM_OP_I32LES:
	case WASM_OP_I32LEU:
	case WASM_OP_I32GES:
	case WASM_OP_I32GEU:
	case WASM_OP_I64EQZ:
	case WASM_OP_I64EQ:
	case WASM_OP_I64NE:
	case WASM_OP_I64LTS:
	case WASM_OP_I64LTU:
	case WASM_OP_I64GTS:
	case WASM_OP_I64GTU:
	case WASM_OP_I64LES:
	case WASM_OP_I64LEU:
	case WASM_OP_I64GES:
	case WASM_OP_I64GEU:
	case WASM_OP_F32EQ:
	case WASM_OP_F32NE:
	case WASM_OP_F32LT:
	case WASM_OP_F32GT:
	case WASM_OP_F32LE:
	case WASM_OP_F32GE:
	case WASM_OP_F64EQ:
	case WASM_OP_F64NE:
	case WASM_OP_F64LT:
	case WASM_OP_F64GT:
	case WASM_OP_F64LE:
	case WASM_OP_F64GE:
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case WASM_OP_I64OR:
	case WASM_OP_I32OR:
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case WASM_OP_I64XOR:
	case WASM_OP_I32XOR:
		op->type = R_ANAL_OP_TYPE_XOR;
		break;
	case WASM_OP_I32CONST:
	case WASM_OP_I64CONST:
	case WASM_OP_F32CONST:
	case WASM_OP_F64CONST:
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut8 arg = data[1];
			r_strbuf_setf (&op->esil, "4,sp,-=,%d,sp,=[4]", arg);
		}
		break;
	case WASM_OP_I64ADD:
	case WASM_OP_I32ADD:
	case WASM_OP_F32ADD:
	case WASM_OP_F64ADD:
		op->type = R_ANAL_OP_TYPE_ADD;
		break;
	case WASM_OP_I64SUB:
	case WASM_OP_I32SUB:
	case WASM_OP_F32SUB:
	case WASM_OP_F64SUB:
		op->type = R_ANAL_OP_TYPE_SUB;
		break;
	case WASM_OP_NOP:
		op->type = R_ANAL_OP_TYPE_NOP;
		r_strbuf_setf (&op->esil, "");
		break;
	case WASM_OP_CALL:
	case WASM_OP_CALLINDIRECT:
		op->type = R_ANAL_OP_TYPE_CALL;
		op->jump = get_cf_offset (anal, data);
		op->fail = addr + op->size;
		if (op->jump != UT64_MAX) {
			op->ptr = op->jump;
		}
		r_strbuf_setf (&op->esil, "4,sp,-=,0x%"PFMT64x",sp,=[4],0x%"PFMT64x",pc,=", op->fail, op->jump);
		break;
	case WASM_OP_BR:
		op->type = R_ANAL_OP_TYPE_JMP;
		set_br_jump(op, data, len - op->size);
		break;
	case WASM_OP_BRIF:
		op->fail = addr + op->size;
		op->type = R_ANAL_OP_TYPE_CJMP;
		set_br_jump(op, data, len - op->size);
		break;
	case WASM_OP_RETURN:
		// should be ret, but if there the analisys is stopped.
		op->type = R_ANAL_OP_TYPE_CRET;
	default:
		break;
	}
	op_old = wop.op;
	addr_old = addr;
	free (wop.txt);
	return op->size;
}
Exemple #19
0
static int _6502_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	char addrbuf[64];
	const int buffsize = sizeof(addrbuf)-1;

	memset (op, '\0', sizeof (RAnalOp));
	op->size = snes_op[data[0]].len;	//snes-arch is similiar to nes/6502
	op->addr = addr;
	op->type = R_ANAL_OP_TYPE_UNK;
	r_strbuf_init (&op->esil);
	switch (data[0]) {
	case 0x02:
	case 0x03:
	case 0x04:
	case 0x07:
	case 0x0b:
	case 0x0c:
	case 0x0f:
	case 0x12:
	case 0x13:
	case 0x14:
	case 0x17:
	case 0x1a:
	case 0x1b:
	case 0x1c:
	case 0x1f:
	case 0x22:
	case 0x23:
	case 0x27:
	case 0x2b:
	case 0x2f:
	case 0x32:
	case 0x33:
	case 0x34:
	case 0x37:
	case 0x3a:
	case 0x3b:
	case 0x3c:
	case 0x3f:
	case 0x42:
	case 0x43:
	case 0x44:
	case 0x47:
	case 0x4b:
	case 0x4f:
	case 0x52:
	case 0x53:
	case 0x54:
	case 0x57:
	case 0x5a:
	case 0x5b:
	case 0x5c:
	case 0x5f:
	case 0x62:
	case 0x63:
	case 0x64:
	case 0x67:
	case 0x6b:
	case 0x6f:
	case 0x72:
	case 0x73:
	case 0x74:
	case 0x77:
	case 0x7a:
	case 0x7b:
	case 0x7c:
	case 0x7f:
	case 0x80:
	case 0x82:
	case 0x83:
	case 0x87:
	case 0x89:
	case 0x8b:
	case 0x8f:
	case 0x92:
	case 0x93:
	case 0x97:
	case 0x9b:
	case 0x9c:
	case 0x9e:
	case 0x9f:
	case 0xa3:
	case 0xa7:
	case 0xab:
	case 0xaf:
	case 0xb2:
	case 0xb3:
	case 0xb7:
	case 0xbb:
	case 0xbf:
	case 0xc2:
	case 0xc3:
	case 0xc7:
	case 0xcb:
	case 0xcf:
	case 0xd2:
	case 0xd3:
	case 0xd4:
	case 0xd7:
	case 0xda:
	case 0xdb:
	case 0xdc:
	case 0xdf:
	case 0xe2:
	case 0xe3:
	case 0xe7:
	case 0xeb:
	case 0xef:
	case 0xf2:
	case 0xf3:
	case 0xf4:
	case 0xf7:
	case 0xfa:
	case 0xfb:
	case 0xfc:
	case 0xff:
		// undocumented or not-implemented opcodes for 6502.
		// some of them might be implemented in 65816
		op->size = 1;
		op->type = R_ANAL_OP_TYPE_ILL;
		break;

	// BRK
	case 0x00: // brk
		op->cycles = 7;
		op->type = R_ANAL_OP_TYPE_SWI;
		// override 65816 code which seems to be wrong: size is 1, but pc = pc + 2
		op->size = 1;
		// PC + 2 to Stack, P to Stack  B=1 D=0 I=1. "B" is not a flag. Only its bit is pushed on the stack
		// PC was already incremented by one at this point. Needs to incremented once more
		// New PC is Interrupt Vector: $fffe. (FIXME: Confirm this is valid for all 6502)
		r_strbuf_set (&op->esil, ",1,I,=,0,D,=,flags,0x10,|,0x100,sp,+,=[1],pc,1,+,0xfe,sp,+,=[2],3,sp,-=,0xfffe,[2],pc,=");
		break;

	// FLAGS
	case 0x78: // sei
	case 0x58: // cli
	case 0x38: // sec
	case 0x18: // clc
	case 0xf8: // sed
	case 0xd8: // cld
	case 0xb8: // clv
		op->cycles = 2;
		// FIXME: what opcode for this?
		op->type = R_ANAL_OP_TYPE_NOP;
		_6502_anal_esil_flags (op, data[0]);
		break;
	// BIT
	case 0x24: // bit $ff
	case 0x2c: // bit $ffff
		op->type = R_ANAL_OP_TYPE_MOV;
		_6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0);
		r_strbuf_setf (&op->esil, "a,%s,[1],&,0x80,&,!,!,N,=,a,%s,[1],&,0x40,&,!,!,V,=,a,%s,[1],&,0xff,&,!,Z,=",addrbuf, addrbuf, addrbuf);
		break;
	// ADC
	case 0x69: // adc #$ff
	case 0x65: // adc $ff
	case 0x75: // adc $ff,x
	case 0x6d: // adc $ffff
	case 0x7d: // adc $ffff,x
	case 0x79: // adc $ffff,y
	case 0x61: // adc ($ff,x)
	case 0x71: // adc ($ff,y)
		// FIXME: update V
		// FIXME: support BCD mode
		op->type = R_ANAL_OP_TYPE_ADD;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0x69) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,+=,C,NUM,$c7,C,=,a,+=,$c7,C,|=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,+=,C,NUM,$c7,C,=,a,+=,$c7,C,|=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		// fix Z
		r_strbuf_append (&op->esil, ",a,a,=,$z,Z,=");
		break;
	// SBC
	case 0xe9: // sbc #$ff
	case 0xe5: // sbc $ff
	case 0xf5: // sbc $ff,x
	case 0xed: // sbc $ffff
	case 0xfd: // sbc $ffff,x
	case 0xf9: // sbc $ffff,y
	case 0xe1: // sbc ($ff,x)
	case 0xf1: // sbc ($ff,y)
		// FIXME: update V
		// FIXME: support BCD mode
		op->type = R_ANAL_OP_TYPE_SUB;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0xe9) // immediate mode
			r_strbuf_setf (&op->esil, "C,!,%s,+,a,-=", addrbuf);
		else	r_strbuf_setf (&op->esil, "C,!,%s,[1],+,a,-=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_BNZ);
		// fix Z and revert C
		r_strbuf_append (&op->esil, ",a,a,=,$z,Z,=,C,!=");
		break;
	// ORA
	case 0x09: // ora #$ff
	case 0x05: // ora $ff
	case 0x15: // ora $ff,x
	case 0x0d: // ora $ffff
	case 0x1d: // ora $ffff,x
	case 0x19: // ora $ffff,y
	case 0x01: // ora ($ff,x)
	case 0x11: // ora ($ff),y
		op->type = R_ANAL_OP_TYPE_OR;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0x09) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,|=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,|=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// AND
	case 0x29: // and #$ff
	case 0x25: // and $ff
	case 0x35: // and $ff,x
	case 0x2d: // and $ffff
	case 0x3d: // and $ffff,x
	case 0x39: // and $ffff,y
	case 0x21: // and ($ff,x)
	case 0x31: // and ($ff),y
		op->type = R_ANAL_OP_TYPE_AND;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0x29) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,&=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,&=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// EOR
	case 0x49: // eor #$ff
	case 0x45: // eor $ff
	case 0x55: // eor $ff,x
	case 0x4d: // eor $ffff
	case 0x5d: // eor $ffff,x
	case 0x59: // eor $ffff,y
	case 0x41: // eor ($ff,x)
	case 0x51: // eor ($ff),y
		op->type = R_ANAL_OP_TYPE_XOR;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0x49) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,^=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,^=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// ASL
	case 0x0a: // asl a
	case 0x06: // asl $ff
	case 0x16: // asl $ff,x
	case 0x0e: // asl $ffff
	case 0x1e: // asl $ffff,x
		op->type = R_ANAL_OP_TYPE_SHL;
		if (data[0] == 0x0a) {
			r_strbuf_set (&op->esil, "1,a,<<=,$c7,C,=,a,a,=");
		} else  {
			_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
			r_strbuf_setf (&op->esil, "1,%s,[1],<<,%s,=[1],$c7,C,=", addrbuf, addrbuf);
		}
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// LSR
	case 0x4a: // lsr a
	case 0x46: // lsr $ff
	case 0x56: // lsr $ff,x
	case 0x4e: // lsr $ffff
	case 0x5e: // lsr $ffff,x
		op->type = R_ANAL_OP_TYPE_SHR;
		if (data[0] == 0x4a) {
			r_strbuf_set (&op->esil, "1,a,&,C,=,1,a,>>=");
		} else {
			_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
			r_strbuf_setf (&op->esil, "1,%s,[1],&,C,=,1,%s,[1],>>,%s,=[1]", addrbuf, addrbuf, addrbuf);
		}
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// ROL
	case 0x2a: // rol a
	case 0x26: // rol $ff
	case 0x36: // rol $ff,x
	case 0x2e: // rol $ffff
	case 0x3e: // rol $ffff,x
		op->type = R_ANAL_OP_TYPE_ROL;
		if (data[0] == 0x2a) {
			r_strbuf_set (&op->esil, "1,a,<<,C,|,a,=,$c7,C,=,a,a,=");
		} else {
			_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
			r_strbuf_setf (&op->esil, "1,%s,[1],<<,C,|,%s,=[1],$c7,C,=", addrbuf, addrbuf);
		}
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// ROR
	case 0x6a: // ror a
	case 0x66: // ror $ff
	case 0x76: // ror $ff,x
	case 0x6e: // ror $ffff
	case 0x7e: // ror $ffff,x
		// uses N as temporary to hold C value. but in fact,
		// it is not temporary since in all ROR ops, N will have the value of C
		op->type = R_ANAL_OP_TYPE_ROR;
		if (data[0] == 0x6a) {
			r_strbuf_set (&op->esil, "C,N,=,1,a,&,C,=,1,a,>>,7,N,<<,|,a,=");
		} else {
			_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
			r_strbuf_setf (&op->esil, "C,N,=,1,%s,[1],&,C,=,1,%s,[1],>>,7,N,<<,|,%s,=[1]", addrbuf, addrbuf, addrbuf);
		}
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// INC
	case 0xe6: // inc $ff
	case 0xf6: // inc $ff,x
	case 0xee: // inc $ffff
	case 0xfe: // inc $ffff,x
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
		r_strbuf_setf (&op->esil, "%s,++=[1]", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// DEC
	case 0xc6: // dec $ff
	case 0xd6: // dec $ff,x
	case 0xce: // dec $ffff
	case 0xde: // dec $ffff,x
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x');
		r_strbuf_setf (&op->esil, "%s,--=[1]", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// INX, INY
	case 0xe8: // inx
	case 0xc8: // iny
		op->cycles = 2;
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_inc_reg (op, data[0], "+");
		break;
	// DEX, DEY
	case 0xca: // dex
	case 0x88: // dey
		op->cycles = 2;
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_inc_reg (op, data[0], "-");
		break;
	// CMP
	case 0xc9: // cmp #$ff
	case 0xc5: // cmp $ff
	case 0xd5: // cmp $ff,x
	case 0xcd: // cmp $ffff
	case 0xdd: // cmp $ffff,x
	case 0xd9: // cmp $ffff,y
	case 0xc1: // cmp ($ff,x)
	case 0xd1: // cmp ($ff),y
		op->type = R_ANAL_OP_TYPE_CMP;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0xc9) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,==", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,==", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_BNZ);
		// invert C, since C=1 when A-M >= 0
		r_strbuf_append (&op->esil, ",C,!,C,=");
		break;
	// CPX
	case 0xe0: // cpx #$ff
	case 0xe4: // cpx $ff
	case 0xec: // cpx $ffff
		op->type = R_ANAL_OP_TYPE_CMP;
		_6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0);
		if (data[0] == 0xe0) // immediate mode
			r_strbuf_setf (&op->esil, "%s,x,==", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],x,==", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_BNZ);
		// invert C, since C=1 when A-M >= 0
		r_strbuf_append (&op->esil, ",C,!,C,=");
		break;
	// CPY
	case 0xc0: // cpy #$ff
	case 0xc4: // cpy $ff
	case 0xcc: // cpy $ffff
		op->type = R_ANAL_OP_TYPE_CMP;
		_6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0);
		if (data[0] == 0xc0) // immediate mode
			r_strbuf_setf (&op->esil, "%s,y,==", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],y,==", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_BNZ);
		// invert C, since C=1 when A-M >= 0
		r_strbuf_append (&op->esil, ",C,!,C,=");
		break;
	// BRANCHES
	case 0x10: // bpl $ffff
	case 0x30: // bmi $ffff
	case 0x50: // bvc $ffff
	case 0x70: // bvs $ffff
	case 0x90: // bcc $ffff
	case 0xb0: // bcs $ffff
	case 0xd0: // bne $ffff
	case 0xf0: // beq $ffff
		// FIXME: Add 1 if branch occurs to same page.
		// FIXME: Add 2 if branch occurs to different page
		op->cycles = 2;
		op->failcycles = 3;
		op->type = R_ANAL_OP_TYPE_CJMP;
		if (data[1] <= 127)
			op->jump = addr + data[1] + op->size;
		else	op->jump = addr - (256 - data[1]) + op->size;
		op->fail = addr + op->size;
		// FIXME: add a type of conditional
		// op->cond = R_ANAL_COND_LE;
		_6502_anal_esil_ccall (op, data[0]);
		break;
	// JSR
	case 0x20: // jsr $ffff
		op->cycles = 6;
		op->type = R_ANAL_OP_TYPE_CALL;
		op->jump = data[1] | data[2] << 8;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = 2;
		// JSR pushes the address-1 of the next operation on to the stack before transferring program
		// control to the following address
		// stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
		r_strbuf_setf (&op->esil, "1,pc,-,0xff,sp,+,=[2],0x%04x,pc,=,2,sp,-=", op->jump);
		break;
	// JMP
	case 0x4c: // jmp $ffff
		op->cycles = 3;
		op->type = R_ANAL_OP_TYPE_JMP;
		op->jump = data[1] | data[2] << 8;
		r_strbuf_setf (&op->esil, "0x%04x,pc,=", op->jump);
		break;
	case 0x6c: // jmp ($ffff)
		op->cycles = 5;
		op->type = R_ANAL_OP_TYPE_UJMP;
		// FIXME: how to read memory?
		// op->jump = data[1] | data[2] << 8;
		r_strbuf_setf (&op->esil, "0x%04x,[2],pc,=", data[1] | data[2] << 8);
		break;
	// RTS
	case 0x60: // rts
		op->eob = 1;
		op->type = R_ANAL_OP_TYPE_RET;
		op->cycles = 6;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -2;
		// Operation:  PC from Stack, PC + 1 -> PC
		// stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
		r_strbuf_set (&op->esil, "0x101,sp,+,[2],pc,=,pc,++=,2,sp,+=");
		break;
	// RTI
	case 0x40: // rti
		op->eob = 1;
		op->type = R_ANAL_OP_TYPE_RET;
		op->cycles = 6;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -3;
		// Operation: P from Stack, PC from Stack
		// stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
		r_strbuf_set (&op->esil, "0x101,sp,+,[1],flags,=,0x102,sp,+,[2],pc,=,3,sp,+=");
		break;
	// NOP
	case 0xea: // nop
		op->type = R_ANAL_OP_TYPE_NOP;
		op->cycles = 2;
		break;
	// LDA
	case 0xa9: // lda #$ff
	case 0xa5: // lda $ff
	case 0xb5: // lda $ff,x
	case 0xad: // lda $ffff
	case 0xbd: // lda $ffff,x
	case 0xb9: // lda $ffff,y
	case 0xa1: // lda ($ff,x)
	case 0xb1: // lda ($ff),y
		op->type = R_ANAL_OP_TYPE_LOAD;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		if (data[0] == 0xa9) // immediate mode
			r_strbuf_setf (&op->esil, "%s,a,=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],a,=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// LDX
	case 0xa2: // ldx #$ff
	case 0xa6: // ldx $ff
	case 0xb6: // ldx $ff,y
	case 0xae: // ldx $ffff
	case 0xbe: // ldx $ffff,y
		op->type = R_ANAL_OP_TYPE_LOAD;
		_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'y');
		if (data[0] == 0xa2) // immediate mode
			r_strbuf_setf (&op->esil, "%s,x,=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],x,=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// LDY
	case 0xa0: // ldy #$ff
	case 0xa4: // ldy $ff
	case 0xb4: // ldy $ff,x
	case 0xac: // ldy $ffff
	case 0xbc: // ldy $ffff,x
		op->type = R_ANAL_OP_TYPE_LOAD;
		_6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 'x');
		if (data[0] == 0xa0) // immediate mode
			r_strbuf_setf (&op->esil, "%s,y,=", addrbuf);
		else	r_strbuf_setf (&op->esil, "%s,[1],y,=", addrbuf);
		_6502_anal_update_flags (op, _6502_FLAGS_NZ);
		break;
	// STA
	case 0x85: // sta $ff
	case 0x95: // sta $ff,x
	case 0x8d: // sta $ffff
	case 0x9d: // sta $ffff,x
	case 0x99: // sta $ffff,y
	case 0x81: // sta ($ff,x)
	case 0x91: // sta ($ff),y
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize);
		r_strbuf_setf (&op->esil, "a,%s,=[1]", addrbuf);
		break;
	// STX
	case 0x86: // stx $ff
	case 0x96: // stx $ff,y
	case 0x8e: // stx $ffff
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'y');
		r_strbuf_setf (&op->esil, "x,%s,=[1]", addrbuf);
		break;
	// STY
	case 0x84: // sty $ff
	case 0x94: // sty $ff,x
	case 0x8c: // sty $ffff
		op->type = R_ANAL_OP_TYPE_STORE;
		_6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 'x');
		r_strbuf_setf (&op->esil, "y,%s,=[1]", addrbuf);
		break;
	// PHP/PHA
	case 0x08: // php
	case 0x48: // pha
		op->type = R_ANAL_OP_TYPE_PUSH;
		op->cycles = 3;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = 1;
		_6502_anal_esil_push (op, data[0]);
		break;
	// PLP,PLA
	case 0x28: // plp
	case 0x68: // plp
		op->type = R_ANAL_OP_TYPE_POP;
		op->cycles = 4;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -1;
		_6502_anal_esil_pop (op, data[0]);
		break;
	// TAX,TYA,...
	case 0xaa: // tax
	case 0x8a: // txa
	case 0xa8: // tay
	case 0x98: // tya
		op->type = R_ANAL_OP_TYPE_MOV;
		op->cycles = 2;
		_6502_anal_esil_mov (op, data[0]);
		break;
	case 0x9a: // txs
		op->type = R_ANAL_OP_TYPE_MOV;
		op->cycles = 2;
		op->stackop = R_ANAL_STACK_SET;
		// FIXME: should I get register X a place it here?
		// op->stackptr = get_register_x();
		_6502_anal_esil_mov (op, data[0]);
		break;
	case 0xba: // tsx
		op->type = R_ANAL_OP_TYPE_MOV;
		op->cycles = 2;
		op->stackop = R_ANAL_STACK_GET;
		_6502_anal_esil_mov (op, data[0]);
		break;
	}
	return op->size;
}
Exemple #20
0
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
	int i;
	char str[32][32];
	r_strbuf_init (&op->esil);
	r_strbuf_set (&op->esil, "");
	switch (insn->detail->arm.cc) {
	case ARM_CC_AL:
		// no condition
		break;
	case ARM_CC_EQ:
		r_strbuf_setf (&op->esil, "zf,0,?,");
		break;
	case ARM_CC_NE:
		r_strbuf_setf (&op->esil, "zf,!,0,?,");
		break;
	case ARM_CC_GT:
	case ARM_CC_LE:
		break;
	default:
		break;
	}
	// TODO: PREFIX CONDITIONAL
	switch (insn->id) {
	case ARM_INS_PUSH:
		// TODO: increment stack
	case ARM_INS_STM:
		for (i=1; i<insn->detail->arm.op_count; i++) {
			r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4],",
				REG (i), ARG (0), i*4);
		}
		break;
	case ARM_INS_POP:
		// TODO: decrement stack
	case ARM_INS_LDM:
		for (i=1; i<insn->detail->arm.op_count; i++) {
			r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=",
				ARG (0), i*4, REG (i));
		}
		break;
	case ARM_INS_CMP:
		r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0));
		break;
	case ARM_INS_LSL:
		// suffix 'S' forces conditional flag to be updated
		r_strbuf_appendf (&op->esil, "%s,%s,<<=", ARG(1), ARG(0));
		break;
	case ARM_INS_LSR:
		// suffix 'S' forces conditional flag to be updated
		r_strbuf_appendf (&op->esil, "%s,%s,>>=", ARG(1), ARG(0));
		break;
	case ARM_INS_B:
		r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0));
		break;
	case ARM_INS_BL:
	case ARM_INS_BLX:
		r_strbuf_appendf (&op->esil, "4,pc,+,lr,=,%s,pc,=", ARG(0));
		break;
	case ARM_INS_MOV:
	case ARM_INS_MOVS:
		r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0));
		break;
	case ARM_INS_SSUB16:
	case ARM_INS_SSUB8:
	case ARM_INS_SUB:
		r_strbuf_appendf (&op->esil, "%s,%s,-=", ARG(1), ARG(0));
		break;
	case ARM_INS_SADD16:
	case ARM_INS_SADD8:
	case ARM_INS_ADD:
		if (!strcmp (ARG(0),ARG(1))) {
			r_strbuf_appendf (&op->esil, "%s,%s,+=", ARG(2), ARG(0));
		} else if (!strcmp (ARG(2),"0")) {
			r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), ARG(0));
		} else {
			r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
		}
		break;
	case ARM_INS_STR:
		r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4]",
			REG(0), MEMBASE(1), MEMDISP(1));
		break;
	case ARM_INS_STRB:
		r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[1]",
			REG(0), MEMBASE(1), MEMDISP(1));
		break;
	case ARM_INS_LDR:
		if (MEMDISP(1)<0) {
			if (REGBASE(1) == ARM_REG_PC) {
				r_strbuf_appendf (&op->esil, "8,%s,+,%d,-,[4],%s,=",
						MEMBASE(1), -MEMDISP(1), REG(0));
				switch (a->bits) {
				case 32:
					op->ptr = addr + 8 - MEMDISP(1);
					op->refptr = 4;
					break;
				case 16:
					if ( (addr % 4) == 0 ) {
						op->ptr = addr + 4 - MEMDISP(1);
						op->refptr = 4;
					} else {
						op->ptr = addr + 2 - MEMDISP(1);
						op->refptr = 4;
					}
					break;
				}
			} else {
				r_strbuf_appendf (&op->esil, "%s,%d,-,[4],%s,=",
					MEMBASE(1), -MEMDISP(1), REG(0));
			}
		} else {
			if (REGBASE(1) == ARM_REG_PC) {
				r_strbuf_appendf (&op->esil, "8,%s,+,%d,+,[4],%s,=",
					MEMBASE(1), MEMDISP(1), REG(0));
				if (a->bits==32) {
					op->ptr = addr + 8 + MEMDISP(1);
					op->refptr = 4;
				} else if (a->bits==16) {
					if ( (addr % 4) == 0 ) {
						op->ptr = addr + 4 + MEMDISP(1);
						op->refptr = 4;
					} else {
						op->ptr = addr + 2 + MEMDISP(1);
						op->refptr = 4;
					}
				}
			} else {
				r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=",
					MEMBASE(1), MEMDISP(1), REG(0));
			}
			op->refptr = 4;
		}
		break;
	case ARM_INS_LDRD:
	case ARM_INS_LDRB:
		r_strbuf_appendf (&op->esil, "%s,%d,+,[1],%s,=",
			MEMBASE(1), MEMDISP(1), REG(0));
		break;
	default:
		break;
	}
	return 0;
}