Beispiel #1
0
/* 
 * Save 4096 bytes from %esp
 * TODO: Add support for reverse stack architectures
 * Also known as r_debug_inject()
 */
R_API ut64 r_debug_execute(RDebug *dbg, const ut8 *buf, int len, int restore) {
	int orig_sz;
	ut8 stackbackup[4096];
	ut8 *backup, *orig = NULL;
	RRegItem *ri, *risp, *ripc;
	ut64 rsp, rpc, ra0 = 0LL;
	if (r_debug_is_dead (dbg))
		return R_FALSE;
	ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR);
	risp = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_SP], R_REG_TYPE_GPR);
	if (ripc) {
		r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
		orig = r_reg_get_bytes (dbg->reg, -1, &orig_sz);
		if (orig == NULL) {
			eprintf ("Cannot get register arena bytes\n");
			return 0LL;
		}
		rpc = r_reg_get_value (dbg->reg, ripc);
		rsp = r_reg_get_value (dbg->reg, risp);

		backup = malloc (len);
		if (backup == NULL) {
			free (orig);
			return 0LL;
		}
		dbg->iob.read_at (dbg->iob.io, rpc, backup, len);
		dbg->iob.read_at (dbg->iob.io, rsp, stackbackup, len);

		r_bp_add_sw (dbg->bp, rpc+len, dbg->bpsize, R_BP_PROT_EXEC);

		/* execute code here */
		dbg->iob.write_at (dbg->iob.io, rpc, buf, len);
	//r_bp_add_sw (dbg->bp, rpc+len, 4, R_BP_PROT_EXEC);
		r_debug_continue (dbg);
	//r_bp_del (dbg->bp, rpc+len);
		/* TODO: check if stopped in breakpoint or not */

		r_bp_del (dbg->bp, rpc+len);
		dbg->iob.write_at (dbg->iob.io, rpc, backup, len);
		if (restore) {
			dbg->iob.write_at (dbg->iob.io, rsp, stackbackup, len);
		}

		r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
		ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_A0], R_REG_TYPE_GPR);
		ra0 = r_reg_get_value (dbg->reg, ri);
		if (restore) {
			r_reg_set_bytes (dbg->reg, -1, orig, orig_sz);
		} else {
			r_reg_set_value (dbg->reg, ripc, rpc);
		}
		r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_TRUE);
		free (backup);
		free (orig);
		eprintf ("ra0=0x%08"PFMT64x"\n", ra0);
	} else eprintf ("r_debug_execute: Cannot get program counter\n");
	return (ra0);
}
Beispiel #2
0
// XXX: Do this work correctly?
static RList *backtrace_x86_64_anal(RDebug *dbg, ut64 at) {
	int i;
	ut8 buf[8];
	RDebugFrame *frame;
	ut64 ptr, ebp2 = UT64_MAX;
	ut64 _rip, _rbp;
	RList *list;
	RReg *reg = dbg->reg;
	RIOBind *bio = &dbg->iob;
	RAnalFunction *fcn;

	_rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR));
	if (at == UT64_MAX) {
		//_rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR));
		_rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR));
	} else {
		_rbp = at;
	}

	list = r_list_new ();
	list->free = free;
	bio->read_at (bio->io, _rip, (ut8*)&buf, 8);

	// TODO : frame->size by using esil to emulate first instructions
	fcn = r_anal_get_fcn_in (dbg->anal, _rip, R_ANAL_FCN_TYPE_NULL);
	if (fcn) {
		frame = R_NEW0 (RDebugFrame);
		frame->addr = _rip;
		frame->size = 0;
		frame->sp = _rbp;
		frame->bp = _rbp + 8; // XXX
		r_list_append (list, frame);
	}

	for (i=1; i<dbg->btdepth; i++) {
		// TODO: make those two reads in a shot
		bio->read_at (bio->io, _rbp, (ut8*)&ebp2, 8);
		if (ebp2 == UT64_MAX)
			break;
		bio->read_at (bio->io, _rbp+8, (ut8*)&ptr, 8);
		if (!ptr || !_rbp)
			break;
		//fcn = r_anal_get_fcn_in (dbg->anal, ptr, R_ANAL_FCN_TYPE_NULL);
		frame = R_NEW0 (RDebugFrame);
		frame->addr = ptr;
		frame->size = 0;
		frame->sp = _rbp;
		frame->bp = _rbp + 8;
		//frame->name = (fcn && fcn->name) ? strdup (fcn->name) : NULL;
		r_list_append (list, frame);
		_rbp = ebp2;
	}

	return list;
}
Beispiel #3
0
static RList *backtrace_x86_64(RDebug *dbg, ut64 at) {
	int i;
	ut8 buf[8];
	RDebugFrame *frame;
	ut64 ptr, ebp2;
	ut64 _rip, _rsp, _rbp = 0;
	RList *list;
	RReg *reg = dbg->reg;
	RIOBind *bio = &dbg->iob;

	_rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR));
	if (at == UT64_MAX) {
		_rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR));
		_rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR));
	} else {
		_rsp = _rbp = at;
	}

	list = r_list_new ();
	list->free = free;
	bio->read_at (bio->io, _rip, (ut8*)&buf, 8);
	/* %rbp=old rbp, %rbp+4 points to ret */
	/* Plugin before function prelude: push %rbp ; mov %rsp, %rbp */
	if (!memcmp (buf, "\x55\x89\xe5", 3) || !memcmp (buf, "\x89\xe5\x57", 3)) {
		if (!bio->read_at (bio->io, _rsp, (ut8*)&ptr, 8)) {
			eprintf ("read error at 0x%08"PFMT64x"\n", _rsp);
			r_list_purge (list);
			free (list);
			return false;
		}
		frame = R_NEW0 (RDebugFrame);
		frame->addr = ptr;
		frame->size = 0; // TODO ?
		r_list_append (list, frame);
		_rbp = ptr;
	}

	for (i=1; i<dbg->btdepth; i++) {
		// TODO: make those two reads in a shot
		bio->read_at (bio->io, _rbp, (ut8*)&ebp2, 8);
		if (ebp2 == UT64_MAX)
			break;
		bio->read_at (bio->io, _rbp+8, (ut8*)&ptr, 8);
		if (!ptr || !_rbp)
			break;
		frame = R_NEW0 (RDebugFrame);
		frame->addr = ptr;
		frame->size = 0; // TODO ?
		r_list_append (list, frame);
		_rbp = ebp2;
	}
	return list;
}
Beispiel #4
0
/* restore program counter after breakpoint hit */
static int r_debug_recoil(RDebug *dbg) {
	int recoil;
	RRegItem *ri;
	if (r_debug_is_dead (dbg))
		return R_FALSE;
	r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
	ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], -1);
	dbg->reason.bpi = NULL;
	if (ri) {
		ut64 addr = r_reg_get_value (dbg->reg, ri);
		recoil = r_bp_recoil (dbg->bp, addr);
		//eprintf ("[R2] Breakpoint recoil at 0x%"PFMT64x" = %d\n", addr, recoil);
#if __arm__
		if (recoil<1) recoil = 0; // XXX Hack :D
#else
		if (recoil<1) recoil = 0; //1; // XXX Hack :D (x86 only?)
#endif
		if (recoil) {
			dbg->reason.type = R_DEBUG_REASON_BREAKPOINT;
			dbg->reason.bpi = r_bp_get_at (dbg->bp, addr-recoil);
			dbg->reason.addr = addr - recoil;
			r_reg_set_value (dbg->reg, ri, addr-recoil);
			if (r_reg_get_value (dbg->reg, ri) != (addr-recoil)) {
				eprintf ("r_debug_recoil: Cannot set program counter\n");
				return R_FALSE;
			}
			r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_TRUE);
			//eprintf ("[BP Hit] Setting pc to 0x%"PFMT64x"\n", (addr-recoil));
			return R_TRUE;
		}
	} else eprintf ("r_debug_recoil: Cannot get program counter\n");
	return R_FALSE;
}
Beispiel #5
0
/* restore program counter after breakpoint hit */
static int r_debug_recoil(RDebug *dbg) {
	int recoil;
	RRegItem *ri;
	if (r_debug_is_dead (dbg)) {
		return false;
	}
	r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
	ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], -1);
	dbg->reason.bpi = NULL;
	if (ri) {
		ut64 addr = r_reg_get_value (dbg->reg, ri);
		recoil = r_bp_recoil (dbg->bp, addr - dbg->bpsize);
		//eprintf ("[R2] Breakpoint recoil at 0x%"PFMT64x" = %d\n", addr, recoil);
		if (recoil < 1)
			recoil = 0; // XXX Hack :D
		if (recoil) {
			dbg->in_recoil = true;
			dbg->reason.type = R_DEBUG_REASON_BREAKPOINT;
			dbg->reason.bpi = r_bp_get_at (dbg->bp, addr-recoil);
			dbg->reason.addr = addr - recoil;
			r_reg_set_value (dbg->reg, ri, addr-recoil);
			if (r_reg_get_value (dbg->reg, ri) != (addr-recoil)) {
				eprintf ("r_debug_recoil: Cannot set program counter\n");
				return false;
			}
			r_debug_reg_sync (dbg, R_REG_TYPE_GPR, true);
			//eprintf ("[BP Hit] Setting pc to 0x%"PFMT64x"\n", (addr-recoil));
			return true;
		}
	} else {
		eprintf ("r_debug_recoil: Cannot get program counter\n");
	}
	return false;
}
Beispiel #6
0
static const char *parse_def(RReg *reg, char **tok, const int n) {
	RRegItem *item;
	char *end;
	int type;

	if (n != 5 && n != 6)
		return "Invalid syntax";

	type = r_reg_type_by_name (tok[0]);
	if (type < 0) {
		return "Invalid register type";
	}

	item = R_NEW0 (RRegItem);
	if (!item) return "Unable to allocate memory";

	item->type = type;
	item->name = strdup (tok[1]);
	// All the numeric arguments are strictly checked
	item->size = parse_size (tok[2], &end);
	if (*end != '\0' || !item->size) {
		r_reg_item_free (item);
		return "Invalid size";
	}
	item->offset = parse_size (tok[3], &end);
	if (*end != '\0') {
		r_reg_item_free (item);
		return "Invalid offset";
	}
	item->packed_size = parse_size (tok[4], &end);
	if (*end != '\0') {
		r_reg_item_free (item);
		return "Invalid packed size";
	}

	// Dynamically update the list of supported bit sizes
	reg->bits |= item->size;

	// This is optional
	if (n == 6)
		item->flags = strdup (tok[5]);

	// Don't allow duplicate registers
	if (r_reg_get (reg, item->name, R_REG_TYPE_ALL)) {
		r_reg_item_free (item);
		return "Duplicate register definition";
	}
	/* Hack to put flags in the same arena as gpr */
	if (type == R_REG_TYPE_FLG) {
		type = R_REG_TYPE_GPR;
	}

	r_list_append (reg->regset[item->type].regs, item);

	// Update the overall profile size
	if (item->offset + item->size > reg->size) {
		reg->size = item->offset + item->size;
	}
	return NULL;
}
Beispiel #7
0
/* io.mem_base = reg1; io.mem_index = reg2; io.disp = 0x0ff */
static RAnalValue *anal_fill_ai_mm(RAnal *anal, x86im_instr_object io) {
	RAnalValue *ret = r_anal_value_new ();
	st64 disp = r_hex_bin_truncate (io.disp, io.disp_size);
	ret->memref = anal->bits/8;
	if (io.mem_base == 0) {
		ret->base = disp;
	} else {
		ret->reg = r_reg_get (anal->reg,
				anal_reg (io.mem_base), R_REG_TYPE_GPR);
		ret->delta = disp;
		if (io.mem_index != 0)
			ret->regdelta = r_reg_get (anal->reg,
					anal_reg (io.mem_index), R_REG_TYPE_GPR);
	}
	return ret;
}
Beispiel #8
0
static int reil_cmp(RAnalEsil *esil) {
	RAnalReilInst *ins;
	char tmp_buf[REGBUFSZ];
	RAnalReilArg *op2, *op1;

	op2 = reil_pop_arg(esil);
	if (!op2) return false;
	op1 = reil_pop_arg(esil);
	if (!op1) {
		R_FREE (op2);
		return false;
	}

	ins = R_NEW0 (RAnalReilInst);
	if (!ins) {
		R_FREE (op1);
		R_FREE (op2);
		return false;
	}
	ins->opcode = REIL_EQ;
	ins->arg[0] = op2;
	ins->arg[1] = op1;
	ins->arg[2] = R_NEW0(RAnalReilArg);
	if (!ins->arg[2]) {
		reil_free_inst (ins);
		return false;
	}
	get_next_temp_reg(esil, tmp_buf);
	reil_make_arg(esil, ins->arg[2], tmp_buf);
	ins->arg[2]->size = 1;
	reil_print_inst(esil, ins);
	// Set vars needed to determine flags.
	snprintf(esil->Reil->cur, sizeof(esil->Reil->old) - 1, "%s:%d",
			ins->arg[2]->name, ins->arg[2]->size);
	snprintf(esil->Reil->old, sizeof(esil->Reil->cur) - 1, "%s:%d", op2->name,
			op2->size);

	if (r_reg_get(esil->anal->reg, op2->name, -1)) {
		esil->Reil->lastsz = op2->size;
	} else if (r_reg_get(esil->anal->reg, op1->name, -1)) {
		esil->Reil->lastsz = op1->size;
	}

	reil_push_arg(esil, ins->arg[2]);
	reil_free_inst(ins);
	return true;
}
Beispiel #9
0
static ut64 esil_get (RAnalEsil *e, const char *s) {
	RRegItem *item;
	// check for register
	if (!s) return 0LL;
	item = r_reg_get (e->anal->reg, s, 0); // GPR only wtf?
	if (item) return r_reg_get_value (e->anal->reg, item);
	return r_num_get (NULL, s);
}
Beispiel #10
0
static void ios_hwstep_enable32 (RDebug *dbg, task_t port, int enable) {
	int i;
	static ARMDebugState32 olds;
	ARMDebugState32 ds;

	mach_msg_type_number_t count = ARM_DEBUG_STATE32_COUNT;
	(void) thread_get_state (port,
	  		ARM_DEBUG_STATE32,
			(thread_state_t)&ds,
			&count);

	//static ut64 chainstep = UT64_MAX;
	if (enable) {
		RIOBind *bio = &dbg->iob;
		ut32 pc = r_reg_get_value (dbg->reg,
		  r_reg_get (dbg->reg, "pc", R_REG_TYPE_GPR));
		ut32 cpsr = r_reg_get_value (dbg->reg,
		  r_reg_get (dbg->reg, "cpsr", R_REG_TYPE_GPR));

		for (i = 0; i < 16 ; i++) {
			ds.bcr[i] = ds.bvr[i] = 0;
		}
		olds = ds;
		//chainstep = UT64_MAX;
		// state = old_state;
		ds.bvr[i] = pc & (UT32_MAX >> 2) << 2;
		ds.bcr[i] = BCR_M_IMVA_MISMATCH | S_USER | BCR_ENABLE;
		if (cpsr & 0x20) {
			ut16 op;
			if (pc & 2) {
				ds.bcr[i] |= BAS_IMVA_2_3;
			} else {
				ds.bcr[i] |= BAS_IMVA_0_1;
			}
			/* check for thumb */
			bio->read_at (bio->io, pc, (void *)&op, 2);
			if (isThumb32 (op)) {
				eprintf ("Thumb32 chain stepping not supported yet\n");
				//chainstep = pc + 2;
			} else {
				ds.bcr[i] |= BAS_IMVA_ALL;
			}
		} else {
			ds.bcr[i] |= BAS_IMVA_ALL;
		}
	} else {
Beispiel #11
0
int gb_write(emu *e, ut64 addr, ut8 *buf, ut32 len)
{
	if(0x2000 <= addr && addr < 0x4000) {
		if(buf[0] == 0x20 || buf[0] == 0x40 || buf[0] == 0x60)
			return r_reg_set_value(e->reg, r_reg_get(e->reg, "mbcrom", -1), 0);
		if(!buf[0])
			return r_reg_set_value(e->reg, r_reg_get(e->reg, "mbcrom", -1), 0);
		return r_reg_set_value(e->reg, r_reg_get(e->reg, "mbcrom", -1), buf[0]-1);
	}
	if(0x4000 <= addr && addr < 0x6000) {
		if(!buf[0])
			return r_reg_set_value(e->reg, r_reg_get(e->reg, "mbcram", -1), 0);
		return r_reg_set_value(e->reg, r_reg_get(e->reg, "mbcram", -1), buf[0]-1);
	}
	if(0xa000 <= addr && addr < 0xc000)
		return emu_write(e, addr + (r_reg_getv(e->reg, "mbcram") << 16), buf, len);
	return emu_write(e, addr, buf, len);
}
Beispiel #12
0
int reg_write(RAnalEsil *esil, const char *regname, ut64 num) {
	RRegItem *reg = r_reg_get (esil->anal->reg, regname, -1);
	if (reg) {
		if (num)
			r_reg_set_value (esil->anal->reg, reg,num);
		return 1;
	}
	return 0;
}
Beispiel #13
0
static int esil_set (RAnalEsil *e, const char *s, ut64 n) {
	if (e->anal && e->anal->reg) {
		RRegItem *item;
		item = r_reg_get (e->anal->reg, s, 0); // GPR only wtf?
		eprintf ("SET (%p)\n", item);
		if (item) return r_reg_set_value (e->anal->reg, item, n);
	}
	return R_TRUE;
}
int reg_read(RAnalEsil *esil, const char *regname, ut64 *num) {
	RRegItem *reg = r_reg_get (esil->anal->reg, regname, -1);
	if (reg) {
		if (num)
			*num = r_reg_get_value (esil->anal->reg, reg);
		return 1;
	}
	return 0;
}
Beispiel #15
0
// Get size of a register.
static ut8 esil_internal_sizeof_reg(RAnalEsil *esil, const char *r) {
	RRegItem *i;
	if (!esil || !esil->anal || !esil->anal->reg || !r)
		return false;
	i = r_reg_get(esil->anal->reg, r, -1);
	if (!i)
		return false;
	return (ut8)i->size;
}
Beispiel #16
0
static ut32 i8051_reg_read (RReg *reg, const char *regname) {
	if (reg) {
		RRegItem *item = r_reg_get (reg, regname, R_REG_TYPE_GPR);
		if (item) {
			return r_reg_get_value (reg, item);
		}
	}
	return 0;
}
Beispiel #17
0
R_API boolt r_anal_cc_update (RAnal *anal, RAnalCC *cc, RAnalOp *op) {
	RRegItem *it;
	cc->off = op->addr;
	switch (op->type) {
	case R_ANAL_OP_TYPE_CALL:
	case R_ANAL_OP_TYPE_UCALL:
		cc->type = R_ANAL_CC_TYPE_STDCALL;
		// TODO: check if next instruction after call is restoring stack
		cc->jump = op->jump;
		return R_FALSE;
	case R_ANAL_OP_TYPE_SWI: // syscall
		cc->type = R_ANAL_CC_TYPE_FASTCALL;
		cc->off = op->jump;
		cc->jump = op->val; // syscall number
		return R_FALSE;
	case R_ANAL_OP_TYPE_XOR:
		if (op->src[0] && op->src[0]->reg && op->dst && op->dst->reg && op->dst->reg->name) {
			char *n1 = op->dst->reg->name;
			char *n2 = op->src[0]->reg->name;
			// XXX: must handle XOR operation properly
			// if n1 == n2 then set to 0
			if (!strcmp (n1, n2)) {
				it = r_reg_get (anal->reg, n1, R_REG_TYPE_GPR);
				r_reg_set_value (anal->reg, it, 0);
			}
		}
		return R_TRUE;
	case R_ANAL_OP_TYPE_MOV:
		if (op->dst && op->dst->reg) {
			it = r_reg_get (anal->reg, op->dst->reg->name, R_REG_TYPE_GPR);
			if (it && op->src[0])
				r_reg_set_value (anal->reg, it, op->src[0]->imm);
		}
		return R_TRUE;
	case R_ANAL_OP_TYPE_PUSH:
	case R_ANAL_OP_TYPE_UPUSH: // add argument
		cc->nargs ++;
		if (cc->nargs>0 && cc->nargs < R_ANAL_CC_ARGS)
			cc->args[cc->nargs] = op->val;
		return R_TRUE;
	}
	// must update internal stuff to recognize parm
	return R_TRUE;
}
Beispiel #18
0
static bool i8051_reg_write (RReg *reg, const char *regname, ut32 num) {
	if (reg) {
		RRegItem *item = r_reg_get (reg, regname, R_REG_TYPE_GPR);
		if (item) {
			r_reg_set_value (reg, item, num);
			return true;
		}
	}
	return false;
}
Beispiel #19
0
R_API int r_debug_continue_until(RDebug *dbg, ut64 addr) {
// TODO: use breakpoint+continue... more efficient
	RRegItem *ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR);
	int n = 0;
	ut64 pc = r_reg_get_value (dbg->reg, ripc);
	while (pc != addr && !r_debug_is_dead (dbg)) {
		r_debug_step (dbg, 1);
		// TODO: obey breakpoints too?
	/* TODO: check if the debugger stops at the right address */
		pc = r_reg_get_value (dbg->reg, ripc);
		n++;
	}
	return n;
}
Beispiel #20
0
int gb_set_reg_profile(emu *e)
{
	int ret = r_anal_set_reg_profile (e->anal);
	e->reg = e->anal->reg;
	r_reg_set_value (e->reg, r_reg_get (e->reg,"mpc",-1), ((RBinAddr *) r_list_get_n (r_bin_get_entries (e->bin), 0))->offset);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"sp",-1), 0xfffe);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"af",-1), 0x01b0);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"bc",-1), 0x0013);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"de",-1), 0x00d8);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"hl",-1), 0x014d);
	r_reg_set_value (e->reg, r_reg_get (e->reg,"ime",-1), R_TRUE);
	return ret;
}
Beispiel #21
0
static int esil_6502_init (RAnalEsil *esil) {
	if (esil->anal && esil->anal->reg) {		//initial values
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "pc", -1), 0x0000);
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "sp", -1), 0xff);
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "a", -1), 0x00);
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "x", -1), 0x00);
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "y", -1), 0x00);
		r_reg_set_value (esil->anal->reg, r_reg_get (esil->anal->reg, "flags", -1), 0x00);
	}
	return true;
}
Beispiel #22
0
static int r_debug_gdb_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
	check_connection (dbg);
	if (!reg_buf) {
		// we cannot write registers before we once read them
		return -1;
	}
	int buflen = 0;
	int bits = dbg->anal->bits;
	const char *pcname = r_reg_get_name (dbg->anal->reg, R_REG_NAME_PC);
	RRegItem *reg = r_reg_get (dbg->anal->reg, pcname, 0);
	if (reg) {
		if (dbg->anal->bits != reg->size)
			bits = reg->size;
	}
	free (r_reg_get_bytes (dbg->reg, type, &buflen));
	// some implementations of the gdb protocol are acting weird.
	// so winedbg is not able to write registers through the <G> packet
	// and also it does not return the whole gdb register profile after
	// calling <g>
	// so this workaround resizes the small register profile buffer
	// to the whole set and fills the rest with 0
	if (buf_size < buflen) {
		ut8* new_buf = realloc (reg_buf, buflen * sizeof (ut8));
		if (!new_buf) {
			return -1;
		}
		reg_buf = new_buf;
		memset (new_buf + buf_size, 0, buflen - buf_size);
	}

	RRegItem* current = NULL;
	for (;;) {
		current = r_reg_next_diff (dbg->reg, type, reg_buf, buflen, current, bits);
		if (!current) break;
		ut64 val = r_reg_get_value (dbg->reg, current);
		int bytes = bits / 8;
		gdbr_write_reg (desc, current->name, (char*)&val, bytes);
	}
	return true;
}
Beispiel #23
0
//= PC+4+R<reg>
static RAnalValue *anal_regrel_jump(RAnal* anal, RAnalOp* op, ut8 reg){
	RAnalValue *ret = r_anal_value_new ();
	ret->reg = r_reg_get (anal->reg, regs[reg], R_REG_TYPE_GPR);
	ret->base = op->addr+4;
	return ret;
}
Beispiel #24
0
/* @(R0,Rx) references for all sizes */
static RAnalValue *anal_fill_r0_reg_ref(RAnal *anal, int reg, st64 size){
	RAnalValue *ret = anal_fill_ai_rg (anal, 0);
	ret->regdelta = r_reg_get (anal->reg, regs[reg], R_REG_TYPE_GPR);
	ret->memref = size;
	return ret;
}
Beispiel #25
0
static RAnalValue *anal_fill_ai_rg(RAnal *anal, int idx) {
        RAnalValue *ret = r_anal_value_new ();
        ret->reg = r_reg_get (anal->reg, regs[idx], R_REG_TYPE_GPR);
        return ret;
}
Beispiel #26
0
int gb_step (emu *e, ut8 *buf)
{
	int ret = R_FALSE;
	GBCpuStats *cpu = (GBCpuStats *)e->data;
	cpu->cycles += e->anop->cycles;
	r_reg_set_value (e->reg, r_reg_get (e->reg, "pc", -1), r_reg_getv(e->reg, "pc") + e->op->size);
	switch (e->anop->type) {
		case R_ANAL_OP_TYPE_NOP:
			ret = R_TRUE;
		case R_ANAL_OP_TYPE_TRAP:
		case R_ANAL_OP_TYPE_ILL:
			break;
		case R_ANAL_OP_TYPE_MOV:
			ret = gb_mov (e);
			break;
		case R_ANAL_OP_TYPE_PUSH:
			ret = gb_push (e);
			break;
		case R_ANAL_OP_TYPE_POP:
			ret = gb_pop (e);
			break;
		case R_ANAL_OP_TYPE_JMP:
			ret = gb_jmp (e);
			break;
		case R_ANAL_OP_TYPE_CJMP:
			ret = gb_cjmp (e);
			break;
		case R_ANAL_OP_TYPE_UJMP:
			ret = gb_ujmp (e);
			break;
		case R_ANAL_OP_TYPE_UCALL:
		case R_ANAL_OP_TYPE_CALL:
			ret = gb_call (e);
			break;
		case R_ANAL_OP_TYPE_CCALL:
			ret = gb_ccall (e);
			break;
		case R_ANAL_OP_TYPE_RET:
			ret = gb_ret (e);
			break;
		case R_ANAL_OP_TYPE_CRET:
			ret = gb_cret (e);
			break;
		case R_ANAL_OP_TYPE_CMP:
			ret = gb_cp (e);
			break;
		case R_ANAL_OP_TYPE_SUB:
			ret = gb_sub (e);
			break;
		case R_ANAL_OP_TYPE_ADD:
			ret = gb_add (e);
			break;
		case R_ANAL_OP_TYPE_XOR:
			ret = gb_xor (e);
			break;
		case R_ANAL_OP_TYPE_AND:
			ret = gb_and (e);
			break;
		case R_ANAL_OP_TYPE_OR:
			ret = gb_or (e);
			break;
		case R_ANAL_OP_TYPE_ACMP:
			ret = gb_bit (e);
			break;
		case R_ANAL_OP_TYPE_ROL:
			ret = gb_rol (e);
			break;
		case R_ANAL_OP_TYPE_STORE:
			ret = gb_store (e);
			break;
		case R_ANAL_OP_TYPE_LOAD:
			ret = gb_load (e);
			break;
	}
	gb_interrupts (e);
	cpu->cycles &= 0xffffff;	//prevent overflows
	cpu->prev_cycles = cpu->cycles;
	return ret;
}
Beispiel #27
0
// XXX: RVM must be inside RAnal ???? imho no. rsyscall must provide ret reg info
//XXX: may overflow. this is vulnerable. needs fix
R_API char *r_anal_cc_to_string (RAnal *anal, RAnalCC* cc) {
	RSyscallItem *si;
	RAnalFunction *fcn;
	char str[1024], buf[64];
	int i, eax = 0; // eax = arg0
	int str_len = 0;
	int buf_len = 0;

	str[0] = 0;
	switch (cc->type) {
	case R_ANAL_CC_TYPE_FASTCALL: // INT
		{
		RRegItem *item;
		const char *a0 = r_reg_get_name (anal->reg, R_REG_NAME_A0); // A0 or RET ??
		item = r_reg_get (anal->reg, a0, R_REG_TYPE_GPR);
		if (!item) {
			//eprintf ("cannot get reg a0\n");
			return R_FALSE;
		}
		eax = (int)r_reg_get_value (anal->reg, item);
		si = r_syscall_get (anal->syscall, eax, (int)cc->jump);
		if (si) {
			//DEBUG r_cons_printf (" ; sc[0x%x][%d]=%s(", (int)analop.value, eax, si->name);
			snprintf (str, sizeof (str), "%s (", si->name);
			for (i=0; i<si->args; i++) {
				const char *reg = r_syscall_reg (anal->syscall, i+1, si->args);
				if (!reg) break; // no registers?
				item = r_reg_get (anal->reg, reg, R_REG_TYPE_GPR);
				if (item) {
					snprintf (buf, sizeof (buf), "0x%"PFMT64x, r_reg_get_value (anal->reg, item));
					strcat (str, buf); // XXX: do not use strcat
				} //else eprintf ("Unknown reg '%s'\n", reg);
				if (i<si->args-1)
					strcat (str, ","); // XXX: do not use strcat
			}
			strcat (str, ")");
		} else {
			int n = (int)cc->jump;
			//if (n == 3) return NULL; // XXX: hack for x86
			snprintf (str, sizeof (str), "syscall[0x%x][%d]=?", n, eax);
		}
		}
		break;
	case R_ANAL_CC_TYPE_STDCALL: // CALL
		fcn = r_anal_fcn_find (anal, cc->jump,
				R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM|R_ANAL_FCN_TYPE_IMP);
		if (fcn && fcn->name)
			snprintf (str, sizeof (str), "%s(", fcn->name);
		else if (cc->jump != -1LL)
			snprintf (str, sizeof (str), "0x%08"PFMT64x"(", cc->jump);
		else strncpy (str, "unk(", sizeof (str)-1);
		str_len = strlen (str);
		if (fcn) cc->nargs = (fcn->nargs>cc->nargs?fcn->nargs:cc->nargs);
		if (cc->nargs>8) {
			//eprintf ("too many arguments for stdcall. chop to 8\n");
			cc->nargs = 8;
		}
		// TODO: optimize string concat
		for (i=0; i<cc->nargs; i++) {
			if (cc->args[cc->nargs-i] != -1LL)
				 snprintf (buf, sizeof (buf),
					"0x%"PFMT64x, cc->args[cc->nargs-i]);
			else strncpy (buf, "unk", sizeof (buf)-1);
			buf_len = strlen (buf);
			if ((buf_len+str_len+5)>=sizeof (str)) {
				strcat (str, "...");
				break;
			}
			strcat (str, buf);
			str_len += buf_len;
			if (i<cc->nargs-1) strcat (str, ", ");
		}
		strcat (str, ")");
		break;
	}
	return strdup (str);
}
Beispiel #28
0
static const char *parse_def(RReg *reg, char **tok, const int n) {
	RRegItem *item;
	char *end, *p;
	int type, type2;

	if (n != 5 && n != 6) {
		return "Invalid syntax: Wrong number of columns";
	}
	p = strchr (tok[0], '@');
	if (p) {
		char *tok0 = strdup (tok[0]);
		char *at = tok0 + (p - tok[0]);
		*at++ = 0;
		type = r_reg_type_by_name (tok0);
		type2 = r_reg_type_by_name (at);
		free (tok0);
	} else {
		type2 = type = r_reg_type_by_name (tok[0]);
		if (type == R_REG_TYPE_FLG) {
			type2 = R_REG_TYPE_GPR;
		}
	}
	if (type < 0 || type2 < 0) {
		return "Invalid register type";
	}

	item = R_NEW0 (RRegItem);
	if (!item) {
		return "Unable to allocate memory";
	}

	item->type = type;
	item->arena = type2;
	item->name = strdup (tok[1]);
	// All the numeric arguments are strictly checked
	item->size = parse_size (tok[2], &end);
	if (*end != '\0' || !item->size) {
		r_reg_item_free (item);
		return "Invalid size";
	}
	item->offset = parse_size (tok[3], &end);
	if (*end != '\0') {
		r_reg_item_free (item);
		return "Invalid offset";
	}
	item->packed_size = parse_size (tok[4], &end);
	if (*end != '\0') {
		r_reg_item_free (item);
		return "Invalid packed size";
	}

	// Dynamically update the list of supported bit sizes
	reg->bits |= item->size;

	// This is optional
	if (n == 6) {
		item->flags = strdup (tok[5]);
	}

	// Don't allow duplicate registers
	if (r_reg_get (reg, item->name, R_REG_TYPE_ALL)) {
		r_reg_item_free (item);
		return "Duplicate register definition";
	}
	/* Hack to put flags in the same arena as gpr */
	if (type == R_REG_TYPE_FLG) {
		type2 = R_REG_TYPE_GPR;
	}

	r_list_append (reg->regset[type2].regs, item);

	// Update the overall profile size
	if (item->offset + item->size > reg->size) {
		reg->size = item->offset + item->size;
	}
	// Update the overall type of registers into a regset
	reg->regset[type2].maskregstype |= ((int)1 << type);
	return NULL;
}
Beispiel #29
0
/* io.rop[0] = reg */
static RAnalValue *anal_fill_ai_rg(RAnal *anal, x86im_instr_object io, int idx) {
	RAnalValue *ret = r_anal_value_new ();
	ret->reg = r_reg_get (anal->reg,
			anal_reg (io.rop[idx]), R_REG_TYPE_GPR);
	return ret;
}
Beispiel #30
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;
}