示例#1
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	static int omode = 0;
#if USE_ITER_API
	static
#endif
	cs_insn *insn = NULL;
	int mode = (a->bits==64)? CS_MODE_64:
		(a->bits==32)? CS_MODE_32:
		(a->bits==16)? CS_MODE_16: 0;
	int n, ret;
	int regsz = 4;

	if (handle && mode != omode) {
		cs_close (&handle);
		handle = 0;
	}
	omode = mode;
	if (handle == 0) {
		ret = cs_open (CS_ARCH_X86, mode, &handle);
		if (ret != CS_ERR_OK) {
			handle = 0;
			return 0;
		}
	}

	switch (a->bits) {
	case 64: regsz = 8; break;
	case 16: regsz = 2; break;
	default:
	case 32: regsz = 4; break;
	}
	memset (op, '\0', sizeof (RAnalOp));
	op->cycles = 1; // aprox
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->src[0] = NULL;
	op->src[1] = NULL;
	op->size = 0;
	op->delay = 0;
	r_strbuf_init (&op->esil);
	cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
	// capstone-next
#if USE_ITER_API
	{
		ut64 naddr = addr;
		size_t size = len;
		if (insn == NULL)
			insn = cs_malloc (handle);
		n = cs_disasm_iter (handle, (const uint8_t**)&buf,
			&size, (uint64_t*)&naddr, insn);
	}
#else
	n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
#endif
	struct Getarg gop = {
		.handle = handle,
		.insn = insn,
		.bits = a->bits
	};
	if (n<1) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else {
		int rs = a->bits/8;
		const char *pc = (a->bits==16)?"ip":
			(a->bits==32)?"eip":"rip";
		const char *sp = (a->bits==16)?"sp":
			(a->bits==32)?"esp":"rsp";
		const char *bp = (a->bits==16)?"bp":
			(a->bits==32)?"ebp":"rbp";
		op->size = insn->size;
		op->family = 0;
		op->prefix = 0;
		switch (insn->detail->x86.prefix[0]) {
		case X86_PREFIX_REPNE:
			op->prefix |= R_ANAL_OP_PREFIX_REPNE;
			break;
		case X86_PREFIX_REP:
			op->prefix |= R_ANAL_OP_PREFIX_REP;
			break;
		case X86_PREFIX_LOCK:
			op->prefix |= R_ANAL_OP_PREFIX_LOCK;
			break;
		}
		switch (insn->id) {
		case X86_INS_FNOP:
		case X86_INS_NOP:
		case X86_INS_PAUSE:
			op->type = R_ANAL_OP_TYPE_NOP;
			if (a->decode)
				esilprintf (op, ",");
			break;
		case X86_INS_HLT:
			op->type = R_ANAL_OP_TYPE_TRAP;
			break;
		case X86_INS_FBLD:
		case X86_INS_FBSTP:
		case X86_INS_FCOMPP:
		case X86_INS_FDECSTP:
		case X86_INS_FEMMS:
		case X86_INS_FFREE:
		case X86_INS_FICOM:
		case X86_INS_FICOMP:
		case X86_INS_FINCSTP:
		case X86_INS_FNCLEX:
		case X86_INS_FNINIT:
		case X86_INS_FNSTCW:
		case X86_INS_FNSTSW:
		case X86_INS_FPATAN:
		case X86_INS_FPREM:
		case X86_INS_FPREM1:
		case X86_INS_FPTAN:
#if CS_API_MAJOR >=4
		case X86_INS_FFREEP:
#endif
		case X86_INS_FRNDINT:
		case X86_INS_FRSTOR:
		case X86_INS_FNSAVE:
		case X86_INS_FSCALE:
		case X86_INS_FSETPM:
		case X86_INS_FSINCOS:
		case X86_INS_FNSTENV:
		case X86_INS_FXAM:
		case X86_INS_FXSAVE:
		case X86_INS_FXSAVE64:
		case X86_INS_FXTRACT:
		case X86_INS_FYL2X:
		case X86_INS_FYL2XP1:
		case X86_INS_FISTTP:
		case X86_INS_FSQRT:
		case X86_INS_FXCH:
		case X86_INS_FTST:
		case X86_INS_FUCOMPI:
		case X86_INS_FUCOMI:
		case X86_INS_FUCOMPP:
		case X86_INS_FUCOMP:
		case X86_INS_FUCOM:
			op->type = R_ANAL_OP_TYPE_SUB;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FLDCW:
		case X86_INS_FLDENV:
		case X86_INS_FLDL2E:
		case X86_INS_FLDL2T:
		case X86_INS_FLDLG2:
		case X86_INS_FLDLN2:
		case X86_INS_FLDPI:
		case X86_INS_FLDZ:
		case X86_INS_FLD1:
		case X86_INS_FLD:
			op->type = R_ANAL_OP_TYPE_LOAD;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FIST:
		case X86_INS_FISTP:
		case X86_INS_FST:
		case X86_INS_FSTP:
		case X86_INS_FSTPNCE:
		case X86_INS_FXRSTOR:
		case X86_INS_FXRSTOR64:
			op->type = R_ANAL_OP_TYPE_STORE;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FDIV:
		case X86_INS_FIDIV:
		case X86_INS_FDIVP:
		case X86_INS_FDIVR:
		case X86_INS_FIDIVR:
		case X86_INS_FDIVRP:
		case X86_INS_FSUBR:
		case X86_INS_FISUBR:
		case X86_INS_FSUBRP:
		case X86_INS_FSUB:
		case X86_INS_FISUB:
		case X86_INS_FSUBP:
			op->type = R_ANAL_OP_TYPE_SUB;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FMUL:
		case X86_INS_FIMUL:
		case X86_INS_FMULP:
			op->type = R_ANAL_OP_TYPE_MUL;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_CLI:
		case X86_INS_STI:
			op->type = R_ANAL_OP_TYPE_SWI;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_CLC:
		case X86_INS_STC:
		case X86_INS_CLAC:
		case X86_INS_CLGI:
		case X86_INS_CLTS:
		case X86_INS_CLWB:
		case X86_INS_STAC:
		case X86_INS_STGI:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_CPU;
			break;
		// cmov
		case X86_INS_SETNE:
		case X86_INS_SETNO:
		case X86_INS_SETNP:
		case X86_INS_SETNS:
		case X86_INS_SETO:
		case X86_INS_SETP:
		case X86_INS_SETS:
		case X86_INS_SETL:
		case X86_INS_SETLE:
		case X86_INS_SETB:
		case X86_INS_SETG:
		case X86_INS_SETAE:
		case X86_INS_SETA:
		case X86_INS_SETBE:
		case X86_INS_SETE:
		case X86_INS_SETGE:
			op->type = R_ANAL_OP_TYPE_CMOV;
			op->family = 0;
			if (a->decode) {
				char *dst = getarg (&gop, 0, 0, NULL);
				switch (insn->id) {
				case X86_INS_SETE:  esilprintf (op, "zf,%s,=", dst); break;
				case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break;
				case X86_INS_SETO:  esilprintf (op, "of,%s,=", dst); break;
				case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break;
				case X86_INS_SETP:  esilprintf (op, "pf,%s,=", dst); break;
				case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETS:  esilprintf (op, "sf,%s,=", dst); break;
				case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break;

				case X86_INS_SETB:  esilprintf (op, "cf,%s,=", dst); break;
				case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break;

				/* TODO */
#if 0
SETLE/SETNG
	Sets the byte in the operand to 1 if the Zero Flag is set or the
	Sign Flag is not equal to the Overflow Flag,  otherwise sets the
	operand to 0.
SETBE/SETNA
	Sets the byte in the operand to 1 if the Carry Flag or the Zero
        Flag is set, otherwise sets the operand to 0.
SETL/SETNGE
	Sets the byte in the operand to 1 if the Sign Flag is not equal
        to the Overflow Flag, otherwise sets the operand to 0.

				case X86_INS_SETL:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETG:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETA:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break;
						    break;
#endif
				}
				free (dst);
			}
			break;
		// cmov
		case X86_INS_MOVSS:
		case X86_INS_CMOVA:
		case X86_INS_CMOVAE:
		case X86_INS_CMOVB:
		case X86_INS_CMOVBE:
		case X86_INS_FCMOVBE:
		case X86_INS_FCMOVB:
		case X86_INS_CMOVE:
		case X86_INS_FCMOVE:
		case X86_INS_CMOVG:
		case X86_INS_CMOVGE:
		case X86_INS_CMOVL:
		case X86_INS_CMOVLE:
		case X86_INS_FCMOVNBE:
		case X86_INS_FCMOVNB:
		case X86_INS_CMOVNE:
		case X86_INS_FCMOVNE:
		case X86_INS_CMOVNO:
		case X86_INS_CMOVNP:
		case X86_INS_FCMOVNU:
		case X86_INS_CMOVNS:
		case X86_INS_CMOVO:
		case X86_INS_CMOVP:
		case X86_INS_FCMOVU:
		case X86_INS_CMOVS:
		// mov
		case X86_INS_MOV:
		case X86_INS_MOVAPS:
		case X86_INS_MOVAPD:
		case X86_INS_MOVZX:
		case X86_INS_MOVUPS:
		case X86_INS_MOVABS:
		case X86_INS_MOVHPD:
		case X86_INS_MOVHPS:
		case X86_INS_MOVLPD:
		case X86_INS_MOVLPS:
		case X86_INS_MOVBE:
		case X86_INS_MOVSB:
		case X86_INS_MOVSD:
		case X86_INS_MOVSQ:
		case X86_INS_MOVSX:
		case X86_INS_MOVSXD:
		case X86_INS_MOVSW:
		case X86_INS_MOVD:
		case X86_INS_MOVQ:
		case X86_INS_MOVDQ2Q:
			{
			op->type = R_ANAL_OP_TYPE_MOV;
			op->ptr = UT64_MAX;
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->ptr = UT64_MAX;
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				} else {
					op->ptr = UT64_MAX;
				}
				if (a->decode) {
					if (op->prefix & R_ANAL_OP_PREFIX_REP) {
						int width = INSOP(0).size;
						const char *src = cs_reg_name(handle, INSOP(1).mem.base);
						const char *dst = cs_reg_name(handle, INSOP(0).mem.base);
						const char *counter = (a->bits==16)?"cx":
							(a->bits==32)?"ecx":"rcx";
						esilprintf (op, "%s,!,?{,BREAK,},%s,DUP,%s,DUP,"\
								"%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\
								"df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \
								"?{,8,GOTO,},%s,=,%s,=",
								counter, src, dst, src, width, dst,
								width, width, src, width, dst, width, src,
								width, dst, counter, counter, dst, src);
					} else {
						char *src = getarg (&gop, 1, 0, NULL);
						char *dst = getarg (&gop, 0, 1, NULL);
						esilprintf (op, "%s,%s", src, dst);
						free (src);
						free (dst);
					}
				}
				break;
			default:
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op, "%s,%s,=", src, dst);
					free (src);
					free (dst);
				}
				break;
			}
			if (op->refptr<1 || op->ptr == UT64_MAX) {
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					op->refptr = INSOP(1).size;
					if (INSOP(1).mem.base == X86_REG_RIP) {
						op->ptr += addr + insn->size;
					} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
						op->stackop = R_ANAL_STACK_GET;
						op->stackptr = regsz;
					}
					break;
				case X86_OP_IMM:
					if (INSOP(1).imm > 10)
						op->ptr = INSOP(1).imm;
					break;
				default:
					break;
				}
			}
			}
			break;
		case X86_INS_SHL:
		case X86_INS_SHLD:
		case X86_INS_SHLX:
			op->type = R_ANAL_OP_TYPE_SHL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "<<");
				esilprintf (op, "%s,%s,$z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAR:
		case X86_INS_SARX:
			op->type = R_ANAL_OP_TYPE_SAR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, ">>");
				esilprintf (op, "%s,%s,$z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAL:
			op->type = R_ANAL_OP_TYPE_SAL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "<<");
				esilprintf (op, "%s,%s,$z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SALC:
			op->type = R_ANAL_OP_TYPE_SAL;
			if (a->decode) {
				esilprintf (op, "$z,DUP,zf,=,al,=");
			}
			break;
		case X86_INS_SHR:
		case X86_INS_SHRD:
		case X86_INS_SHRX:
			op->type = R_ANAL_OP_TYPE_SHR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,>>=,$z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_CMP:
		case X86_INS_CMPPD:
		case X86_INS_CMPPS:
		case X86_INS_CMPSW:
		case X86_INS_CMPSD:
		case X86_INS_CMPSQ:
		case X86_INS_CMPSB:
		case X86_INS_CMPSS:
		case X86_INS_TEST:
			if (insn->id == X86_INS_TEST) {
				op->type = R_ANAL_OP_TYPE_ACMP;					//compare via and
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=",
						src, dst);
					free (src);
					free (dst);
				}
			} else {
				op->type = R_ANAL_OP_TYPE_CMP;
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op,  "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=",
						src, dst, (INSOP(0).size*8));
					free (src);
					free (dst);
				}
			}
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				}
				op->ptr = INSOP(1).imm;
				break;
			default:
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					op->refptr = INSOP(1).size;
					if (INSOP(1).mem.base == X86_REG_RIP) {
						op->ptr += addr + insn->size;
					} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
						op->stackop = R_ANAL_STACK_SET;
						op->stackptr = regsz;
					}
					break;
				case X86_OP_IMM:
					op->ptr = INSOP(1).imm;
					break;
				default:
					break;
				}
				break;
			}
			break;
		case X86_INS_LEA:
			op->type = R_ANAL_OP_TYPE_LEA;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				char *dst = getarg (&gop, 1, 2, NULL);
				esilprintf (op, "%s,%s,=", dst, src);
				free (src);
				free (dst);
			}
			switch (INSOP(1).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(1).mem.disp;
				op->refptr = INSOP(1).size;
				switch (INSOP(1).mem.base) {
				case X86_REG_RIP:
					op->ptr += addr + op->size;
					break;
				case X86_REG_RBP:
				case X86_REG_EBP:
					op->stackop = R_ANAL_STACK_GET;
					op->stackptr = regsz;
					break;
				default:
					/* unhandled */
					break;
				}
				break;
			case X86_OP_IMM:
				if (INSOP(1).imm > 10)
					op->ptr = INSOP(1).imm;
				break;
			default:
				break;
			}
			break;
		case X86_INS_ENTER:
		case X86_INS_PUSH:
		case X86_INS_PUSHAW:
		case X86_INS_PUSHAL:
		case X86_INS_PUSHF:
			{
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op,  "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs);
				free (dst);
			}
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->ptr = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_PUSH;
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UPUSH;
				break;
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = regsz;
			break;
		case X86_INS_LEAVE:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=",
					bp, sp, sp, rs, bp, rs, sp);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_POP:
		case X86_INS_POPF:
		case X86_INS_POPAW:
		case X86_INS_POPAL:
		case X86_INS_POPCNT:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op,
					"%s,[%d],%s,=,%d,%s,+=",
					sp, rs, dst, rs, sp);
				free (dst);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_RET:
		case X86_INS_RETF:
		case X86_INS_RETFQ:
		case X86_INS_IRET:
		case X86_INS_IRETD:
		case X86_INS_IRETQ:
		case X86_INS_SYSRET:
			op->type = R_ANAL_OP_TYPE_RET;
			if (a->decode)
				esilprintf (op, "%s,[%d],%s,=,%d,%s,+=",
					sp, rs, pc, rs, sp);
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_INT3:
			if (a->decode)
				esilprintf (op, "3,$");
			op->type = R_ANAL_OP_TYPE_TRAP; // TRAP
			break;
		case X86_INS_INT1:
			if (a->decode)
				esilprintf (op, "1,$");
			op->type = R_ANAL_OP_TYPE_SWI; // TRAP
			break;
		case X86_INS_INT:
			if (a->decode)
				esilprintf (op, "%d,$",
					R_ABS((int)INSOP(0).imm));
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
		case X86_INS_SYSCALL:
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
		case X86_INS_INTO:
		case X86_INS_VMCALL:
		case X86_INS_VMMCALL:
			op->type = R_ANAL_OP_TYPE_TRAP;
			if (a->decode)
				esilprintf (op, "%d,$", (int)INSOP(0).imm);
			break;
		case X86_INS_JL:
		case X86_INS_JLE:
		case X86_INS_JA:
		case X86_INS_JAE:
		case X86_INS_JB:
		case X86_INS_JBE:
		case X86_INS_JCXZ:
		case X86_INS_JECXZ:
		case X86_INS_JRCXZ:
		case X86_INS_JO:
		case X86_INS_JNO:
		case X86_INS_JS:
		case X86_INS_JNS:
		case X86_INS_JP:
		case X86_INS_JNP:
		case X86_INS_JE:
		case X86_INS_JNE:
		case X86_INS_JG:
		case X86_INS_JGE:
		case X86_INS_LOOP:
		case X86_INS_LOOPE:
		case X86_INS_LOOPNE:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = INSOP(0).imm;
			op->fail = addr+op->size;
			const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx";
			if (a->decode) {
				char *dst = getarg (&gop, 0, 2, NULL);
				switch (insn->id) {
				case X86_INS_JL:
					esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JLE:
					esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JA:
					esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc);
					break;
				case X86_INS_JAE:
					esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JB:
					esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JO:
					esilprintf (op, "of,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNO:
					esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JE:
					esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JGE:
					esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNE:
					esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JG:
					esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JS:
					esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNS:
					esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JP:
					esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNP:
					esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JBE:
					esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JCXZ:
					esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JECXZ:
					esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JRCXZ:
					esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_LOOP:
					esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc);
					break;
				case X86_INS_LOOPE:
					esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}",
						cnt, cnt, dst, pc);
					break;
				case X86_INS_LOOPNE:
					esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}",
						cnt, cnt, dst, pc);
					break;
				}
				free (dst);
			}
			break;
		case X86_INS_CALL:
		case X86_INS_LCALL:
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->type = R_ANAL_OP_TYPE_CALL;
				// TODO: what if UCALL?
				// TODO: use imm_size
				op->jump = INSOP(0).imm;
				op->fail = addr+op->size;
				break;
			case X86_OP_MEM:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				if (INSOP(0).mem.base == 0) {
					op->ptr = INSOP(0).mem.disp;
				}
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				break;
			}
			if (a->decode) {
				char* arg = getarg (&gop, 0, 0, NULL);
				esilprintf (op,
						"%s,"
						"%d,%s,-=,%s,"
						"=[],"
						"%s,%s,=",
						pc, rs, sp, sp, arg, pc);
				free (arg);
			}
			break;
		case X86_INS_JMP:
		case X86_INS_LJMP:
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,=", src, pc);
				free (src);
			}
			// TODO: what if UJMP?
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->jump = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_JMP;
				if (a->decode) {
					ut64 dst = INSOP(0).imm;
					esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
				}
				break;
			case X86_OP_MEM:
				op->type = R_ANAL_OP_TYPE_UJMP;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr = INSOP(0).mem.disp;
					op->ptr += addr + insn->size;
					op->refptr = 8;
				} else {
					cs_x86_op in = INSOP(0);
					if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) {
						op->type = R_ANAL_OP_TYPE_UJMP;
						op->ptr = in.mem.disp;
						if (a->decode) {
							esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc);
						}
					}
				}
				break;
			case X86_OP_REG:
			case X86_OP_FP:
			default: // other?
				op->type = R_ANAL_OP_TYPE_UJMP;
				break;
			}
			break;
		case X86_INS_IN:
		case X86_INS_INSW:
		case X86_INS_INSD:
		case X86_INS_INSB:
		case X86_INS_OUT:
		case X86_INS_OUTSB:
		case X86_INS_OUTSD:
		case X86_INS_OUTSW:
			op->type = R_ANAL_OP_TYPE_IO;
			break;
		case X86_INS_VXORPD:
		case X86_INS_VXORPS:
		case X86_INS_VPXORD:
		case X86_INS_VPXORQ:
		case X86_INS_VPXOR:
		case X86_INS_XORPS:
		case X86_INS_KXORW:
		case X86_INS_PXOR:
		case X86_INS_XOR:
			op->type = R_ANAL_OP_TYPE_XOR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "^");
				esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,0,cf,=,0,of,=,$s,sf,=",
					src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_OR:
			op->type = R_ANAL_OP_TYPE_OR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,|=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_INC:
			op->type = R_ANAL_OP_TYPE_ADD;
			op->val = 1;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,++=", src);
				free (src);
			}
			break;
		case X86_INS_DEC:
			op->type = R_ANAL_OP_TYPE_SUB;
			op->val = 1;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,--=", src);
				free (src);
			}
			break;
		case X86_INS_SUB:
		case X86_INS_PSUBB:
		case X86_INS_PSUBW:
		case X86_INS_PSUBD:
		case X86_INS_PSUBQ:
		case X86_INS_PSUBSB:
		case X86_INS_PSUBSW:
		case X86_INS_PSUBUSB:
		case X86_INS_PSUBUSW:
			op->type = R_ANAL_OP_TYPE_SUB;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "-");
				esilprintf (op, "%s,%s,$c,cf,=,$z,zf,=,$s,sf,=,$o,of,=",
					src, dst); // TODO: update flags
				free (src);
				free (dst);
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = INSOP(1).imm;
				}
			}
			break;
		case X86_INS_LIDT:
			op->type = R_ANAL_OP_TYPE_LOAD;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_SIDT:
			op->type = R_ANAL_OP_TYPE_STORE;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_RDRAND:
		case X86_INS_RDSEED:
		case X86_INS_RDMSR:
		case X86_INS_RDPMC:
		case X86_INS_RDTSC:
		case X86_INS_RDTSCP:
		case X86_INS_CRC32:
		case X86_INS_SHA1MSG1:
		case X86_INS_SHA1MSG2:
		case X86_INS_SHA1NEXTE:
		case X86_INS_SHA1RNDS4:
		case X86_INS_SHA256MSG1:
		case X86_INS_SHA256MSG2:
		case X86_INS_SHA256RNDS2:
		case X86_INS_AESDECLAST:
		case X86_INS_AESDEC:
		case X86_INS_AESENCLAST:
		case X86_INS_AESENC:
		case X86_INS_AESIMC:
		case X86_INS_AESKEYGENASSIST:
			// AES instructions
			op->family = R_ANAL_OP_FAMILY_CRYPTO;
			op->type = R_ANAL_OP_TYPE_MOV; // XXX
			break;
		case X86_INS_AND:
		case X86_INS_ANDN:
		case X86_INS_ANDPD:
		case X86_INS_ANDPS:
		case X86_INS_ANDNPD:
		case X86_INS_ANDNPS:
			op->type = R_ANAL_OP_TYPE_AND;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "&");
				// TODO: update of = cf = 0
				// TODO: update sf, zf and pf
				// TODO: af is undefined
				esilprintf (op, "0,of,=,0,cf,=," // set carry and overflow flags
					"%s,%s," // set reg value
					"$z,zf,=,"  // update zero flag
					"$s,sf,=,"  // update sign flag
					"$o,pf,=",  // update parity flag
					// TODO: add sign and parity flags here
					src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_DIV:
		case X86_INS_IDIV:
			op->type = R_ANAL_OP_TYPE_DIV;
			if (a->decode) {
				int width = INSOP(0).size;
				char *dst = getarg (&gop, 0, 0, NULL);
				const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax";
				const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx";
				// TODO update flags & handle signedness
				esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=",
					dst, r_ax, r_dx, dst, r_ax, r_ax);
				free (dst);
			}
			break;
		case X86_INS_MUL:
		case X86_INS_MULX:
		case X86_INS_MULPD:
		case X86_INS_MULPS:
		case X86_INS_MULSD:
		case X86_INS_MULSS:
			op->type = R_ANAL_OP_TYPE_MUL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "*");
				if (!src && dst) {
					switch (dst[0]) {
					case 'r':
						src = strdup ("rax");
						break;
					case 'e':
						src = strdup ("eax");
						break;
					default:
						src = strdup ("al");
						break;
					}
				}
				esilprintf (op, "%s,%s", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_PACKSSDW:
		case X86_INS_PACKSSWB:
		case X86_INS_PACKUSWB:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		case X86_INS_PADDB:
		case X86_INS_PADDD:
		case X86_INS_PADDW:
		case X86_INS_PADDSB:
		case X86_INS_PADDSW:
		case X86_INS_PADDUSB:
		case X86_INS_PADDUSW:
			op->type = R_ANAL_OP_TYPE_ADD;
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		case X86_INS_FADD:
		case X86_INS_FADDP:
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case X86_INS_ADD:
		case X86_INS_ADDPS:
		case X86_INS_ADDSD:
		case X86_INS_ADDSS:
		case X86_INS_ADDSUBPD:
		case X86_INS_ADDSUBPS:
		case X86_INS_ADDPD:
		case X86_INS_XADD:
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				if (INSOP(0).type == X86_OP_MEM) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *src2 = getarg (&gop, 0, 0, NULL);
					char *dst = getarg (&gop, 0, 1, NULL);
					// TODO: update flags
					esilprintf (op, "%s,%s,+,%s", src, src2, dst);
					free (src);
					free (src2);
					free (dst);
				} else {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 1, "+");
					esilprintf (op, "%s,%s", src, dst);		// TODO: update flags
					free (src);
					free (dst);
				}
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = -INSOP(1).imm;
				}
			}
			break;
			/* Direction flag */
		case X86_INS_CLD:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_CPU;
			if (a->decode)
				esilprintf (op, "0,df,=");
			break;
		case X86_INS_STD:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_CPU;
			if (a->decode)
				esilprintf (op, "1,df,=");
			break;
		}
		switch (insn->id) {
		case X86_INS_MOVAPS: //cvtss2sd
		case X86_INS_ADDSD: //cvtss2sd
		case X86_INS_SUBSD: //cvtss2sd
		case X86_INS_MULSD: //cvtss2sd
		case X86_INS_CVTSS2SD: //cvtss2sd
		case X86_INS_MOVSS:
		case X86_INS_MOVSD:
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		}
	}
//#if X86_GRP_PRIVILEGE>0
	if (insn) {
#if HAVE_CSGRP_PRIVILEGE
		if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE))
			op->family = R_ANAL_OP_FAMILY_PRIV;
#endif
#if !USE_ITER_API
		cs_free (insn, n);
#endif
	}
	//cs_close (&handle);
	return op->size;
}
示例#2
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	static csh handle = 0;
	static int omode = -1;
	int n, ret;
	cs_insn *insn;
	int mode = (a->bits==64)? CS_MODE_64: (a->bits==32)? CS_MODE_32: 0;
	mode |= CS_MODE_BIG_ENDIAN;
	if (mode != omode) {
		cs_close (&handle);
		handle = 0;
		omode = mode;
	}
	if (handle == 0) {
		ret = cs_open (CS_ARCH_PPC, mode, &handle);
		if (ret != CS_ERR_OK) {
			return -1;
		}
		cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
	}
	op->delay = 0;
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->size = 4;
	
	// capstone-next
	n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
	if (n<1) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else {
		struct Getarg gop = {
			.handle = handle,
			.insn = insn,
			.bits = a->bits
		};
		op->size = insn->size;
		switch (insn->id) {
		case PPC_INS_MFLR:
			op->type = R_ANAL_OP_TYPE_PUSH;
			break;
		case PPC_INS_MTLR:
			op->type = R_ANAL_OP_TYPE_POP;
			break;
		case PPC_INS_MR:
		case PPC_INS_LI:
		case PPC_INS_LIS:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s,=", ARG(1), ARG(0)); break;
			break;
		case PPC_INS_RLWINM:
			op->type = R_ANAL_OP_TYPE_ROL;
			break;
		case PPC_INS_SC:
			op->type = R_ANAL_OP_TYPE_SWI;
			esilprintf (op, "0,$");
			break;
		case PPC_INS_NOP:
			op->type = R_ANAL_OP_TYPE_NOP;
			esilprintf (op, ",");
			break;
		case PPC_INS_STW:
		case PPC_INS_STWU:
		case PPC_INS_STWUX:
		case PPC_INS_STWX:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG(0), ARG2(1, "=[4]"));
			break;
		case PPC_INS_STB:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s", ARG(0), ARG2(1, "=[1]"));
			break;
		case PPC_INS_STH:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s", ARG(0), ARG2(1, "=[2]"));
			break;
		case PPC_INS_STWBRX:
		case PPC_INS_STWCX:
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case PPC_INS_LA:
		case PPC_INS_LBZ:
		case PPC_INS_LBZU:
		case PPC_INS_LBZUX:
		case PPC_INS_LBZX:
		case PPC_INS_LD:
		case PPC_INS_LDARX:
		case PPC_INS_LDBRX:
		case PPC_INS_LDU:
		case PPC_INS_LDUX:
		case PPC_INS_LDX:
		case PPC_INS_LFD:
		case PPC_INS_LFDU:
		case PPC_INS_LFDUX:
		case PPC_INS_LFDX:
		case PPC_INS_LFIWAX:
		case PPC_INS_LFIWZX:
		case PPC_INS_LFS:
		case PPC_INS_LFSU:
		case PPC_INS_LFSUX:
		case PPC_INS_LFSX:
		case PPC_INS_LHA:
		case PPC_INS_LHAU:
		case PPC_INS_LHAUX:
		case PPC_INS_LHAX:
		case PPC_INS_LHBRX:
		case PPC_INS_LHZ:
		case PPC_INS_LHZU:
		case PPC_INS_LWA:
		case PPC_INS_LWARX:
		case PPC_INS_LWAUX:
		case PPC_INS_LWAX:
		case PPC_INS_LWBRX:
		case PPC_INS_LWZ:
		case PPC_INS_LWZU:
		case PPC_INS_LWZUX:
		case PPC_INS_LWZX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,[4],%s,=", ARG(1), ARG(0));
			break;
		case PPC_INS_SLW:
		case PPC_INS_SLWI:
			op->type = R_ANAL_OP_TYPE_SHL;
			esilprintf (op, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		case PPC_INS_SRW:
		case PPC_INS_SRWI:
			op->type = R_ANAL_OP_TYPE_SHR;
			esilprintf (op, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		case PPC_INS_CMPW:
		case PPC_INS_CMPWI:
		case PPC_INS_CMPLWI:
			op->type = R_ANAL_OP_TYPE_CMP;
			esilprintf (op, "%s,%s,==", ARG(1), ARG(0));
			break;
		case PPC_INS_MULLI:
		case PPC_INS_MULLW:
			op->type = R_ANAL_OP_TYPE_MUL;
			esilprintf (op, "%s,%s,*,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		case PPC_INS_SUB:
		case PPC_INS_SUBC:
		case PPC_INS_SUBFIC:
		case PPC_INS_SUBFZE:
			op->type = R_ANAL_OP_TYPE_SUB;
			esilprintf (op, "%s,%s,-,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		case PPC_INS_ADD:
		case PPC_INS_ADDI:
		case PPC_INS_ADDC:
		case PPC_INS_ADDE:
		case PPC_INS_ADDIC:
		case PPC_INS_ADDIS:
		case PPC_INS_ADDME:
		case PPC_INS_ADDZE:
			op->type = R_ANAL_OP_TYPE_ADD;
			esilprintf (op, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		case PPC_INS_MTSPR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s,=", ARG(1), ARG(0));
			break;
		case PPC_INS_BCTR: // switch table here
			op->type = R_ANAL_OP_TYPE_UJMP;
			esilprintf (op, "ctr,pc,=");
			break;
		case PPC_INS_BC:
			op->type = R_ANAL_OP_TYPE_UJMP;
			esilprintf (op, "%s,pc,=", ARG(0));
			break;
		case PPC_INS_B:
		case PPC_INS_BA:
			op->type = R_ANAL_OP_TYPE_JMP;
			op->jump = (ut64)(ut32)insn->detail->ppc.operands[0].imm;
			switch (insn->detail->ppc.operands[0].type) {
			case PPC_OP_CRX:
				op->type = R_ANAL_OP_TYPE_CJMP;
				break;
			case PPC_OP_REG:
				op->type = R_ANAL_OP_TYPE_CJMP;
				op->jump = (ut64)(ut32)insn->detail->ppc.operands[1].imm;
				op->fail = addr+4;
				//op->type = R_ANAL_OP_TYPE_UJMP;
			default:
				break;
			}
			break;
		case PPC_INS_NOR:
			op->type = R_ANAL_OP_TYPE_NOR;
			//esilprintf (op, "%s,%s,^,%s,=", ARG(1), ARG(2), ARG(0));
			break;
		case PPC_INS_XOR:
		case PPC_INS_XORI:
		case PPC_INS_XORIS:
			op->type = R_ANAL_OP_TYPE_XOR;
			esilprintf (op, "%s,%s,^,%s,=", ARG(1), ARG(2), ARG(0));
			break;
		case PPC_INS_DIVD:
		case PPC_INS_DIVDU:
		case PPC_INS_DIVW:
		case PPC_INS_DIVWU:
			op->type = R_ANAL_OP_TYPE_DIV;
			break;
		case PPC_INS_BL:
		case PPC_INS_BLA:
			op->type = R_ANAL_OP_TYPE_CALL;
			op->jump = (ut64)(ut32)insn->detail->ppc.operands[0].imm;
			op->fail = addr+4;
			esilprintf (op, "pc,lr,=,%s,pc,=", ARG(0));
			break;
		case PPC_INS_BLR:
		case PPC_INS_BLRL:
			op->type = R_ANAL_OP_TYPE_RET;
			esilprintf (op, "lr,pc,=");
			break;
		case PPC_INS_AND:
		case PPC_INS_NAND:
		case PPC_INS_ANDI:
		case PPC_INS_ANDIS:
			op->type = R_ANAL_OP_TYPE_AND;
			break;
		case PPC_INS_OR:
		case PPC_INS_ORC:
		case PPC_INS_ORI:
		case PPC_INS_ORIS:
			op->type = R_ANAL_OP_TYPE_OR;
			esilprintf (op, "%s,%s,|,%s,=", ARG(2), ARG(1), ARG(0));
			break;
		}
		cs_free (insn, n);
		//cs_close (&handle);
	}
	return op->size;
}

RAnalPlugin r_anal_plugin_ppc_cs = {
	.name = "ppc",
	.desc = "Capstone PowerPC analysis",
	.license = "BSD",
	.arch = R_SYS_ARCH_PPC,
	.bits = 32|64,
	.op = &analop,
	.set_reg_profile = &set_reg_profile,
};

#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
	.type = R_LIB_TYPE_ANAL,
	.data = &r_anal_plugin_ppc_cs,
	.version = R2_VERSION
};
示例#3
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	static int omode = 0;
#if USE_ITER_API
	static
#endif
	cs_insn *insn = NULL;
	int mode = (a->bits==64)? CS_MODE_64:
		(a->bits==32)? CS_MODE_32:
		(a->bits==16)? CS_MODE_16: 0;
	int n, ret;
	int regsz = 4;

	if (handle && mode != omode) {
		cs_close (&handle);
		handle = 0;
	}
	omode = mode;
	if (handle == 0) {
		ret = cs_open (CS_ARCH_X86, mode, &handle);
		if (ret != CS_ERR_OK) {
			handle = 0;
			return 0;
		}
	}
#if 0
	if (len>3 && !memcmp (buf, "\xff\xff\xff\xff", 4))
		return 0;
#endif
	switch (a->bits) {
	case 64: regsz = 8; break;
	case 16: regsz = 2; break;
	default: regsz = 4; break; // 32
	}
	memset (op, '\0', sizeof (RAnalOp));
	op->cycles = 1; // aprox
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->src[0] = NULL;
	op->src[1] = NULL;
	op->size = 0;
	op->delay = 0;
	r_strbuf_init (&op->esil);
	cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
	// capstone-next
#if USE_ITER_API
	{
		ut64 naddr = addr;
		size_t size = len;
		if (insn == NULL)
			insn = cs_malloc (handle);
		n = cs_disasm_iter (handle, (const uint8_t**)&buf,
			&size, (uint64_t*)&naddr, insn);
	}
#else
	n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
#endif
	struct Getarg gop = {
		.handle = handle,
		.insn = insn,
		.bits = a->bits
	};
	if (n<1) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else {
		int rs = a->bits/8;
		const char *pc = (a->bits==16)?"ip":
			(a->bits==32)?"eip":"rip";
		const char *sp = (a->bits==16)?"sp":
			(a->bits==32)?"esp":"rsp";
		const char *bp = (a->bits==16)?"bp":
			(a->bits==32)?"ebp":"rbp";
		op->size = insn->size;
		op->family = R_ANAL_OP_FAMILY_CPU; // almost everything is CPU
		op->prefix = 0;
		switch (insn->detail->x86.prefix[0]) {
		case X86_PREFIX_REPNE:
			op->prefix |= R_ANAL_OP_PREFIX_REPNE;
			break;
		case X86_PREFIX_REP:
			op->prefix |= R_ANAL_OP_PREFIX_REP;
			break;
		case X86_PREFIX_LOCK:
			op->prefix |= R_ANAL_OP_PREFIX_LOCK;
			break;
		}
		switch (insn->id) {
		case X86_INS_FNOP:
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* fallthru */
		case X86_INS_NOP:
		case X86_INS_PAUSE:
			op->type = R_ANAL_OP_TYPE_NOP;
			if (a->decode)
				esilprintf (op, ",");
			break;
		case X86_INS_HLT:
			op->type = R_ANAL_OP_TYPE_TRAP;
			break;
		case X86_INS_FBLD:
		case X86_INS_FBSTP:
		case X86_INS_FCOMPP:
		case X86_INS_FDECSTP:
		case X86_INS_FEMMS:
		case X86_INS_FFREE:
		case X86_INS_FICOM:
		case X86_INS_FICOMP:
		case X86_INS_FINCSTP:
		case X86_INS_FNCLEX:
		case X86_INS_FNINIT:
		case X86_INS_FNSTCW:
		case X86_INS_FNSTSW:
		case X86_INS_FPATAN:
		case X86_INS_FPREM:
		case X86_INS_FPREM1:
		case X86_INS_FPTAN:
#if CS_API_MAJOR >=4
		case X86_INS_FFREEP:
#endif
		case X86_INS_FRNDINT:
		case X86_INS_FRSTOR:
		case X86_INS_FNSAVE:
		case X86_INS_FSCALE:
		case X86_INS_FSETPM:
		case X86_INS_FSINCOS:
		case X86_INS_FNSTENV:
		case X86_INS_FXAM:
		case X86_INS_FXSAVE:
		case X86_INS_FXSAVE64:
		case X86_INS_FXTRACT:
		case X86_INS_FYL2X:
		case X86_INS_FYL2XP1:
		case X86_INS_FISTTP:
		case X86_INS_FSQRT:
		case X86_INS_FXCH:
			op->family = R_ANAL_OP_FAMILY_FPU;
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case X86_INS_FTST:
		case X86_INS_FUCOMPI:
		case X86_INS_FUCOMI:
		case X86_INS_FUCOMPP:
		case X86_INS_FUCOMP:
		case X86_INS_FUCOM:
			op->family = R_ANAL_OP_FAMILY_FPU;
			op->type = R_ANAL_OP_TYPE_CMP;
			break;
		case X86_INS_FABS:
			op->type = R_ANAL_OP_TYPE_ABS;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FLDCW:
		case X86_INS_FLDENV:
		case X86_INS_FLDL2E:
		case X86_INS_FLDL2T:
		case X86_INS_FLDLG2:
		case X86_INS_FLDLN2:
		case X86_INS_FLDPI:
		case X86_INS_FLDZ:
		case X86_INS_FLD1:
		case X86_INS_FLD:
			op->type = R_ANAL_OP_TYPE_LOAD;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FIST:
		case X86_INS_FISTP:
		case X86_INS_FST:
		case X86_INS_FSTP:
		case X86_INS_FSTPNCE:
		case X86_INS_FXRSTOR:
		case X86_INS_FXRSTOR64:
			op->type = R_ANAL_OP_TYPE_STORE;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FDIV:
		case X86_INS_FIDIV:
		case X86_INS_FDIVP:
		case X86_INS_FDIVR:
		case X86_INS_FIDIVR:
		case X86_INS_FDIVRP:
			op->type = R_ANAL_OP_TYPE_DIV;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FSUBR:
		case X86_INS_FISUBR:
		case X86_INS_FSUBRP:
		case X86_INS_FSUB:
		case X86_INS_FISUB:
		case X86_INS_FSUBP:
			op->type = R_ANAL_OP_TYPE_SUB;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_FMUL:
		case X86_INS_FIMUL:
		case X86_INS_FMULP:
			op->type = R_ANAL_OP_TYPE_MUL;
			op->family = R_ANAL_OP_FAMILY_FPU;
			break;
		case X86_INS_CLI:
		case X86_INS_STI:
			op->type = R_ANAL_OP_TYPE_SWI;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_CLC:
		case X86_INS_STC:
		case X86_INS_CLAC:
		case X86_INS_CLGI:
		case X86_INS_CLTS:
#if CS_API_MAJOR >= 4
		case X86_INS_CLWB:
#endif
		case X86_INS_STAC:
		case X86_INS_STGI:
			op->type = R_ANAL_OP_TYPE_MOV;
			break;
		// cmov
		case X86_INS_SETNE:
		case X86_INS_SETNO:
		case X86_INS_SETNP:
		case X86_INS_SETNS:
		case X86_INS_SETO:
		case X86_INS_SETP:
		case X86_INS_SETS:
		case X86_INS_SETL:
		case X86_INS_SETLE:
		case X86_INS_SETB:
		case X86_INS_SETG:
		case X86_INS_SETAE:
		case X86_INS_SETA:
		case X86_INS_SETBE:
		case X86_INS_SETE:
		case X86_INS_SETGE:
			op->type = R_ANAL_OP_TYPE_CMOV;
			op->family = 0;
			if (a->decode) {
				char *dst = getarg (&gop, 0, 0, NULL);
				switch (insn->id) {
				case X86_INS_SETE:  esilprintf (op, "zf,%s,=", dst); break;
				case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break;
				case X86_INS_SETO:  esilprintf (op, "of,%s,=", dst); break;
				case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break;
				case X86_INS_SETP:  esilprintf (op, "pf,%s,=", dst); break;
				case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETS:  esilprintf (op, "sf,%s,=", dst); break;
				case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break;

				case X86_INS_SETB:  esilprintf (op, "cf,%s,=", dst); break;
				case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break;

				/* TODO */
#if 0
SETLE/SETNG
	Sets the byte in the operand to 1 if the Zero Flag is set or the
	Sign Flag is not equal to the Overflow Flag,  otherwise sets the
	operand to 0.
SETBE/SETNA
	Sets the byte in the operand to 1 if the Carry Flag or the Zero
        Flag is set, otherwise sets the operand to 0.
SETL/SETNGE
	Sets the byte in the operand to 1 if the Sign Flag is not equal
        to the Overflow Flag, otherwise sets the operand to 0.

				case X86_INS_SETL:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETG:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETA:  esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break;
				case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break;
						    break;
#endif
				}
				free (dst);
			}
			break;
		// cmov
		case X86_INS_FCMOVBE:
		case X86_INS_FCMOVB:
		case X86_INS_FCMOVNBE:
		case X86_INS_FCMOVNB:
		case X86_INS_FCMOVE:
		case X86_INS_FCMOVNE:
		case X86_INS_FCMOVNU:
		case X86_INS_FCMOVU:
			op->family = R_ANAL_OP_FAMILY_FPU;
			op->type = R_ANAL_OP_TYPE_MOV;
			break;
		case X86_INS_CMOVA:
		case X86_INS_CMOVAE:
		case X86_INS_CMOVB:
		case X86_INS_CMOVBE:
		case X86_INS_CMOVE:
		case X86_INS_CMOVG:
		case X86_INS_CMOVGE:
		case X86_INS_CMOVL:
		case X86_INS_CMOVLE:
		case X86_INS_CMOVNE:
		case X86_INS_CMOVNO:
		case X86_INS_CMOVNP:
		case X86_INS_CMOVNS:
		case X86_INS_CMOVO:
		case X86_INS_CMOVP:
		case X86_INS_CMOVS:
			op->type = R_ANAL_OP_TYPE_CMOV;
			break;
		// mov
		case X86_INS_MOVSS:
		case X86_INS_MOV:
		case X86_INS_MOVAPS:
		case X86_INS_MOVAPD:
		case X86_INS_MOVZX:
		case X86_INS_MOVUPS:
		case X86_INS_MOVABS:
		case X86_INS_MOVHPD:
		case X86_INS_MOVHPS:
		case X86_INS_MOVLPD:
		case X86_INS_MOVLPS:
		case X86_INS_MOVBE:
		case X86_INS_MOVSB:
		case X86_INS_MOVSD:
		case X86_INS_MOVSQ:
		case X86_INS_MOVSX:
		case X86_INS_MOVSXD:
		case X86_INS_MOVSW:
		case X86_INS_MOVD:
		case X86_INS_MOVQ:
		case X86_INS_MOVDQ2Q:
			{
			op->type = R_ANAL_OP_TYPE_MOV;
			op->ptr = UT64_MAX;
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				} else {
					if (op->ptr < 0x1000)
						op->ptr = UT64_MAX;
				} 
				if (a->decode) {
					if (op->prefix & R_ANAL_OP_PREFIX_REP) {
						int width = INSOP(0).size;
						const char *src = cs_reg_name(handle, INSOP(1).mem.base);
						const char *dst = cs_reg_name(handle, INSOP(0).mem.base);
						const char *counter = (a->bits==16)?"cx":
							(a->bits==32)?"ecx":"rcx";
						esilprintf (op, "%s,!,?{,BREAK,},%s,NUM,%s,NUM,"\
								"%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\
								"df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \
								"?{,8,GOTO,},%s,=,%s,=",
								counter, src, dst, src, width, dst,
								width, width, src, width, dst, width, src,
								width, dst, counter, counter, dst, src);
					} else {
						char *src = getarg (&gop, 1, 0, NULL);
						char *dst = getarg (&gop, 0, 1, NULL);
						esilprintf (op, "%s,%s", src, dst);
						free (src);
						free (dst);
					}
				}
				break;
			case X86_OP_REG:
				{
				char *dst = getarg (&gop, 0, 0, NULL);
				op->dst = r_anal_value_new ();
				op->dst->reg = r_reg_get (a->reg, dst, R_REG_TYPE_GPR);
				op->src[0] = r_anal_value_new ();
				if (INSOP(1).type == X86_OP_MEM) {
					op->src[0]->delta = INSOP(1).mem.disp;
				}
				free (dst);
				}
			default:
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op, "%s,%s,=", src, dst);
					free (src);
					free (dst);
				}
				break;
			}
			if (op->refptr<1 || op->ptr == UT64_MAX) {
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					op->refptr = INSOP(1).size;
					if (INSOP(1).mem.base == X86_REG_RIP) {
						op->ptr += addr + insn->size;
					} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
						op->stackop = R_ANAL_STACK_GET;
						op->stackptr = regsz;
					}
					break;
				case X86_OP_IMM:
					if (INSOP(1).imm > 10)
						op->ptr = INSOP(1).imm;
					break;
				default:
					break;
				}
			}
			}
			break;
		case X86_INS_ROL:
		case X86_INS_RCL:
			// TODO: RCL Still does not work as intended
			//  - Set flags
			op->type = R_ANAL_OP_TYPE_ROL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,<<<,%s,=", src, dst, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_ROR:
		case X86_INS_RCR:
			// TODO: RCR Still does not work as intended
			//  - Set flags
			op->type = R_ANAL_OP_TYPE_ROR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,>>>,%s,=", src, dst, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SHL:
		case X86_INS_SHLD:
		case X86_INS_SHLX:
			// TODO: Set CF: Carry flag is the last bit shifted out due to
			// this operation. It is undefined for SHL and SHR where the
			// number of bits shifted is greater than the size of the
			// destination.
			op->type = R_ANAL_OP_TYPE_SHL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "<<");
				esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAR:
		case X86_INS_SARX:
			// TODO: Set CF. See case X86_INS_SHL for more details.
			op->type = R_ANAL_OP_TYPE_SAR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, ">>");
				esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAL:
			// TODO: Set CF: See case X86_INS_SAL for more details.
			op->type = R_ANAL_OP_TYPE_SAL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "<<");
				esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SALC:
			op->type = R_ANAL_OP_TYPE_SAL;
			if (a->decode) {
				esilprintf (op, "$z,DUP,zf,=,al,=");
			}
			break;
		case X86_INS_SHR:
		case X86_INS_SHRD:
		case X86_INS_SHRX:
			// TODO: Set CF: See case X86_INS_SAL for more details.
			op->type = R_ANAL_OP_TYPE_SHR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,>>=,$z,zf,=,$p,pf,=,$s,sf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_CMP:
		case X86_INS_CMPPD:
		case X86_INS_CMPPS:
		case X86_INS_CMPSW:
		case X86_INS_CMPSD:
		case X86_INS_CMPSQ:
		case X86_INS_CMPSB:
		case X86_INS_CMPSS:
		case X86_INS_TEST:
			if (insn->id == X86_INS_TEST) {
				op->type = R_ANAL_OP_TYPE_ACMP;					//compare via and
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=",
						src, dst);
					free (src);
					free (dst);
				}
			} else {
				op->type = R_ANAL_OP_TYPE_CMP;
				if (a->decode) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 0, NULL);
					esilprintf (op,  "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=",
						src, dst, (INSOP(0).size*8));
					free (src);
					free (dst);
				}
			}
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				}
				op->ptr = INSOP(1).imm;
				break;
			default:
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					op->refptr = INSOP(1).size;
					if (INSOP(1).mem.base == X86_REG_RIP) {
						op->ptr += addr + insn->size;
					} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
						op->stackop = R_ANAL_STACK_SET;
						op->stackptr = regsz;
					}
					break;
				case X86_OP_IMM:
					op->ptr = INSOP(1).imm;
					break;
				default:
					break;
				}
				break;
			}
			break;
		case X86_INS_LEA:
			op->type = R_ANAL_OP_TYPE_LEA;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				char *dst = getarg (&gop, 1, 2, NULL);
				esilprintf (op, "%s,%s,=", dst, src);
				free (src);
				free (dst);
			}
			switch (INSOP(1).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(1).mem.disp;
				op->refptr = INSOP(1).size;
				switch (INSOP(1).mem.base) {
				case X86_REG_RIP:
					op->ptr += addr + op->size;
					break;
				case X86_REG_RBP:
				case X86_REG_EBP:
					op->stackop = R_ANAL_STACK_GET;
					op->stackptr = regsz;
					break;
				default:
					/* unhandled */
					break;
				}
				break;
			case X86_OP_IMM:
				if (INSOP(1).imm > 10)
					op->ptr = INSOP(1).imm;
				break;
			default:
				break;
			}
			break;
		case X86_INS_ENTER:
		case X86_INS_PUSH:
		case X86_INS_PUSHAW:
		case X86_INS_PUSHAL:
		case X86_INS_PUSHF:
			{
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op,  "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs);
				free (dst);
			}
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->ptr = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_PUSH;
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UPUSH;
				break;
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = regsz;
			break;
		case X86_INS_LEAVE:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=",
					bp, sp, sp, rs, bp, rs, sp);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_POP:
		case X86_INS_POPF:
		case X86_INS_POPAW:
		case X86_INS_POPAL:
		case X86_INS_POPCNT:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op,
					"%s,[%d],%s,=,%d,%s,+=",
					sp, rs, dst, rs, sp);
				free (dst);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_RET:
		case X86_INS_RETF:
		case X86_INS_RETFQ:
		case X86_INS_IRET:
		case X86_INS_IRETD:
		case X86_INS_IRETQ:
		case X86_INS_SYSRET:
			op->type = R_ANAL_OP_TYPE_RET;
			if (a->decode)
				esilprintf (op, "%s,[%d],%s,=,%d,%s,+=",
					sp, rs, pc, rs, sp);
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_INT3:
			if (a->decode)
				esilprintf (op, "3,$");
			op->type = R_ANAL_OP_TYPE_TRAP; // TRAP
			break;
		case X86_INS_INT1:
			if (a->decode)
				esilprintf (op, "1,$");
			op->type = R_ANAL_OP_TYPE_SWI; // TRAP
			break;
		case X86_INS_INT:
			if (a->decode)
				esilprintf (op, "%d,$",
					R_ABS((int)INSOP(0).imm));
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
		case X86_INS_SYSCALL:
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
		case X86_INS_INTO:
		case X86_INS_VMCALL:
		case X86_INS_VMMCALL:
			op->type = R_ANAL_OP_TYPE_TRAP;
			if (a->decode)
				esilprintf (op, "%d,$", (int)INSOP(0).imm);
			break;
		case X86_INS_JL:
		case X86_INS_JLE:
		case X86_INS_JA:
		case X86_INS_JAE:
		case X86_INS_JB:
		case X86_INS_JBE:
		case X86_INS_JCXZ:
		case X86_INS_JECXZ:
		case X86_INS_JRCXZ:
		case X86_INS_JO:
		case X86_INS_JNO:
		case X86_INS_JS:
		case X86_INS_JNS:
		case X86_INS_JP:
		case X86_INS_JNP:
		case X86_INS_JE:
		case X86_INS_JNE:
		case X86_INS_JG:
		case X86_INS_JGE:
		case X86_INS_LOOP:
		case X86_INS_LOOPE:
		case X86_INS_LOOPNE:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = INSOP(0).imm;
			op->fail = addr+op->size;
			const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx";
			if (a->decode) {
				char *dst = getarg (&gop, 0, 2, NULL);
				switch (insn->id) {
				case X86_INS_JL:
					esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JLE:
					esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JA:
					esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc);
					break;
				case X86_INS_JAE:
					esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JB:
					esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JO:
					esilprintf (op, "of,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNO:
					esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JE:
					esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JGE:
					esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNE:
					esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JG:
					esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JS:
					esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNS:
					esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JP:
					esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNP:
					esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JBE:
					esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JCXZ:
					esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JECXZ:
					esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JRCXZ:
					esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_LOOP:
					esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc);
					break;
				case X86_INS_LOOPE:
					esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}",
						cnt, cnt, dst, pc);
					break;
				case X86_INS_LOOPNE:
					esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}",
						cnt, cnt, dst, pc);
					break;
				}
				free (dst);
			}
			break;
		case X86_INS_CALL:
		case X86_INS_LCALL:
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->type = R_ANAL_OP_TYPE_CALL;
				// TODO: what if UCALL?
				// TODO: use imm_size
				op->jump = INSOP(0).imm;
				op->fail = addr+op->size;
				break;
			case X86_OP_MEM:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				if (INSOP(0).mem.base == 0) {
					op->ptr = INSOP(0).mem.disp;
				}
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				break;
			}
			if (a->decode) {
				char* arg = getarg (&gop, 0, 0, NULL);
				esilprintf (op,
						"%s,"
						"%d,%s,-=,%s,"
						"=[],"
						"%s,%s,=",
						pc, rs, sp, sp, arg, pc);
				free (arg);
			}
			break;
		case X86_INS_JMP:
		case X86_INS_LJMP:
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,=", src, pc);
				free (src);
			}
			// TODO: what if UJMP?
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->jump = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_JMP;
				if (a->decode) {
					ut64 dst = INSOP(0).imm;
					esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
				}
				break;
			case X86_OP_MEM:
				op->type = R_ANAL_OP_TYPE_UJMP;
				op->ptr = INSOP(0).mem.disp;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
					op->refptr = 8;
				} else {
					cs_x86_op in = INSOP(0);
					if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) {
						if (a->decode) {
							esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc);
						}
					}
				}
				break;
			case X86_OP_REG:
				{
				char *src = getarg (&gop, 0, 0, NULL);
				op->src[0] = r_anal_value_new ();
				op->src[0]->reg = r_reg_get (a->reg, src, R_REG_TYPE_GPR);
				free (src);
				//XXX fallthrough
				}
			case X86_OP_FP:
			default: // other?
				op->type = R_ANAL_OP_TYPE_UJMP;
				op->ptr = UT64_MAX;
				break;
			}
			break;
		case X86_INS_IN:
		case X86_INS_INSW:
		case X86_INS_INSD:
		case X86_INS_INSB:
			op->type = R_ANAL_OP_TYPE_IO;
			op->type2 = 0;
			break;
		case X86_INS_OUT:
		case X86_INS_OUTSB:
		case X86_INS_OUTSD:
		case X86_INS_OUTSW:
			op->type = R_ANAL_OP_TYPE_IO;
			op->type2 = 1;
			break;
		case X86_INS_VXORPD:
		case X86_INS_VXORPS:
		case X86_INS_VPXORD:
		case X86_INS_VPXORQ:
		case X86_INS_VPXOR:
		case X86_INS_XORPS:
		case X86_INS_KXORW:
		case X86_INS_PXOR:
		case X86_INS_XOR:
			op->type = R_ANAL_OP_TYPE_XOR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "^");
				esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=",
					src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_OR:
			// The OF and CF flags are cleared; the SF, ZF, and PF flags are
			// set according to the result. The state of the AF flag is
			// undefined.
			op->type = R_ANAL_OP_TYPE_OR;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "%s,%s,|=,0,of,=,0,cf,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_INC:
			// The CF flag is not affected. The OF, SF, ZF, AF, and PF flags
			// are set according to the result.
			op->type = R_ANAL_OP_TYPE_ADD;
			op->val = 1;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				if (strchr (src, '[')) {
					char *dst = r_str_replace (strdup (src), "[", "=[", 1);
					esilprintf (op, "1,%s,++,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst);
					free (dst);
				} else {
					esilprintf (op, "%s,++=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src);
				}
				free (src);
			}
			break;
		case X86_INS_DEC:
			// The CF flag is not affected. The OF, SF, ZF, AF, and PF flags
			// are set according to the result.
			op->type = R_ANAL_OP_TYPE_SUB;
			op->val = 1;
			if (a->decode) {
				char *src = getarg (&gop, 0, 0, NULL);
				//esilprintf (op, "%s,--=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src);
				esilprintf (op, "1,%s,[4],-,%s,=[4],$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, src);
				free (src);
			}
			break;
		case X86_INS_PSUBB:
		case X86_INS_PSUBW:
		case X86_INS_PSUBD:
		case X86_INS_PSUBQ:
		case X86_INS_PSUBSB:
		case X86_INS_PSUBSW:
		case X86_INS_PSUBUSB:
		case X86_INS_PSUBUSW:
			op->type = R_ANAL_OP_TYPE_SUB;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "-");
				esilprintf (op, "%s,%s", src, dst);
				free(src);
				free(dst);
			}
			break;
		case X86_INS_SUB:
			op->type = R_ANAL_OP_TYPE_SUB;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "-");
				// Set OF, SF, ZF, AF, PF, and CF flags.
				// We use $b rather than $c here as the carry flag really
				// represents a "borrow"
				esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=",
					src, dst);
				free (src);
				free (dst);
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = INSOP(1).imm;
				}
			}
			break;
		case X86_INS_SBB:
			// dst = dst - (src + cf)
			op->type = R_ANAL_OP_TYPE_SUB;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				esilprintf (op, "cf,%s,+,%s,-=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_LIDT:
			op->type = R_ANAL_OP_TYPE_LOAD;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_SIDT:
			op->type = R_ANAL_OP_TYPE_STORE;
			op->family = R_ANAL_OP_FAMILY_PRIV;
			break;
		case X86_INS_RDRAND:
		case X86_INS_RDSEED:
		case X86_INS_RDMSR:
		case X86_INS_RDPMC:
		case X86_INS_RDTSC:
		case X86_INS_RDTSCP:
		case X86_INS_CRC32:
		case X86_INS_SHA1MSG1:
		case X86_INS_SHA1MSG2:
		case X86_INS_SHA1NEXTE:
		case X86_INS_SHA1RNDS4:
		case X86_INS_SHA256MSG1:
		case X86_INS_SHA256MSG2:
		case X86_INS_SHA256RNDS2:
		case X86_INS_AESDECLAST:
		case X86_INS_AESDEC:
		case X86_INS_AESENCLAST:
		case X86_INS_AESENC:
		case X86_INS_AESIMC:
		case X86_INS_AESKEYGENASSIST:
			// AES instructions
			op->family = R_ANAL_OP_FAMILY_CRYPTO;
			op->type = R_ANAL_OP_TYPE_MOV; // XXX
			break;
		case X86_INS_AND:
		case X86_INS_ANDN:
		case X86_INS_ANDPD:
		case X86_INS_ANDPS:
		case X86_INS_ANDNPD:
		case X86_INS_ANDNPS:
			op->type = R_ANAL_OP_TYPE_AND;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "&");
				esilprintf (op, "%s,%s,0,of,=,0,cf,=,$z,zf,=,$s,sf,=,$o,pf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_IDIV:
			op->type = R_ANAL_OP_TYPE_DIV;
			if (a->decode) {
				char *a0 = getarg (&gop, 0, 0, NULL);
				char *a1 = getarg (&gop, 1, 0, NULL);
				char *a2 = getarg (&gop, 2, 0, NULL);
				// TODO update flags & handle signedness
				if (!a2 && !a1) {
					// TODO: IDIV rbx not implemented. this is just a workaround
// http://www.tptp.cc/mirrors/siyobik.info/instruction/IDIV.html
// Divides (signed) the value in the AX, DX:AX, or EDX:EAX registers (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, or EDX:EAX registers. The source operand can be a general-purpose register or a memory location. The action of this instruction depends on the operand size (dividend/divisor), as shown in the following table:
// IDIV RBX    ==   RDX:RAX /= RBX
					esilprintf (op, "%s,%s,/=", a0, "rax");
				} else {
					esilprintf (op, "%s,%s,/,%s,=", a2, a1, a0);
				}
				free (a0);
				free (a1);
				free (a2);
			}
			break;
		case X86_INS_DIV:
			op->type = R_ANAL_OP_TYPE_DIV;
			if (a->decode) {
				int width = INSOP(0).size;
				char *dst = getarg (&gop, 0, 0, NULL);
				const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax";
				const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx";
				// TODO update flags & handle signedness
				esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=",
					dst, r_ax, r_dx, dst, r_ax, r_ax);
				free (dst);
			}
			break;
		case X86_INS_IMUL:
			op->type = R_ANAL_OP_TYPE_MUL;
			if (a->decode) {
				char *a0 = getarg (&gop, 0, 0, NULL);
				char *a1 = getarg (&gop, 1, 0, NULL);
				char *a2 = getarg (&gop, 2, 0, NULL);
				if (a2) {
					// TODO update flags & handle signedness
					esilprintf (op, "%s,%s,*,%s,=", a2, a1, a0);
					free (a2);
				} else {
					if (a1) {
						esilprintf (op, "%s,%s,*=", a1, a0);
					} else {
						esilprintf (op, "%s,%s,*=", a0, "rax");
					}
				}
				free (a0);
				free (a1);
			}
			break;
		case X86_INS_MUL:
		case X86_INS_MULX:
		case X86_INS_MULPD:
		case X86_INS_MULPS:
		case X86_INS_MULSD:
		case X86_INS_MULSS:
			op->type = R_ANAL_OP_TYPE_MUL;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, "*");
				if (!src && dst) {
					switch (dst[0]) {
					case 'r':
						src = strdup ("rax");
						break;
					case 'e':
						src = strdup ("eax");
						break;
					default:
						src = strdup ("al");
						break;
					}
				}
				esilprintf (op, "%s,%s", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_PACKSSDW:
		case X86_INS_PACKSSWB:
		case X86_INS_PACKUSWB:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		case X86_INS_PADDB:
		case X86_INS_PADDD:
		case X86_INS_PADDW:
		case X86_INS_PADDSB:
		case X86_INS_PADDSW:
		case X86_INS_PADDUSB:
		case X86_INS_PADDUSW:
			op->type = R_ANAL_OP_TYPE_ADD;
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		case X86_INS_XCHG:
			op->type = R_ANAL_OP_TYPE_MOV;
			op->family = R_ANAL_OP_FAMILY_CPU;
			{
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, NULL);
				esilprintf (op, "%s,%s,%s,=,%s,=", src, dst, src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_XADD: /* xchg + add */
			op->type = R_ANAL_OP_TYPE_ADD;
			op->family = R_ANAL_OP_FAMILY_CPU;
			{
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 1, NULL);
				if (src == dst) {
					esilprintf (op, "%s,%s,+,%s", src, dst, dst);
				} else {
					esilprintf (op, "%s,%s,%s,=,%s,=," "%s,%s,+,%s",
							src, dst, src, dst,
							src, dst, dst);
				}
				free (src);
				free (dst);
			}
			break;
		case X86_INS_FADD:
		case X86_INS_FADDP:
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case X86_INS_ADDPS:
		case X86_INS_ADDSD:
		case X86_INS_ADDSS:
		case X86_INS_ADDSUBPD:
		case X86_INS_ADDSUBPS:
		case X86_INS_ADDPD:
			// The OF, SF, ZF, AF, CF, and PF flags are set according to the
			// result.
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				if (INSOP(0).type == X86_OP_MEM) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *src2 = getarg (&gop, 0, 0, NULL);
					char *dst = getarg (&gop, 0, 1, NULL);
					esilprintf (op, "%s,%s,+,%s", src, src2, dst);
					free (src);
					free (src2);
					free (dst);
				} else {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 1, "+");
					esilprintf (op, "%s,%s", src, dst);
					free (src);
					free (dst);
				}
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = -INSOP(1).imm;
				}
			}
			break;
		case X86_INS_ADD:
			// The OF, SF, ZF, AF, CF, and PF flags are set according to the
			// result.
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				if (INSOP(0).type == X86_OP_MEM) {
					char *src = getarg (&gop, 1, 0, NULL);
					char *src2 = getarg (&gop, 0, 0, NULL);
					char *dst = getarg (&gop, 0, 1, NULL);
					esilprintf (op, "%s,%s,+,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, src2, dst);
					free (src);
					free (src2);
					free (dst);
				} else {
					char *src = getarg (&gop, 1, 0, NULL);
					char *dst = getarg (&gop, 0, 1, "+");
					esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst);
					free (src);
					free (dst);
				}
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = -INSOP(1).imm;
				}
			}
			break;
		case X86_INS_ADC:
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				char *src = getarg (&gop, 1, 0, NULL);
				char *dst = getarg (&gop, 0, 0, NULL);
				// dst = dst + src + cf
				// NOTE: We would like to add the carry first before adding the
				// source to ensure that the flag computation from $c belongs
				// to the operation of adding dst += src rather than the one
				// that adds carry (as esil only keeps track of the last
				// addition to set the flags).
				esilprintf (op, "cf,%s,+,%s,+=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst);
				free (src);
				free (dst);
			}
				break;
			/* Direction flag */
		case X86_INS_CLD:
			op->type = R_ANAL_OP_TYPE_MOV;
			if (a->decode)
				esilprintf (op, "0,df,=");
			break;
		case X86_INS_STD:
			op->type = R_ANAL_OP_TYPE_MOV;
			if (a->decode)
				esilprintf (op, "1,df,=");
			break;
		}
		switch (insn->id) {
		case X86_INS_MOVAPS: //cvtss2sd
		case X86_INS_ADDSD: //cvtss2sd
		case X86_INS_SUBSD: //cvtss2sd
		case X86_INS_MULSD: //cvtss2sd
		case X86_INS_CVTSS2SD: //cvtss2sd
		case X86_INS_MOVSS:
		case X86_INS_MOVSD:
			op->family = R_ANAL_OP_FAMILY_MMX;
			break;
		}
	}
//#if X86_GRP_PRIVILEGE>0
	if (insn) {
#if HAVE_CSGRP_PRIVILEGE
		if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE))
			op->family = R_ANAL_OP_FAMILY_PRIV;
#endif
#if !USE_ITER_API
		cs_free (insn, n);
#endif
	}
	//cs_close (&handle);
	return op->size;
}
示例#4
0
static int bpf_anal(RAnal *anal, RAnalOp *op, ut64 addr,
	const ut8 *data, int len) {
	RBpfSockFilter *f = (RBpfSockFilter *)data;
	memset (op, '\0', sizeof (RAnalOp));
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->type = R_ANAL_OP_TYPE_UNK;
	op->size = 8;
	op->addr = addr;

	r_strbuf_init (&op->esil);

	switch (f->code) {
	case BPF_RET | BPF_A:
		op->type = R_ANAL_OP_TYPE_RET;
		esilprintf (op, "A,R0,=,0,$");
		break;
	case BPF_RET | BPF_K:
	case BPF_RET | BPF_X:
		op->type = R_ANAL_OP_TYPE_RET;
		if (BPF_SRC (f->code) == BPF_K) {
			esilprintf (op, "%" PFMT64d ",R0,=,0,$", f->k);
		} else if (BPF_SRC (f->code) == BPF_X) {
			esilprintf (op, "X,R0,=,0,$");
		}
		break;
	case BPF_MISC_TAX:
		op->type = R_ANAL_OP_TYPE_MOV;
		SET_REG_SRC_DST (op, "A", "X");
		esilprintf (op, "A,X,=");
		break;
	case BPF_MISC_TXA:
		op->type = R_ANAL_OP_TYPE_MOV;
		SET_REG_SRC_DST (op, "X", "A");
		esilprintf (op, "X,A,=");
		break;
	case BPF_ST:
		if (INSIDE_M (f->k)) {
			op->type = R_ANAL_OP_TYPE_MOV;
			SET_REG_SRC_DST (op, "A", M[f->k]);
			esilprintf (op, "A,M[%" PFMT64d "],=", f->k);
		} else {
			op->type = R_ANAL_OP_TYPE_ILL;
		}
		break;
	case BPF_STX:
		if (INSIDE_M (f->k)) {
			op->type = R_ANAL_OP_TYPE_MOV;
			SET_REG_SRC_DST (op, "X", M[f->k]);
			esilprintf (op, "X,M[%" PFMT64d "],=", f->k);
		} else {
			op->type = R_ANAL_OP_TYPE_ILL;
		}
		break;
	case BPF_LD_W | BPF_LEN:
		op->type = R_ANAL_OP_TYPE_MOV;
		SET_REG_SRC_DST (op, "len", "A");
		esilprintf (op, "len,A,=", f->k);
		break;
	case BPF_LDX | BPF_LEN:
		op->type = R_ANAL_OP_TYPE_MOV;
		SET_REG_SRC_DST (op, "len", "X");
		esilprintf (op, "len,X,=", f->k);
		break;
	case BPF_LD_W | BPF_ABS:
		EMIT_LOAD (op, anal->gp + f->k, 4);
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",>,?{,0,R0,=,0,$,BREAK,},%" PFMT64d ",[4],A,=",
			f->k + 4, op->ptr);
		break;
	case BPF_LD_H | BPF_ABS:
		EMIT_LOAD (op, anal->gp + f->k, 2);
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",>,?{,0,R0,=,0,$,BREAK,},"
			"%" PFMT64d ",[2],A,=",
			f->k + 2, op->ptr);
		break;
	case BPF_LD_B | BPF_ABS:
		EMIT_LOAD (op, anal->gp + f->k, 1);
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",>,?{,0,R0,=,0,$,BREAK,},"
			"%" PFMT64d ",[1],A,=",
			f->k + 1, op->ptr);
		break;
	case BPF_LD_W | BPF_IND:
		op->type = R_ANAL_OP_TYPE_LOAD;
		op->ptrsize = 4;
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",X,+,0xffffffff,&,>,?{,0,R0,=,0,$,BREAK,},"
			"%" PFMT64d ",X,+,0xffffffff,&,[4],A,=",
			(st32)f->k + 4, anal->gp + (st32)f->k);
		break;
	case BPF_LD_H | BPF_IND:
		op->type = R_ANAL_OP_TYPE_LOAD;
		op->ptrsize = 2;
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",X,+,0xffffffff,&,>,?{,0,R0,=,0,$,BREAK,},"
			"%" PFMT64d ",X,+,0xffffffff,&,[2],A,=",
			(st32)f->k + 2, anal->gp + (st32)f->k);
		break;
	case BPF_LD_B | BPF_IND:
		op->type = R_ANAL_OP_TYPE_LOAD;
		op->ptrsize = 1;
		SET_A_DST (op);
		esilprintf (op,
			"len,%" PFMT64d ",X,+,0xffffffff,&,>,?{,0,R0,=,0,$,BREAK,},"
			"%" PFMT64d ",X,+,0xffffffff,&,[1],A,=",
			(st32)f->k + 1, anal->gp + (st32)f->k);
		break;
	case BPF_LD | BPF_IMM:
		op->type = R_ANAL_OP_TYPE_MOV;
		op->val = f->k;
		SET_REG_DST_IMM (op, "A", f->k);
		esilprintf (op, "0x%08" PFMT64x ",A,=", f->k);
		break;
	case BPF_LDX | BPF_IMM:
		op->type = R_ANAL_OP_TYPE_MOV;
		op->val = f->k;
		SET_REG_DST_IMM (op, "X", f->k);
		esilprintf (op, "0x%08" PFMT64x ",X,=", f->k);
		break;
	case BPF_LDX_B | BPF_MSH:
		op->type = R_ANAL_OP_TYPE_LOAD;
		op->ptrsize = 1;
		op->ptr = anal->gp + f->k;
		SET_A_DST (op);
		esilprintf (op, "%" PFMT64d ",[1],0xf,&,4,*,X,=", op->ptr);
		break;
	case BPF_LD | BPF_MEM:
		op->type = R_ANAL_OP_TYPE_MOV;
		if (INSIDE_M (f->k)) {
			SET_REG_SRC_DST (op, M[f->k], "A");
			esilprintf (op, "M[%" PFMT64d "],A,=", f->k);
		} else {
			op->type = R_ANAL_OP_TYPE_ILL;
		}
		break;
	case BPF_LDX | BPF_MEM:
		op->type = R_ANAL_OP_TYPE_MOV;
		if (INSIDE_M (f->k)) {
			SET_REG_SRC_DST (op, M[f->k], "X");
			esilprintf (op, "M[%" PFMT64d "],X,=", f->k);
		} else {
			op->type = R_ANAL_OP_TYPE_ILL;
		}
		break;
	case BPF_JMP_JA:
		op->type = R_ANAL_OP_TYPE_JMP;
		op->jump = addr + 8 + f->k * 8;
		esilprintf (op, "%" PFMT64d ",pc,=", op->jump);

		break;
	case BPF_JMP_JGT | BPF_X:
	case BPF_JMP_JGT | BPF_K:
		EMIT_CJMP (op, addr, f);
		op->cond = R_ANAL_COND_GT;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			esilprintf (op,
				"%" PFMT64d ",A,>,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->val, op->jump, op->fail);
		} else if (BPF_SRC (f->code) == BPF_X) {
			esilprintf (op,
				"X,A,>,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->jump, op->fail);
		} else {
			op->type = R_ANAL_OP_TYPE_ILL;
		}
		break;
	case BPF_JMP_JGE | BPF_X:
	case BPF_JMP_JGE | BPF_K:
		EMIT_CJMP (op, addr, f);
		op->cond = R_ANAL_COND_GE;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			esilprintf (op,
				"%" PFMT64d ",A,>=,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->val, op->jump, op->fail);
		} else {
			esilprintf (op,
				"X,A,>=,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->jump, op->fail);
		}
		break;
	case BPF_JMP_JEQ | BPF_X:
	case BPF_JMP_JEQ | BPF_K:
		EMIT_CJMP (op, addr, f);
		op->cond = R_ANAL_COND_EQ;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			esilprintf (op,
				"%" PFMT64d ",A,==,$z,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->val, op->jump, op->fail);
		} else {
			esilprintf (op,
				"X,A,==,$z,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->jump, op->fail);
		}
		break;
	case BPF_JMP_JSET | BPF_X:
	case BPF_JMP_JSET | BPF_K:
		EMIT_CJMP (op, addr, f);
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			esilprintf (op,
				"%" PFMT64d ",A,&,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->val, op->jump, op->fail);
		} else {
			esilprintf (op,
				"X,A,&,!,?{,%" PFMT64d ",pc,=,BREAK,},%" PFMT64d ",pc,=",
				op->val, op->jump, op->fail);
		}
		break;
	case BPF_ALU_NEG:
		op->type = R_ANAL_OP_TYPE_NOT;
		esilprintf (op, "A,0,-,A,=");
		SET_REG_SRC_DST (op, "A", "A");
		break;
	case BPF_ALU_LSH | BPF_X:
	case BPF_ALU_LSH | BPF_K:
		op->type = R_ANAL_OP_TYPE_SHL;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,<<=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,<<=");
		}
		break;
	case BPF_ALU_RSH | BPF_X:
	case BPF_ALU_RSH | BPF_K:
		op->type = R_ANAL_OP_TYPE_SHR;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,>>=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,>>=");
		}
		break;
	case BPF_ALU_ADD | BPF_X:
	case BPF_ALU_ADD | BPF_K:
		op->type = R_ANAL_OP_TYPE_ADD;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", op->val);
			esilprintf (op, "%" PFMT64d ",A,+=", op->val);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,+=");
		}
		break;
	case BPF_ALU_SUB | BPF_X:
	case BPF_ALU_SUB | BPF_K:
		op->type = R_ANAL_OP_TYPE_SUB;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", op->val);
			esilprintf (op, "%" PFMT64d ",A,-=", op->val);

		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,-=");
		}
		break;
	case BPF_ALU_MUL | BPF_X:
	case BPF_ALU_MUL | BPF_K:
		op->type = R_ANAL_OP_TYPE_MUL;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,*=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,*=");
		}
		break;
	case BPF_ALU_DIV | BPF_X:
	case BPF_ALU_DIV | BPF_K:
		op->type = R_ANAL_OP_TYPE_DIV;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			if (f->k == 0) {
				esilprintf (op, "0,R0,=,0,$");
			} else {
				esilprintf (op, "%" PFMT64d ",A,/=", f->k);
			}
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "0,X,==,$z,?{,0,R0,=,0,$,BREAK,},X,A,/=");
		}
		break;
	case BPF_ALU_MOD | BPF_X:
	case BPF_ALU_MOD | BPF_K:
		op->type = R_ANAL_OP_TYPE_MOD;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			if (f->k == 0) {
				esilprintf (op, "0,R0,=,0,$");
			} else {
				esilprintf (op, "%" PFMT64d ",A,%%=", f->k);
			}
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "0,X,==,$z,?{,0,R0,=,0,$,BREAK,},X,A,%%=");
		}
		break;
	case BPF_ALU_AND | BPF_X:
	case BPF_ALU_AND | BPF_K:
		op->type = R_ANAL_OP_TYPE_AND;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,&=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,&=");
		}
		break;
	case BPF_ALU_OR | BPF_X:
	case BPF_ALU_OR | BPF_K:
		op->type = R_ANAL_OP_TYPE_OR;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,|=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,|,A,=");
		}
		break;
	case BPF_ALU_XOR | BPF_X:
	case BPF_ALU_XOR | BPF_K:
		op->type = R_ANAL_OP_TYPE_XOR;
		if (BPF_SRC (f->code) == BPF_K) {
			op->val = f->k;
			SET_REG_DST_IMM (op, "A", f->k);
			esilprintf (op, "%" PFMT64d ",A,^=", f->k);
		} else {
			SET_REG_SRC_DST (op, "X", "A");
			esilprintf (op, "X,A,^=");
		}
		break;
	default:
		op->type = R_ANAL_OP_TYPE_ILL;
		break;
	}

	return op->size;
}
示例#5
0
static int dalvik_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	int sz = dalvik_opcodes[data[0]].len;
	if (!op || sz >= len) {
		return sz;
	}
	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->size = sz;
	op->nopcode = 1; // Necessary??
	op->id = data[0];

	ut32 vA = 0;
	ut32 vB = 0;
	ut32 vC = 0;
	if (len > 3) {
		vA = data[1];
		vB = data[2];
		vC = data[3];
	}
	switch (data[0]) {
	case 0xca: // rem-float:
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x1b: // const-string/jumbo
	case 0x14: // const
	case 0x15: // const
	case 0x16: // const
	case 0x17: // const
	case 0x42: // const
	case 0x12: // const/4
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			// op->stackop = R_ANAL_STACK_SET;
			op->ptr = -vA; // why
			op->val = vA;
			esilprintf (op, "0x%"PFMT64x",v%d,=", vA, vB);
		}
		break;
	case 0x01: // move
	case 0x07: // move-object
	case 0x04: // mov-wide
		{
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			if (vA == vB) {
				op->type = R_ANAL_OP_TYPE_NOP;
				esilprintf (op, ",");
			} else {
				op->type = R_ANAL_OP_TYPE_MOV;
				op->stackop = R_ANAL_STACK_SET;
				op->ptr = -vA;
				esilprintf (op, "v%d,v%d,=", vA, vB);
			}
		}
		break;
	case 0x02: // move/from16
	case 0x03: // move/16
	case 0x05: // move-wide/from16
	case 0x06: // mov-wide&17
	case 0x08: // move-object/from16
	case 0x09: // move-object/16
	case 0x13: // const/16
		op->type = R_ANAL_OP_TYPE_MOV;
		if (len > 2) {
			int vA = (int) data[1];
			ut32 vB = (data[3] << 8) | data[2];
			esilprintf (op, "v%d,v%d,=", vA, vB);
			op->val = vB;
		}
		break;
	case 0x18: // const-wide
	case 0x19: // const-wide
		// 180001000101.  const-wide v0:v1, 0x18201cd01010001
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case 0x0a: // move-result
	case 0x0d: // move-exception
	case 0x0c: // move-result-object
	case 0x0b: // move-result-wide
	 	// TODO: add MOVRET OP TYPE ??
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut32 vA = data[1];
			esilprintf (op, "sp,v%d,=[8],8,sp,+=,8", vA);
		}
		break;
	case 0x1a: // const-string
		op->type = R_ANAL_OP_TYPE_MOV;
		op->datatype = R_ANAL_DATATYPE_STRING;
		if (len > 2) {
			ut32 vA = data[1];
			ut32 vB = (data[3]<<8) | data[2];
			ut64 offset = R_ANAL_GET_OFFSET (anal, 's', vB);
			op->ptr = offset;
			op->refptr = 0;
			esilprintf (op, "0x%"PFMT64x",v%d,=", offset, vA);
		}
		break;
	case 0x1c: // const-class
		op->type = R_ANAL_OP_TYPE_MOV;
		op->datatype = R_ANAL_DATATYPE_CLASS;
		break;
	case 0x89: // float-to-double
	case 0x8a: // double-to-int
	case 0x87: // double-to-int
	case 0x8c: // double-to-float
	case 0x8b: // double-to-long
	case 0x88: // float-to-long
	case 0x86: // long-to-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x81: // int-to-long
	case 0x82: // int-to-float
	case 0x85: // long-to-float
	case 0x83: // int-to-double
	case 0x8d: // int-to-byte
	case 0x8e: // int-to-char
		op->type = R_ANAL_OP_TYPE_CAST;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xff,&,v%d,=", vB, vA);
		}
		break;
	case 0x8f: // int-to-short
		op->type = R_ANAL_OP_TYPE_CAST;
		// op->datatype = R_ANAL_DATATYPE_INT32 | R_ANAL_DATATYPE_INT16;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xffff,&,v%d,=", vB, vA);
		}
		break;
	case 0x84: // long-to-int
		op->type = R_ANAL_OP_TYPE_CAST;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xffffffff,&,v%d,=", vB, vA);
		}
		break;
	case 0x20: // instance-of
		{
		op->type = R_ANAL_OP_TYPE_CMP;
		esilprintf (op, "%d,instanceof,%d,-,!,v%d,=", vC, vB, vA);
		}
		break;
	case 0x21: // array-length
		op->type = R_ANAL_OP_TYPE_LENGTH;
		op->datatype = R_ANAL_DATATYPE_ARRAY;
		break;
	case 0x44: // aget
	case 0x45: //aget-bool
	case 0x46:
	case 0x47: //aget-bool
	case 0x48: //aget-byte
	case 0x49: //aget-char
	case 0x4a: //aget-short
	case 0x52: //iget
	case 0x58: //iget-short
	case 0x53: //iget-wide
	case 0x56: //iget-byte
	case 0x57: //iget-char
	case 0xea: //sget-wide-volatile
	case 0xf4: //iget-byte
	case 0x66: //sget-short
	case 0xfd: //sget-object
	case 0x55: //iget-bool
	case 0x60: // sget
	case 0x61: //
	case 0x64: // sget-byte
	case 0x65: // sget-char
	case 0xe3: //iget-volatile
	case 0xe4: //
	case 0xe5: // sget
	case 0xe6: // sget
	case 0xe7: // iget-object-volatile
	case 0xe8: //iget-bool
	case 0xf3: //iget-bool
	case 0xf8: //iget-bool
	case 0xf2: //iget-quick
		op->type = R_ANAL_OP_TYPE_LOAD;
		break;
	case 0x54: // iget-object
		{
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,v%d,iget,v%d,=", vC, vB, vA);
		}
		break;
	case 0x63: // sget-boolean
		{
		const char *vT = "-boolean";
		op->datatype = R_ANAL_DATATYPE_BOOLEAN;
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,%d,sget%s,v%d,=", vC, vB, vT, vA);
		}
		break;
	case 0x62: // sget-object
		{
		const char *vT = "-object";
		op->datatype = R_ANAL_DATATYPE_OBJECT;
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,%d,sget%s,v%d,=", vC, vB, vT, vA);
		}
		break;
	case 0x6b: //sput-byte
	case 0x6d: //sput-short
	case 0xeb: //sput-wide-volatile
	case 0x4b: //aput
	case 0x4c: //aput-wide
	case 0x4d: // aput-object
	case 0x4e: // aput-bool
	case 0x4f: //
	case 0x5e: //iput-char
	case 0xfc: //iput-object-volatile
	case 0xf5: //iput-quick
	case 0x5c: //iput-bool
	case 0x69: //sput-object
	case 0x5f: //iput-wide
	case 0xe9: //iput-wide-volatile
	case 0xf6: //iput-wide
	case 0xf7: //iput-wide
	case 0x67: //iput-wide
	case 0x59: //iput-wide
	case 0x5a: //iput-wide
	case 0x5b: //iput-wide
	case 0x5d: //iput-wide
	case 0x50: //
	case 0x51: // aput-short
	case 0x68: // sput-wide
	case 0x6a: // sput-boolean
	case 0x6c: // sput-wide
	case 0xfe: // sput
		op->type = R_ANAL_OP_TYPE_STORE;
		{
			ut32 vA = (data[1] & 0x0f);
			ut32 vB = (data[1] & 0xf0) >> 4;
			esilprintf (op, "TODO,v%d,v%d,=", vA, vB);
		}
		break;
	case 0xad: // mul-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		op->type = R_ANAL_OP_TYPE_MUL;
		esilprintf (op, "v%d,v%d,*,v%d,=", vC, vB, vA);
		break;
	case 0x9d:
	case 0xc8: // mul-float
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* fall through */
	case 0xcd:
	case 0xd2:
	case 0x92:
	case 0xb2:
		op->type = R_ANAL_OP_TYPE_MUL;
		break;
	case 0x7c: // not-int
	case 0x7e: // not-long
		op->type = R_ANAL_OP_TYPE_NOT;
		break;
	case 0xa4: // shr-long
	case 0xba: // ushr-int/2addr
	case 0xe2: // ushr-int
	case 0xa5: // ushr-long
	case 0x9a: // ushr-long
	case 0xc5: // ushr-long/2addr
	case 0xc4: // shr-long/2addr
	case 0xe1: // shr-int/lit8
	case 0x99: // shr-int
		op->type = R_ANAL_OP_TYPE_SHR;
		break;
	case 0xaa: // rem-float
	case 0xcf: // rem-double
	case 0xaf: // rem-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0xb4: // rem-int/2addr
	case 0xdc: // rem-int/lit8
	case 0xd4: // rem-int
	case 0xbf: // rem-long/2addr
	case 0x9f: // rem-long
	case 0x94: // rem-int
		op->type = R_ANAL_OP_TYPE_MOD; // mod = rem
		break;
	case 0xd7:
	case 0xd9:
	case 0xda:
	case 0xde:

	case 0x95: // and-int
	case 0x96: // or-int
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case 0xc2: // xor-long
	case 0x97: // xor-int
	case 0xdf: // xor-int/lit16
	case 0xa2: // xor-long
		op->type = R_ANAL_OP_TYPE_XOR;
		break;
	case 0xc9: // div-float
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x93: // div-int
	case 0xd3: // div-int/lit16
	case 0xdb: // div-int/lit8
	case 0xce: // div-double
	case 0x9e: // div-double
	case 0xbe: // div-double
	case 0xae: // div-double
	case 0xa9: // div-float
	case 0xb3: // div-int/2addr
		op->type = R_ANAL_OP_TYPE_DIV;
		break;
	case 0x0e: // return-void
	case 0x0f: // return
	case 0x10: // return-wide
	case 0x11: // return-object
	case 0xf1: // return-void-barrier
		op->type = R_ANAL_OP_TYPE_RET;
		op->eob = true;
		//TODO: handle return if(0x0e) {} else {}
		if (data[0] == 0x0e) {// return-void
			esilprintf (op, "sp,[8],ip,=,8,sp,+=");
		} else {
			ut32 vA = data[1];
			esilprintf (op, "sp,[8],ip,=,8,sp,+=,8,sp,-=,v%d,sp,=[8]", vA);
		}
		break;
	case 0x28: // goto
		op->jump = addr + ((char)data[1])*2;
		op->type = R_ANAL_OP_TYPE_JMP;
		op->eob = true;
		esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		break;
	case 0x29: // goto/16
		if (len > 3) {
			op->jump = addr + (short)(data[2]|data[3]<<8)*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		}
		break;
	case 0x2a: // goto/32
		if (len > 5) {
			op->jump = addr + (int)(data[2]|(data[3]<<8)|(data[4]<<16)|(data[5]<<24))*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		}
		break;
	case 0x2c:
	case 0x2b:
		op->type = R_ANAL_OP_TYPE_SWITCH;
		break;
	case 0x3e: // glitch 0 width instruction .. invalid instruction
	case 0x43:
		op->type = R_ANAL_OP_TYPE_ILL;
		esilprintf (op, ",");
		op->size = 1;
		op->eob = true;
		break;
	case 0x2d: // cmpl-float
	case 0x2e: // cmpg-float
	case 0x3f: // cmpg-float // ???? wrong disasm imho 2e0f12003f0f
	case 0x2f: // cmpl-double
	case 0x30: // cmlg-double
	case 0x31: // cmp-long
	case 0x1f: // check-cast
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case 0x32: // if-eq
	case 0x33: // if-ne
	case 0x34: // if-lt
	case 0x35: // if-ge
	case 0x36: // if-gt
	case 0x37: // if-le
		op->type = R_ANAL_OP_TYPE_CJMP;
		//XXX fix this better the check is to avoid an oob
		if (len > 2) {
			op->jump = addr + (len>3?(short)(data[2]|data[3]<<8)*2 : 0);
			op->fail = addr + sz;
			op->eob = true;
			ut32 vA = data[1];
			ut32 vB = data[2];
			const char *cond = getCond (data[0]);
			esilprintf (op, "v%d,v%d,==,%s,?{,%"PFMT64d",ip,=}", vB, vA, cond, op->jump);
		}
		break;
	case 0x38: // if-eqz
	case 0x39: // if-nez
	case 0x3a: // if-ltz
	case 0x3b: // if-gez
	case 0x3c: // if-gtz
	case 0x3d: // if-lez
		op->type = R_ANAL_OP_TYPE_CJMP;
		//XXX fix this better the check is to avoid an oob
		if (len > 2) {
			op->jump = addr + (len>3?(short)(data[2]|data[3]<<8)*2 : 0);
			op->fail = addr + sz;
			op->eob = true;
			ut32 vA = data[1];
			const char *cond = getCondz (data[0]);
			esilprintf (op, "v%d,%s,?{,%"PFMT64d",ip,=}", vA, cond, op->jump);
		}
		break;
	case 0xec: // breakpoint
		op->type = R_ANAL_OP_TYPE_TRAP;
		esilprintf (op, "TRAP");
		break;
	case 0x1d: // monitor-enter
		op->type = R_ANAL_OP_TYPE_PUSH;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = 1;
		esilprintf (op, ",");
		break;
	case 0x1e: // monitor-exit /// wrong type?
		op->type = R_ANAL_OP_TYPE_POP;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -1;
		esilprintf (op, ",");
		break;
	case 0x6f: // invoke-super
	case 0xfa: // invoke-super-quick
	case 0x70: // invoke-direct
	case 0x71: // invoke-static
	case 0x72: // invoke-interface
	case 0x73: //
	case 0x74: //
	case 0x75: //
	case 0x76: // invoke-direct
	case 0x77: //
	case 0x78: // invokeinterface/range
	case 0xb9: // invokeinterface
	case 0xb7: // invokespecial
	case 0xb8: // invokestatic
	case 0xb6: // invokevirtual
	case 0x6e: // invoke-virtual
	case 0xf0: // invoke-object-init-range
	case 0xf9: // invoke-virtual-quick/range
	case 0xfb: // invoke-super-quick/range
		if (len > 2) {
			//XXX fix this better since the check avoid an oob
			//but the jump will be incorrect
			ut32 vB = len > 3?(data[3] << 8) | data[2] : 0;
			op->jump = anal->binb.get_offset (anal->binb.bin, 'm', vB);
			op->fail = addr + sz;
			op->type = R_ANAL_OP_TYPE_CALL;
			// TODO: handle /range instructions
			esilprintf (op, "8,sp,-=,0x%"PFMT64x",sp,=[8],0x%"PFMT64x",ip,=", addr);
		}
		break;
	case 0x27: // throw
		{
			ut32 vA = data[1];
			op->type = R_ANAL_OP_TYPE_TRAP;
			esilprintf (op, "v%d,TRAP", vA);
		}
		break;
	case 0xee: // execute-inline
	case 0xef: // execute-inline/range
		op->type = R_ANAL_OP_TYPE_SWI;
		break;
	case 0xed: // throw-verification-error
		op->type = R_ANAL_OP_TYPE_TRAP;
		break;
	case 0x22: // new-instance
		op->type = R_ANAL_OP_TYPE_NEW;
		if (len > 2) {
			int vA = (int) data[1];
			int vB = (data[3] << 8) | data[2];
			// resolve class name for vB
			ut64 off = R_ANAL_GET_OFFSET (anal, 't', vB);
			op->ptr = off;
			esilprintf (op, "%d,new,v%d,=", off, vA);
		}
		break;
	case 0x23: // new-array
		op->type = R_ANAL_OP_TYPE_NEW;
		// 0x1c, 0x1f, 0x22
		if (len > 2) {
			ut32 vA = (data[1] & 0x0f);
			ut32 vB = (data[1] & 0xf0) >> 4;
			ut32 vC = (int) data[2] | (data[3]<<8);
			esilprintf (op, "%d,%d,new-array,v%d,=",vC, vB, vA);
		}
		break;
	case 0x24: // filled-new-array
	case 0x25: // filled-new-array-range
	case 0x26: // filled-new-array-data
		op->type = R_ANAL_OP_TYPE_NEW;
		// 0x1c, 0x1f, 0x22
		if (len > 2) {
			//int vA = (int) data[1];
			int vB = (data[3] << 8) | data[2];
			// resolve class name for vB
			ut64 off = R_ANAL_GET_OFFSET (anal, 't', vB);
			op->ptr = off;
		}
		break;
	case 0x00: // nop
		op->type = R_ANAL_OP_TYPE_NOP;
		esilprintf (op, ",");
		break;
	case 0x90: // add-int
	case 0x9b: // add-long
	case 0xa6: // add-float
	case 0xac: // add-double
	case 0xb0: // add-int/2addr
	case 0xbb: // add-long/2addr
	case 0xc6: // add-float/2addr
	case 0xcb: // add-double/2addr
	case 0xd0: // add-int/lit16
	case 0xd8: // add-int/lit8
		{
			op->type = R_ANAL_OP_TYPE_ADD;
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			esilprintf (op, "v%d,v%d,+=", vB, vA);
		}
		break;
	case 0xa7: // sub-float
	case 0xcc: // sub-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* fall thru */
	case 0xc7:
	case 0xbc:
	case 0x91:
	case 0xb1: //sub-int/2addr
	case 0xd1: //sub-int/2addr
	case 0x9c: //sub-long
		op->type = R_ANAL_OP_TYPE_SUB;
		esilprintf (op, "v%d,v%d,-,v%d,=", vC, vB, vA);
		break;
	case 0x7b: // neg-int
	case 0x7d: // neg-long
	case 0x7f: // neg-float
	case 0x80: // neg-double
		op->type = R_ANAL_OP_TYPE_NOT;
		break;
	case 0xa0: // and-long
	case 0xc0: // and-long
	case 0xdd: // and-long
	case 0xd5: // and-long
	case 0xb5: // and-int
		op->type = R_ANAL_OP_TYPE_AND;
		break;
	case 0xd6: // orint/lit16
	case 0xc1: // or-long/2addr
	case 0xa1: // or-long
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case 0xe0: //lshl
	case 0xc3: //lshl
	case 0xa3: // shl-long
	case 0x98: // shl-long
		op->type = R_ANAL_OP_TYPE_SHL;
		break;
	}
示例#6
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	csh handle;
	cs_insn *insn;
	int mode = (a->bits==64)? CS_MODE_64: 
		(a->bits==32)? CS_MODE_32:
		(a->bits==16)? CS_MODE_16: 0;
	int n, ret = cs_open (CS_ARCH_X86, mode, &handle);
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->size = 0;
	op->delay = 0;
	r_strbuf_init (&op->esil);
	if (ret == CS_ERR_OK) {
		cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
		// capstone-next
		n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
		if (n<1) {
			op->type = R_ANAL_OP_TYPE_ILL;
		} else {
			int rs = a->bits/8;
			const char *pc = (a->bits==16)?"ip":
				(a->bits==32)?"eip":"rip";
			const char *sp = (a->bits==16)?"sp":
				(a->bits==32)?"esp":"rsp";
			op->size = insn->size;
			op->prefix = 0;
			switch (insn->detail->x86.prefix[0]) {
			case X86_PREFIX_REPNE:
				op->prefix |= R_ANAL_OP_PREFIX_REPNE;
			case X86_PREFIX_REP:
				op->prefix |= R_ANAL_OP_PREFIX_REP;
			case X86_PREFIX_LOCK:
				op->prefix |= R_ANAL_OP_PREFIX_LOCK;
			}
			switch (insn->id) {
			case X86_INS_FNOP:
			case X86_INS_NOP:
				op->type = R_ANAL_OP_TYPE_NOP;
				if (a->decode)
					esilprintf (op, "");
				break;
			case X86_INS_HLT:
				op->type = R_ANAL_OP_TYPE_TRAP;
				break;
			case X86_INS_CLI:
			case X86_INS_STI:
			case X86_INS_CLC:
			case X86_INS_STC:
				break;
			case X86_INS_MOV:
			case X86_INS_MOVZX:
			case X86_INS_MOVABS:
			case X86_INS_MOVHPD:
			case X86_INS_MOVHPS:
			case X86_INS_MOVLPD:
			case X86_INS_MOVLPS:
			case X86_INS_MOVBE:
			case X86_INS_MOVSB:
			case X86_INS_MOVSD:
			case X86_INS_MOVSQ:
			case X86_INS_MOVSS:
			case X86_INS_MOVSW:
			case X86_INS_MOVD:
			case X86_INS_MOVQ:
			case X86_INS_MOVDQ2Q:
				op->type = R_ANAL_OP_TYPE_MOV;
				switch (INSOP(0).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(0).mem.disp;
					break;
				}
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					break;
				}
				break;
			case X86_INS_CMP:
			case X86_INS_VCMP:
			case X86_INS_CMPPD:
			case X86_INS_CMPPS:
			case X86_INS_CMPSW:
			case X86_INS_CMPSD:
			case X86_INS_CMPSQ:
			case X86_INS_CMPSB:
			case X86_INS_CMPSS:
			case X86_INS_TEST:
				op->type = R_ANAL_OP_TYPE_CMP;
				break;
			case X86_INS_LEA:
				op->type = R_ANAL_OP_TYPE_LEA;
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					break;
				}
				break;
			case X86_INS_ENTER:
			case X86_INS_PUSH:
			case X86_INS_PUSHAW:
			case X86_INS_PUSHAL:
			case X86_INS_PUSHF:
				op->type = R_ANAL_OP_TYPE_PUSH;
				break;
			case X86_INS_LEAVE:
			case X86_INS_POP:
			case X86_INS_POPAW:
			case X86_INS_POPAL:
			case X86_INS_POPF:
			case X86_INS_POPCNT:
				op->type = R_ANAL_OP_TYPE_POP;
				break;
			case X86_INS_RET:
			case X86_INS_RETF:
			case X86_INS_IRET:
			case X86_INS_IRETD:
			case X86_INS_IRETQ:
			case X86_INS_SYSRET:
				op->type = R_ANAL_OP_TYPE_RET;
				if (a->decode)
					esilprintf (op, "%s,[%d],%s,=,%d,%s,+=",
						sp, rs, pc, rs, sp);
				break;
			case X86_INS_INT1:
			case X86_INS_INT3:
			case X86_INS_INTO:
			case X86_INS_INT:
			case X86_INS_VMCALL:
			case X86_INS_VMMCALL:
			case X86_INS_SYSCALL:
				op->type = R_ANAL_OP_TYPE_TRAP;
				if (a->decode)
					esilprintf (op, "%d,$", (int)INSOP(0).imm);
				break;
			case X86_INS_JL:
			case X86_INS_JLE:
			case X86_INS_JA:
			case X86_INS_JAE:
			case X86_INS_JB:
			case X86_INS_JBE:
			case X86_INS_JCXZ:
			case X86_INS_JECXZ:
			case X86_INS_JO:
			case X86_INS_JNO:
			case X86_INS_JS:
			case X86_INS_JNS:
			case X86_INS_JP:
			case X86_INS_JNP:
			case X86_INS_JE:
			case X86_INS_JNE:
			case X86_INS_JG:
			case X86_INS_JGE:
				op->type = R_ANAL_OP_TYPE_CJMP;
				op->jump = INSOP(0).imm;
				op->fail = addr+op->size;
				if (a->decode) {
					if (INSOP(0).type==X86_OP_IMM) {
// TODO
					}
				}
				break;
			case X86_INS_CALL:
			case X86_INS_LCALL:
				if (INSOP(0).type==X86_OP_IMM) {
					op->type = R_ANAL_OP_TYPE_CALL;
					// TODO: what if UCALL?
					// TODO: use imm_size
					op->jump = INSOP(0).imm;
					op->fail = addr+op->size;
				} else {
					op->type = R_ANAL_OP_TYPE_UCALL;
				}
				break;
			case X86_INS_JMP:
			case X86_INS_LJMP:
				// TODO: what if UJMP?
				op->jump = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_JMP;
				if (a->decode) {
					ut64 dst = INSOP(0).imm;
					esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
				}
				break;
			case X86_INS_IN:
			case X86_INS_INSW:
			case X86_INS_INSD:
			case X86_INS_INSB:
			case X86_INS_OUT:
			case X86_INS_OUTSB:
			case X86_INS_OUTSD:
			case X86_INS_OUTSW:
				op->type = R_ANAL_OP_TYPE_IO;
				break;
			case X86_INS_VXORPD:
			case X86_INS_VXORPS:
			case X86_INS_VPXORD:
			case X86_INS_VPXORQ:
			case X86_INS_VPXOR:
			case X86_INS_KXORW:
			case X86_INS_PXOR:
			case X86_INS_XOR:
				op->type = R_ANAL_OP_TYPE_XOR;
				break;
			case X86_INS_OR:
				op->type = R_ANAL_OP_TYPE_OR;
				break;
			case X86_INS_SUB:
			case X86_INS_DEC:
			case X86_INS_PSUBB:
			case X86_INS_PSUBW:
			case X86_INS_PSUBD:
			case X86_INS_PSUBQ:
			case X86_INS_PSUBSB:
			case X86_INS_PSUBSW:
			case X86_INS_PSUBUSB:
			case X86_INS_PSUBUSW:
				op->type = R_ANAL_OP_TYPE_SUB;
				break;
			case X86_INS_AND:
			case X86_INS_ANDN:
			case X86_INS_ANDPD:
			case X86_INS_ANDPS:
			case X86_INS_ANDNPD:
			case X86_INS_ANDNPS:
				op->type = R_ANAL_OP_TYPE_AND;
				break;
			case X86_INS_DIV:
				op->type = R_ANAL_OP_TYPE_DIV;
				break;
			case X86_INS_MUL:
				op->type = R_ANAL_OP_TYPE_MUL;
				break;
			case X86_INS_INC:
			case X86_INS_ADD:
			case X86_INS_FADD:
			case X86_INS_ADDPD:
				op->type = R_ANAL_OP_TYPE_ADD;
				break;
			}
		}
		cs_free (insn, n);
		cs_close (&handle);
	}
	return op->size;
}
示例#7
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	csh handle;
#if USE_ITER_API
	static
#endif
	cs_insn *insn = NULL;
	int mode = (a->bits==64)? CS_MODE_64:
		(a->bits==32)? CS_MODE_32:
		(a->bits==16)? CS_MODE_16: 0;
	int n, ret = cs_open (CS_ARCH_X86, mode, &handle);
	int regsz = 4;

	if (ret != CS_ERR_OK) {
		return 0;
	}
	switch (a->bits) {
	case 64: regsz = 8; break;
	case 16: regsz = 2; break;
	default:
	case 32: regsz = 4; break;
	}
	memset (op, '\0', sizeof (RAnalOp));
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->src[0] = NULL;
	op->src[1] = NULL;
	op->size = 0;
	op->delay = 0;
	r_strbuf_init (&op->esil);
	cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
	// capstone-next
#if USE_ITER_API
	{
		ut64 naddr = addr;
		size_t size = len;
		if (insn == NULL)
			insn = cs_malloc (handle);
		n = cs_disasm_iter (handle, (const uint8_t**)&buf,
			&size, (uint64_t*)&naddr, insn);
	}
#else
	n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
#endif
	if (n<1) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else {
		int rs = a->bits/8;
		const char *pc = (a->bits==16)?"ip":
			(a->bits==32)?"eip":"rip";
		const char *sp = (a->bits==16)?"sp":
			(a->bits==32)?"esp":"rsp";
		const char *bp = (a->bits==16)?"bp":
			(a->bits==32)?"ebp":"rbp";
		op->size = insn->size;
		op->prefix = 0;
		switch (insn->detail->x86.prefix[0]) {
		case X86_PREFIX_REPNE:
			op->prefix |= R_ANAL_OP_PREFIX_REPNE;
		case X86_PREFIX_REP:
			op->prefix |= R_ANAL_OP_PREFIX_REP;
		case X86_PREFIX_LOCK:
			op->prefix |= R_ANAL_OP_PREFIX_LOCK;
		}
		switch (insn->id) {
		case X86_INS_FNOP:
		case X86_INS_NOP:
			op->type = R_ANAL_OP_TYPE_NOP;
			if (a->decode)
				esilprintf (op, ",");
			break;
		case X86_INS_HLT:
			op->type = R_ANAL_OP_TYPE_TRAP;
			break;
		case X86_INS_CLI:
		case X86_INS_STI:
		case X86_INS_CLC:
		case X86_INS_STC:
			break;
		// cmov
		case X86_INS_CMOVA:
		case X86_INS_CMOVAE:
		case X86_INS_CMOVB:
		case X86_INS_CMOVBE:
		case X86_INS_FCMOVBE:
		case X86_INS_FCMOVB:
		case X86_INS_CMOVE:
		case X86_INS_FCMOVE:
		case X86_INS_CMOVG:
		case X86_INS_CMOVGE:
		case X86_INS_CMOVL:
		case X86_INS_CMOVLE:
		case X86_INS_FCMOVNBE:
		case X86_INS_FCMOVNB:
		case X86_INS_CMOVNE:
		case X86_INS_FCMOVNE:
		case X86_INS_CMOVNO:
		case X86_INS_CMOVNP:
		case X86_INS_FCMOVNU:
		case X86_INS_CMOVNS:
		case X86_INS_CMOVO:
		case X86_INS_CMOVP:
		case X86_INS_FCMOVU:
		case X86_INS_CMOVS:
		// mov
		case X86_INS_MOV:
		case X86_INS_MOVZX:
		case X86_INS_MOVABS:
		case X86_INS_MOVHPD:
		case X86_INS_MOVHPS:
		case X86_INS_MOVLPD:
		case X86_INS_MOVLPS:
		case X86_INS_MOVBE:
		case X86_INS_MOVSB:
		case X86_INS_MOVSD:
		case X86_INS_MOVSQ:
		case X86_INS_MOVSS:
		case X86_INS_MOVSW:
		case X86_INS_MOVD:
		case X86_INS_MOVQ:
		case X86_INS_MOVDQ2Q:
			{
			op->type = R_ANAL_OP_TYPE_MOV;
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				}
				if (a->decode) {
					char *src = getarg (handle, insn, 1, 0);
					char *dst = getarg (handle, insn, 0, 1);
					esilprintf (op, "%s,%s", src, dst);
					free (src);
					free (dst);
				}
				break;
			default:
				if (a->decode) {
					char *src = getarg (handle, insn, 1, 0);
					char *dst = getarg (handle, insn, 0, 0);
					esilprintf (op, "%s,%s,=", src, dst);
					free (src);
					free (dst);
				}
				break;
			}
			switch (INSOP(1).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(1).mem.disp;
				op->refptr = INSOP(1).size;
				if (INSOP(1).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_GET;
					op->stackptr = regsz;
				}
				break;
			case X86_OP_IMM:
				if (INSOP(1).imm > 10)
					op->ptr = INSOP(1).imm;
				break;
			default:
				break;
			}
			}
			break;
		case X86_INS_SHL:
		case X86_INS_SHLD:
		case X86_INS_SHLX:
			op->type = R_ANAL_OP_TYPE_SHL;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,<<=,cz,%%z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAR:
		case X86_INS_SARX:
			op->type = R_ANAL_OP_TYPE_SAR;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,>>=,%%z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SAL:
		case X86_INS_SALC:
			op->type = R_ANAL_OP_TYPE_SAL;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,<<=,%%z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SHR:
		case X86_INS_SHRD:
		case X86_INS_SHRX:
			op->type = R_ANAL_OP_TYPE_SHR;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,>>=,cz,%%z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_CMP:
		case X86_INS_VCMP:
		case X86_INS_CMPPD:
		case X86_INS_CMPPS:
		case X86_INS_CMPSW:
		case X86_INS_CMPSD:
		case X86_INS_CMPSQ:
		case X86_INS_CMPSB:
		case X86_INS_CMPSS:
		case X86_INS_TEST:
			op->type = R_ANAL_OP_TYPE_CMP;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op,  "%s,%s,==,%%z,zf,=", src, dst);
				free (src);
				free (dst);
			}
			switch (INSOP(0).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(0).mem.disp;
				op->refptr = INSOP(0).size;
				if (INSOP(0).mem.base == X86_REG_RIP) {
					op->ptr += addr + insn->size;
				} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
					op->stackop = R_ANAL_STACK_SET;
					op->stackptr = regsz;
				}
				break;
			default:
				switch (INSOP(1).type) {
				case X86_OP_MEM:
					op->ptr = INSOP(1).mem.disp;
					op->refptr = INSOP(1).size;
					if (INSOP(1).mem.base == X86_REG_RIP) {
						op->ptr += addr + insn->size;
					} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
						op->stackop = R_ANAL_STACK_SET;
						op->stackptr = regsz;
					}
					break;
				case X86_OP_IMM:
					op->ptr = INSOP(1).imm;
					break;
				default:
					break;
				}
				break;
			}
			break;
		case X86_INS_LEA:
			op->type = R_ANAL_OP_TYPE_LEA;
			if (a->decode) {
				char *src = getarg (handle, insn, 0, 0);
				char *dst = getarg (handle, insn, 1, 2);
				esilprintf (op, "%s,%s,=", dst, src);
				free (src);
				free (dst);
			}
			switch (INSOP(1).type) {
			case X86_OP_MEM:
				op->ptr = INSOP(1).mem.disp;
				op->refptr = INSOP(1).size;
				switch (INSOP(1).mem.base) {
				case X86_REG_RIP:
					op->ptr += addr + op->size;
					break;
				case X86_REG_RBP:
				case X86_REG_EBP:
					op->stackop = R_ANAL_STACK_GET;
					op->stackptr = regsz;
					break;
				}
				break;
			case X86_OP_IMM:
				if (INSOP(1).imm > 10)
					op->ptr = INSOP(1).imm;
				break;
			default:
				break;
			}
			break;
		case X86_INS_ENTER:
		case X86_INS_PUSH:
		case X86_INS_PUSHAW:
		case X86_INS_PUSHAL:
		case X86_INS_PUSHF:
			{
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op,  "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs);
				free (dst);
			}
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->ptr = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_PUSH;
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UPUSH;
				break;
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = regsz;
			break;
		case X86_INS_LEAVE:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				esilprintf (op, "%s,%s,=,%s,[%d],%s,%d,%s,-=",
					bp, sp, sp, rs, bp, rs, sp);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_POP:
		case X86_INS_POPAW:
		case X86_INS_POPAL:
		case X86_INS_POPF:
		case X86_INS_POPCNT:
			op->type = R_ANAL_OP_TYPE_POP;
			if (a->decode) {
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op,
					"%s,[%d],%s,=,%d,%s,+=",
					sp, rs, dst, rs, sp);
				free (dst);
			}
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_RET:
		case X86_INS_RETF:
		case X86_INS_IRET:
		case X86_INS_IRETD:
		case X86_INS_IRETQ:
		case X86_INS_SYSRET:
			op->type = R_ANAL_OP_TYPE_RET;
			if (a->decode)
				esilprintf (op, "%s,[%d],%s,=,%d,%s,+=",
					sp, rs, pc, rs, sp);
			op->stackop = R_ANAL_STACK_INC;
			op->stackptr = -regsz;
			break;
		case X86_INS_INT:
			if (a->decode)
				esilprintf (op, "%d,$", (int)INSOP(0).imm);
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
		case X86_INS_INT1:
		case X86_INS_INT3:
		case X86_INS_INTO:
		case X86_INS_VMCALL:
		case X86_INS_VMMCALL:
		case X86_INS_SYSCALL:
			op->type = R_ANAL_OP_TYPE_TRAP;
			if (a->decode)
				esilprintf (op, "%d,$", (int)INSOP(0).imm);
			break;
		case X86_INS_JL:
		case X86_INS_JLE:
		case X86_INS_JA:
		case X86_INS_JAE:
		case X86_INS_JB:
		case X86_INS_JBE:
		case X86_INS_JCXZ:
		case X86_INS_JECXZ:
		case X86_INS_JRCXZ:
		case X86_INS_JO:
		case X86_INS_JNO:
		case X86_INS_JS:
		case X86_INS_JNS:
		case X86_INS_JP:
		case X86_INS_JNP:
		case X86_INS_JE:
		case X86_INS_JNE:
		case X86_INS_JG:
		case X86_INS_JGE:
		case X86_INS_LOOP:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = INSOP(0).imm;
			op->fail = addr+op->size;
			if (a->decode) {
				char *dst = getarg (handle, insn, 0, 2);
				switch (insn->id) {
				case X86_INS_JL:
					esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JLE:
					esilprintf (op, "of,sf,^,zf,|,%s,%s,=", dst, pc);
					break;
				case X86_INS_JA:
					esilprintf (op, "cf,!,zf,!,&,?{,%s,%s,=,}",dst, pc);
					break;
				case X86_INS_JAE:
					esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JB:
					esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JO:
					esilprintf (op, "of,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNO:
					esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JE:
					esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JGE:
					esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNE:
					esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JG:
					esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JS:
					esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNS:
					esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JP:
					esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JNP:
					esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JBE:
					esilprintf (op, "zf,cf,&,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JCXZ:
					esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JECXZ:
					esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc);
					break;
				case X86_INS_JRCXZ:
					esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc);
					break;
				}
				free (dst);
			}
			break;
		case X86_INS_CALL:
		case X86_INS_LCALL:
			switch (INSOP(0).type) {
			case X86_OP_IMM:
				op->type = R_ANAL_OP_TYPE_CALL;
				// TODO: what if UCALL?
				// TODO: use imm_size
				op->jump = INSOP(0).imm;
				op->fail = addr+op->size;
				break;
			case X86_OP_MEM:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				if (INSOP(0).mem.base == 0) {
					op->ptr = INSOP(0).mem.disp;
				}
				break;
			default:
				op->type = R_ANAL_OP_TYPE_UCALL;
				op->jump = UT64_MAX;
				break;
			}
			if (a->decode) {
				char* arg = getarg (handle, insn, 0, 1);
				esilprintf (op,
						"%d,%s,+,"
						"%d,%s,-=,%s,"
						"=[],"
						"%s,%s,=",
						op->size, pc,
						rs, sp, sp, arg, pc);
				free (arg);
			}
			break;
		case X86_INS_JMP:
		case X86_INS_LJMP:
			if (a->decode) {
				char *src = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,=", src, pc);
				free (src);
			}
			// TODO: what if UJMP?
			if (INSOP(0).type == X86_OP_IMM) {
				op->jump = INSOP(0).imm;
				op->type = R_ANAL_OP_TYPE_JMP;
				if (a->decode) {
					ut64 dst = INSOP(0).imm;
					esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
				}
			} else {
				op->type = R_ANAL_OP_TYPE_UJMP;
			}
			break;
		case X86_INS_IN:
		case X86_INS_INSW:
		case X86_INS_INSD:
		case X86_INS_INSB:
		case X86_INS_OUT:
		case X86_INS_OUTSB:
		case X86_INS_OUTSD:
		case X86_INS_OUTSW:
			op->type = R_ANAL_OP_TYPE_IO;
			break;
		case X86_INS_VXORPD:
		case X86_INS_VXORPS:
		case X86_INS_VPXORD:
		case X86_INS_VPXORQ:
		case X86_INS_VPXOR:
		case X86_INS_KXORW:
		case X86_INS_PXOR:
		case X86_INS_XOR:
			op->type = R_ANAL_OP_TYPE_XOR;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,^=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_OR:
			op->type = R_ANAL_OP_TYPE_OR;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,|=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_SUB:
		case X86_INS_DEC:
		case X86_INS_PSUBB:
		case X86_INS_PSUBW:
		case X86_INS_PSUBD:
		case X86_INS_PSUBQ:
		case X86_INS_PSUBSB:
		case X86_INS_PSUBSW:
		case X86_INS_PSUBUSB:
		case X86_INS_PSUBUSW:
			op->type = R_ANAL_OP_TYPE_SUB;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,-=,%%c,cf,=,%%z,zf,=,%%s,sf,=,%%o,of,=", src, dst); // TODO: update flags
				free (src);
				free (dst);
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = INSOP(1).imm;
				}
			}
			break;
		case X86_INS_AND:
		case X86_INS_ANDN:
		case X86_INS_ANDPD:
		case X86_INS_ANDPS:
		case X86_INS_ANDNPD:
		case X86_INS_ANDNPS:
			op->type = R_ANAL_OP_TYPE_AND;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,&=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_DIV:
			op->type = R_ANAL_OP_TYPE_DIV;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,/=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_MUL:
			op->type = R_ANAL_OP_TYPE_MUL;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,*=", src, dst);
				free (src);
				free (dst);
			}
			break;
		case X86_INS_INC:
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "1,%s,+=", dst);
				free (dst);
			}
			break;
		case X86_INS_ADD:
		case X86_INS_FADD:
		case X86_INS_ADDPD:
			op->type = R_ANAL_OP_TYPE_ADD;
			if (a->decode) {
				char *src = getarg (handle, insn, 1, 0);
				char *dst = getarg (handle, insn, 0, 0);
				esilprintf (op, "%s,%s,+=", src, dst);
				free (src);
				free (dst);
			}
			if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) {
				if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) {
					op->stackop = R_ANAL_STACK_INC;
					op->stackptr = -INSOP(1).imm;
				}
			}
			break;
		}
	}
#if !USE_ITER_API
	cs_free (insn, n);
#endif
	cs_close (&handle);
	return op->size;
}
示例#8
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
	static csh handle = 0;
	static int omode = -1, obits = -1;
	int n, ret;
	cs_insn *insn;
	int mode = (a->bits == 64) ? CS_MODE_64 : (a->bits == 32) ? CS_MODE_32 : 0;
	mode |= a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN;

	op->delay = 0;
	op->type = R_ANAL_OP_TYPE_NULL;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	if (a->cpu && strncmp (a->cpu, "vle", 3) == 0) {
		// vle is big-endian only
		if (!a->big_endian) {
			return -1;
		}
		ret = analop_vle (a, op, addr, buf, len);
		if (ret >= 0) {
			return op->size;
		}
	}

	if (mode != omode || a->bits != obits) {
		cs_close (&handle);
		handle = 0;
		omode = mode;
		obits = a->bits;
	}
	if (handle == 0) {
		ret = cs_open (CS_ARCH_PPC, mode, &handle);
		if (ret != CS_ERR_OK) {
			return -1;
		}
		cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
	}
	op->size = 4;

	r_strbuf_init (&op->esil);
	r_strbuf_set (&op->esil, "");

	// capstone-next
	n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
	if (n < 1) {
		op->type = R_ANAL_OP_TYPE_ILL;
	} else {
		opex (&op->opex, handle, insn);
		struct Getarg gop = {
			.handle = handle,
			.insn = insn,
			.bits = a->bits
		};
		op->size = insn->size;
		op->id = insn->id;
		switch (insn->id) {
#if CS_API_MAJOR >= 4
		case PPC_INS_CMPB:
#endif
		case PPC_INS_CMPD:
		case PPC_INS_CMPDI:
		case PPC_INS_CMPLD:
		case PPC_INS_CMPLDI:
		case PPC_INS_CMPLW:
		case PPC_INS_CMPLWI:
		case PPC_INS_CMPW:
		case PPC_INS_CMPWI:
			op->type = R_ANAL_OP_TYPE_CMP;
			op->sign = true;
			if (ARG (2)[0] == '\0') esilprintf (op, "%s,%s,-,0xff,&,cr0,=", ARG (1), ARG (0));
			else esilprintf (op, "%s,%s,-,0xff,&,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_MFLR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "lr,%s,=", ARG (0));
			break;
		case PPC_INS_MTLR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,lr,=", ARG (0));
			break;
		case PPC_INS_MR:
		case PPC_INS_LI:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s,=", ARG (1), ARG (0));
			break;
		case PPC_INS_LIS:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s0000,%s,=", ARG (1), ARG (0));
			break;
		case PPC_INS_CLRLWI:
			op->type = R_ANAL_OP_TYPE_AND;
			esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask32 (ARG (2), "0x1F"), ARG (0));
			break;
		case PPC_INS_RLWINM:
			op->type = R_ANAL_OP_TYPE_ROL;
			esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask32 (ARG (3), ARG (4)), ARG (0));
			break;
		case PPC_INS_SC:
			op->type = R_ANAL_OP_TYPE_SWI;
			esilprintf (op, "0,$");
			break;
		case PPC_INS_EXTSB:
			op->sign = true;
			op->type = R_ANAL_OP_TYPE_MOV;
			if (a->bits == 64) esilprintf (op, "%s,0x80,&,?{,0xFFFFFFFFFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
			else esilprintf (op, "%s,0x80,&,?{,0xFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
			break;
		case PPC_INS_EXTSH:
			op->sign = true;
			if (a->bits == 64) esilprintf (op, "%s,0x8000,&,?{,0xFFFFFFFFFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
			else esilprintf (op, "%s,0x8000,&,?{,0xFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
			break;
		case PPC_INS_EXTSW:
			op->sign = true;
			esilprintf (op, "%s,0x80000000,&,?{,0xFFFFFFFF00000000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
			break;
		case PPC_INS_SYNC:
		case PPC_INS_ISYNC:
		case PPC_INS_LWSYNC:
		case PPC_INS_MSYNC:
		case PPC_INS_PTESYNC:
		case PPC_INS_TLBSYNC:
		case PPC_INS_SLBIA:
		case PPC_INS_SLBIE:
		case PPC_INS_SLBMFEE:
		case PPC_INS_SLBMTE:
		case PPC_INS_EIEIO:
		case PPC_INS_NOP:
			op->type = R_ANAL_OP_TYPE_NOP;
			esilprintf (op, ",");
			break;
		case PPC_INS_STW:
		case PPC_INS_STWU:
		case PPC_INS_STWUX:
		case PPC_INS_STWX:
		case PPC_INS_STWCX:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[4]"));
			break;
		case PPC_INS_STWBRX:
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case PPC_INS_STB:
		case PPC_INS_STBU:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[1]"));
			break;
		case PPC_INS_STH:
		case PPC_INS_STHU:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[2]"));
			break;
		case PPC_INS_STD:
		case PPC_INS_STDU:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[8]"));
			break;
		case PPC_INS_LBZ:
#if CS_API_MAJOR >= 4
		case PPC_INS_LBZCIX:
#endif
		case PPC_INS_LBZU:
		case PPC_INS_LBZUX:
		case PPC_INS_LBZX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,%s,=", ARG2 (1, "[1]"), ARG (0));
			break;
		case PPC_INS_LD:
		case PPC_INS_LDARX:
#if CS_API_MAJOR >= 4
		case PPC_INS_LDCIX:
#endif
		case PPC_INS_LDU:
		case PPC_INS_LDUX:
		case PPC_INS_LDX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,%s,=", ARG2 (1, "[8]"), ARG (0));
			break;
		case PPC_INS_LDBRX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case PPC_INS_LFD:
		case PPC_INS_LFDU:
		case PPC_INS_LFDUX:
		case PPC_INS_LFDX:
		case PPC_INS_LFIWAX:
		case PPC_INS_LFIWZX:
		case PPC_INS_LFS:
		case PPC_INS_LFSU:
		case PPC_INS_LFSUX:
		case PPC_INS_LFSX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0));
			break;
		case PPC_INS_LHA:
		case PPC_INS_LHAU:
		case PPC_INS_LHAUX:
		case PPC_INS_LHAX:
		case PPC_INS_LHZ:
		case PPC_INS_LHZU:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,%s,=", ARG2 (1, "[2]"), ARG (0));
			break;
		case PPC_INS_LHBRX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case PPC_INS_LWA:
		case PPC_INS_LWARX:
		case PPC_INS_LWAUX:
		case PPC_INS_LWAX:
		case PPC_INS_LWZ:
#if CS_API_MAJOR >= 4
		case PPC_INS_LWZCIX:
#endif
		case PPC_INS_LWZU:
		case PPC_INS_LWZUX:
		case PPC_INS_LWZX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0));
			break;
		case PPC_INS_LWBRX:
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case PPC_INS_SLW:
		case PPC_INS_SLWI:
			op->type = R_ANAL_OP_TYPE_SHL;
			esilprintf (op, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_SRW:
		case PPC_INS_SRWI:
			op->type = R_ANAL_OP_TYPE_SHR;
			esilprintf (op, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_MULLI:
			op->sign = true;
		case PPC_INS_MULLW:
		case PPC_INS_MULLD:
			op->type = R_ANAL_OP_TYPE_MUL;
			esilprintf (op, "%s,%s,*,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_SUB:
		case PPC_INS_SUBC:
		case PPC_INS_SUBF:
		case PPC_INS_SUBFIC:
		case PPC_INS_SUBFZE:
			op->type = R_ANAL_OP_TYPE_SUB;
			esilprintf (op, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0));
			break;
		case PPC_INS_ADD:
		case PPC_INS_ADDI:
			op->sign = true;
			op->type = R_ANAL_OP_TYPE_ADD;
			esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_ADDC:
		case PPC_INS_ADDIC:
			op->type = R_ANAL_OP_TYPE_ADD;
			esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_ADDE:
		case PPC_INS_ADDIS:
		case PPC_INS_ADDME:
		case PPC_INS_ADDZE:
			op->type = R_ANAL_OP_TYPE_ADD;
			esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_MTSPR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s,=", ARG (1), PPCSPR (0));
			break;
		case PPC_INS_BCTR: // switch table here
			op->type = R_ANAL_OP_TYPE_UJMP;
			esilprintf (op, "ctr,pc,=");
			break;
		case PPC_INS_BCTRL: // switch table here
			op->type = R_ANAL_OP_TYPE_CALL;
			esilprintf (op, "pc,lr,=,ctr,pc,=");
			break;
		case PPC_INS_B:
		case PPC_INS_BC:
			op->jump = ARG (1)[0] == '\0' ? IMM (0) : IMM (1);
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->fail = addr + op->size;
			switch (insn->detail->ppc.bc) {
			case PPC_BC_LT:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "0,cr0,<,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "0,%s,<,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_LE:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "0,cr0,<=,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "0,%s,<=,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_EQ:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "0,cr0,==,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "0,%s,==,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_GE:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "0,cr0,>=,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "0,%s,>=,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_GT:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "0,cr0,>,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "0,%s,>,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_NE:
				if (ARG (1)[0] == '\0') {
					esilprintf (op, "cr0,?{,%s,pc,=,},", ARG (0));
				} else {
					esilprintf (op, "%s,?{,%s,pc,=,},", ARG (0), ARG (1));
				}
				break;
			case PPC_BC_INVALID:
				op->type = R_ANAL_OP_TYPE_JMP;
				esilprintf (op, "%s,pc,=", ARG (0));
			case PPC_BC_UN: // unordered
			case PPC_BC_NU: // not unordered
			case PPC_BC_SO: // summary overflow
			case PPC_BC_NS: // not summary overflow
			default:
				break;
			}
			break;
		case PPC_INS_BA:
			switch (insn->detail->ppc.operands[0].type) {
			case PPC_OP_CRX:
				op->type = R_ANAL_OP_TYPE_CJMP;
				op->fail = addr + op->size;
				break;
			case PPC_OP_REG:
				if (op->type == R_ANAL_OP_TYPE_CJMP) {
					op->type = R_ANAL_OP_TYPE_UCJMP;
				} else {
					op->type = R_ANAL_OP_TYPE_CJMP;
				}
				op->jump = IMM (1);
				op->fail = addr + op->size;
				//op->type = R_ANAL_OP_TYPE_UJMP;
			default:
				break;
			}
			break;
		case PPC_INS_BDNZ:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			esilprintf (op, "1,ctr,-=,ctr,?{,%s,pc,=,}", ARG (0));
			break;
		case PPC_INS_BDNZA:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDNZL:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDNZLA:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDNZLR:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->fail = addr + op->size;
			esilprintf (op, "1,ctr,-=,ctr,?{,lr,pc,=,},");
			break;
		case PPC_INS_BDNZLRL:
			op->fail = addr + op->size;
			op->type = R_ANAL_OP_TYPE_CJMP;
			break;
		case PPC_INS_BDZ:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			esilprintf (op, "1,ctr,-=,ctr,0,==,?{,%s,pc,=,}", ARG (0));
			break;
		case PPC_INS_BDZA:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDZL:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDZLA:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			break;
		case PPC_INS_BDZLR:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->fail = addr + op->size;
			esilprintf (op, "1,ctr,-=,ctr,0,==,?{,lr,pc,=,}");
			break;
		case PPC_INS_BDZLRL:
			op->type = R_ANAL_OP_TYPE_CJMP;
			op->fail = addr + op->size;
			break;
		case PPC_INS_BLR:
		case PPC_INS_BLRL:
		case PPC_INS_BCLR:
		case PPC_INS_BCLRL:
			op->type = R_ANAL_OP_TYPE_CRET;
			op->fail = addr + op->size;
			switch (insn->detail->ppc.bc) {
			case PPC_BC_INVALID:
				op->type = R_ANAL_OP_TYPE_RET;
				esilprintf (op, "lr,pc,=");
				break;
			case PPC_BC_LT:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "0,cr0,<,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "0,%s,<,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_LE:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "0,cr0,<=,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "0,%s,<=,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_EQ:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "0,cr0,==,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "0,%s,==,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_GE:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "0,cr0,>=,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "0,%s,>=,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_GT:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "0,cr0,>,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "0,%s,>,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_NE:
				if (ARG (0)[0] == '\0') {
					esilprintf (op, "cr0,?{,lr,pc,=,},");
				} else {
					esilprintf (op, "%s,?{,lr,pc,=,},", ARG (0));
				}
				break;
			case PPC_BC_UN: // unordered
			case PPC_BC_NU: // not unordered
			case PPC_BC_SO: // summary overflow
			case PPC_BC_NS: // not summary overflow
			default:
				break;
			}
			break;
		case PPC_INS_NOR:
			op->type = R_ANAL_OP_TYPE_NOR;
			esilprintf (op, "%s,%s,|,!,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_XOR:
		case PPC_INS_XORI:
			op->type = R_ANAL_OP_TYPE_XOR;
			esilprintf (op, "%s,%s,^,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_XORIS:
			op->type = R_ANAL_OP_TYPE_XOR;
			esilprintf (op, "16,%s,<<,%s,^,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_DIVD:
		case PPC_INS_DIVW:
			op->sign = true;
			op->type = R_ANAL_OP_TYPE_DIV;
			esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_DIVDU:
		case PPC_INS_DIVWU:
			op->type = R_ANAL_OP_TYPE_DIV;
			esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_BL:
		case PPC_INS_BLA:
			op->type = R_ANAL_OP_TYPE_CALL;
			op->jump = IMM (0);
			op->fail = addr + op->size;
			esilprintf (op, "pc,lr,=,%s,pc,=", ARG (0));
			break;
		case PPC_INS_TRAP:
			op->sign = true;
			op->type = R_ANAL_OP_TYPE_TRAP;
			break;
		case PPC_INS_AND:
		case PPC_INS_NAND:
		case PPC_INS_ANDI:
			op->type = R_ANAL_OP_TYPE_AND;
			esilprintf (op, "%s,%s,&,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_ANDIS:
			op->type = R_ANAL_OP_TYPE_AND;
			esilprintf (op, "16,%s,<<,%s,&,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_OR:
		case PPC_INS_ORI:
			op->type = R_ANAL_OP_TYPE_OR;
			esilprintf (op, "%s,%s,|,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_ORIS:
			op->type = R_ANAL_OP_TYPE_OR;
			esilprintf (op, "16,%s,<<,%s,|,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_MFPVR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "pvr,%s,=", ARG (0));
			break;
		case PPC_INS_MFSPR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,%s,=", PPCSPR (1), ARG (0));
			break;
		case PPC_INS_MFCTR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "ctr,%s,=", ARG (0));
			break;
		case PPC_INS_MFDCCR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "dccr,%s,=", ARG (0));
			break;
		case PPC_INS_MFICCR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "iccr,%s,=", ARG (0));
			break;
		case PPC_INS_MFDEAR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "dear,%s,=", ARG (0));
			break;
		case PPC_INS_MFMSR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "msr,%s,=", ARG (0));
			break;
		case PPC_INS_MTCTR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,ctr,=", ARG (0));
			break;
		case PPC_INS_MTDCCR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,dccr,=", ARG (0));
			break;
		case PPC_INS_MTICCR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,iccr,=", ARG (0));
			break;
		case PPC_INS_MTDEAR:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,dear,=", ARG (0));
			break;
		case PPC_INS_MTMSR:
		case PPC_INS_MTMSRD:
			op->type = R_ANAL_OP_TYPE_MOV;
			esilprintf (op, "%s,msr,=", ARG (0));
			break;
			// Data Cache Block Zero
		case PPC_INS_DCBZ:
			op->type = R_ANAL_OP_TYPE_STORE;
			esilprintf (op, "%s,%s", ARG (0), ARG2 (1, ",=[128]"));
			break;
		case PPC_INS_CLRLDI:
			op->type = R_ANAL_OP_TYPE_AND;
			esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask64 (ARG (2), "0x3F"), ARG (0));
			break;
		case PPC_INS_ROTLDI:
			op->type = R_ANAL_OP_TYPE_ROL;
			esilprintf (op, "%s,%s,<<<,%s,=", ARG (2), ARG (1), ARG (0));
			break;
		case PPC_INS_RLDCL:
		case PPC_INS_RLDICL:
			op->type = R_ANAL_OP_TYPE_ROL;
			esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (ARG (3), "0x3F"), ARG (0));
			break;
		case PPC_INS_RLDCR:
		case PPC_INS_RLDICR:
			op->type = R_ANAL_OP_TYPE_ROL;
			esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (0, ARG (3)), ARG (0));
			break;
		}
		if (a->fillval) {
			op_fillval (op, handle, insn);
		}
		r_strbuf_fini (&op->esil);
		cs_free (insn, n);
		//cs_close (&handle);
	}
	return op->size;
}

static int archinfo(RAnal *a, int q) {
	if (a->cpu && !strncmp (a->cpu, "vle", 3)) {
		return 2;
	}
	return 4;
}

RAnalPlugin r_anal_plugin_ppc_cs = {
	.name = "ppc",
	.desc = "Capstone PowerPC analysis",
	.license = "BSD",
	.esil = true,
	.arch = "ppc",
	.bits = 32 | 64,
	.archinfo = archinfo,
	.op = &analop,
	.set_reg_profile = &set_reg_profile,
};

#ifndef CORELIB
RLibStruct radare_plugin = {
	.type = R_LIB_TYPE_ANAL,
	.data = &r_anal_plugin_ppc_cs,
	.version = R2_VERSION
};