Exemplo n.º 1
0
Result Stream_InitStr(Stream* pfStream,
                      const char* pszName, 
                      const char* psz)
{
  pfStream->type = 2;
  return SStream_Init(&pfStream->streamObj.sstream, pszName, psz);
}
Exemplo n.º 2
0
// dynamicly allocate memory to contain disasm insn
// NOTE: caller must free() the allocated memory itself to avoid memory leaking
size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
{
	struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
	MCInst mci;
	uint16_t insn_size;
	size_t c = 0;
	unsigned int f = 0;
	cs_insn insn_cache[INSN_CACHE_SIZE];
	void *total = NULL;
	size_t total_size = 0;

	if (!handle) {
		// FIXME: how to handle this case:
		// handle->errnum = CS_ERR_HANDLE;
		return 0;
	}

	handle->errnum = CS_ERR_OK;

	// reset previous prefix for X86
	handle->prev_prefix = 0;

	memset(insn_cache, 0, sizeof(insn_cache));

	while (size > 0) {
		MCInst_Init(&mci);
		mci.csh = handle;

		bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
		if (r) {
			SStream ss;
			SStream_Init(&ss);

			// relative branches need to know the address & size of current insn
			mci.insn_size = insn_size;
			mci.address = offset;

			if (handle->detail) {
				// save all the information for non-detailed mode
				mci.flat_insn.address = offset;
				mci.flat_insn.size = insn_size;
				// allocate memory for @detail pointer
				insn_cache[f].detail = cs_mem_calloc(1, sizeof(cs_detail));
			}

			handle->printer(&mci, &ss, handle->printer_info);

			fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);

			if (!handle->check_combine || !handle->check_combine(handle, &insn_cache[f])) {
				f++;

				if (f == ARR_SIZE(insn_cache)) {
					// resize total to contain newly disasm insns
					total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
					void *tmp = cs_mem_realloc(total, total_size);
					if (tmp == NULL) {	// insufficient memory
						cs_mem_free(total);
						handle->errnum = CS_ERR_MEM;
						return 0;
					}

					total = tmp;
					memcpy((void*)((uintptr_t)total + total_size - sizeof(insn_cache)), insn_cache, sizeof(insn_cache));

					// reset f back to 0
					f = 0;
				}

				c++;
			} else {
				// combine this instruction with previous prefix "instruction"
				cs_insn *prev = get_prev_insn(insn_cache, f, total, total_size);
				handle->combine(handle, &insn_cache[f], prev);
			}

			buffer += insn_size;
			size -= insn_size;
			offset += insn_size;

			if (count > 0) {
				// x86 hacky
				if (!handle->prev_prefix) {
					if (c == count)
						break;
				} else {
					// only combine 1 prefix with regular instruction
					if (c == count + 1) {
						// the last insn is redundant
						c--;
						f--;
						// free allocated detail pointer of the last redundant instruction
						if (handle->detail)
							cs_mem_free(insn_cache[f].detail);

						break;
					}
				}
			}
		} else	{
			// encounter a broken instruction
			// XXX: TODO: JOXEAN continue here
			break;
		}
	}

	if (f) {
		// resize total to contain newly disasm insns
		void *tmp = cs_mem_realloc(total, total_size + f * sizeof(insn_cache[0]));
		if (tmp == NULL) {	// insufficient memory
			cs_mem_free(total);
			handle->errnum = CS_ERR_MEM;
			return 0;
		}

		total = tmp;
		memcpy((void*)((uintptr_t)total + total_size), insn_cache, f * sizeof(insn_cache[0]));

	}

	*insn = total;

	return c;
}
Exemplo n.º 3
0
Arquivo: cs.c Projeto: bSr43/capstone
// iterator for instruction "single-stepping"
CAPSTONE_EXPORT
bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
		uint64_t *address, cs_insn *insn)
{
	struct cs_struct *handle;
	uint16_t insn_size;
	MCInst mci;
	bool r;

	handle = (struct cs_struct *)(uintptr_t)ud;
	if (!handle) {
		return false;
	}

	handle->errnum = CS_ERR_OK;

	MCInst_Init(&mci);
	mci.csh = handle;

	// relative branches need to know the address & size of current insn
	mci.address = *address;

	// save all the information for non-detailed mode
	mci.flat_insn = insn;
	mci.flat_insn->address = *address;
#ifdef CAPSTONE_DIET
	// zero out mnemonic & op_str
	mci.flat_insn->mnemonic[0] = '\0';
	mci.flat_insn->op_str[0] = '\0';
#endif

	r = handle->disasm(ud, *code, *size, &mci, &insn_size, *address, handle->getinsn_info);
	if (r) {
		SStream ss;
		SStream_Init(&ss);

		mci.flat_insn->size = insn_size;

		// map internal instruction opcode to public insn ID
		handle->insn_id(handle, insn, mci.Opcode);

		handle->printer(&mci, &ss, handle->printer_info);

		fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, *code);

		*code += insn_size;
		*size -= insn_size;
		*address += insn_size;
	} else { 	// encounter a broken instruction
		size_t skipdata_bytes;

		// if there is no request to skip data, or remaining data is too small,
		// then bail out
		if (!handle->skipdata || handle->skipdata_size > *size)
			return false;

		if (handle->skipdata_setup.callback) {
			skipdata_bytes = handle->skipdata_setup.callback(*code, *size,
					0, handle->skipdata_setup.user_data);
			if (skipdata_bytes > *size)
				// remaining data is not enough
				return false;

			if (!skipdata_bytes)
				// user requested not to skip data, so bail out
				return false;
		} else
			skipdata_bytes = handle->skipdata_size;

		// we have to skip some amount of data, depending on arch & mode
		insn->id = 0;	// invalid ID for this "data" instruction
		insn->address = *address;
		insn->size = (uint16_t)skipdata_bytes;
		memcpy(insn->bytes, *code, skipdata_bytes);
#ifdef CAPSTONE_DIET
		insn->mnemonic[0] = '\0';
		insn->op_str[0] = '\0';
#else
		strncpy(insn->mnemonic, handle->skipdata_setup.mnemonic,
				sizeof(insn->mnemonic) - 1);
		skipdata_opstr(insn->op_str, *code, skipdata_bytes);
#endif

		*code += skipdata_bytes;
		*size -= skipdata_bytes;
		*address += skipdata_bytes;
	}

	return true;
}
Exemplo n.º 4
0
Arquivo: cs.c Projeto: bSr43/capstone
// dynamicly allocate memory to contain disasm insn
// NOTE: caller must free() the allocated memory itself to avoid memory leaking
CAPSTONE_EXPORT
size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
{
	struct cs_struct *handle;
	MCInst mci;
	uint16_t insn_size;
	size_t c = 0, i;
	unsigned int f = 0;	// index of the next instruction in the cache
	cs_insn *insn_cache;	// cache contains disassembled instructions
	void *total = NULL;
	size_t total_size = 0;	// total size of output buffer containing all insns
	bool r;
	void *tmp;
	size_t skipdata_bytes;
	uint64_t offset_org; // save all the original info of the buffer
	size_t size_org;
	const uint8_t *buffer_org;
	unsigned int cache_size = INSN_CACHE_SIZE;
	size_t next_offset;

	handle = (struct cs_struct *)(uintptr_t)ud;
	if (!handle) {
		// FIXME: how to handle this case:
		// handle->errnum = CS_ERR_HANDLE;
		return 0;
	}

	handle->errnum = CS_ERR_OK;

	// reset IT block of ARM structure
	if (handle->arch == CS_ARCH_ARM)
		handle->ITBlock.size = 0;

#ifdef CAPSTONE_USE_SYS_DYN_MEM
	if (count > 0 && count <= INSN_CACHE_SIZE)
		cache_size = (unsigned int) count;
#endif

	// save the original offset for SKIPDATA
	buffer_org = buffer;
	offset_org = offset;
	size_org = size;

	total_size = sizeof(cs_insn) * cache_size;
	total = cs_mem_malloc(total_size);
	if (total == NULL) {
		// insufficient memory
		handle->errnum = CS_ERR_MEM;
		return 0;
	}

	insn_cache = total;

	while (size > 0) {
		MCInst_Init(&mci);
		mci.csh = handle;

		// relative branches need to know the address & size of current insn
		mci.address = offset;

		if (handle->detail) {
			// allocate memory for @detail pointer
			insn_cache->detail = cs_mem_malloc(sizeof(cs_detail));
		} else {
			insn_cache->detail = NULL;
		}

		// save all the information for non-detailed mode
		mci.flat_insn = insn_cache;
		mci.flat_insn->address = offset;
#ifdef CAPSTONE_DIET
		// zero out mnemonic & op_str
		mci.flat_insn->mnemonic[0] = '\0';
		mci.flat_insn->op_str[0] = '\0';
#endif

		r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
		if (r) {
			SStream ss;
			SStream_Init(&ss);

			mci.flat_insn->size = insn_size;

			// map internal instruction opcode to public insn ID

			handle->insn_id(handle, insn_cache, mci.Opcode);

			handle->printer(&mci, &ss, handle->printer_info);

			fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer);

			next_offset = insn_size;
		} else	{
			// encounter a broken instruction

			// free memory of @detail pointer
			if (handle->detail) {
				cs_mem_free(insn_cache->detail);
			}

			// if there is no request to skip data, or remaining data is too small,
			// then bail out
			if (!handle->skipdata || handle->skipdata_size > size)
				break;

			if (handle->skipdata_setup.callback) {
				skipdata_bytes = handle->skipdata_setup.callback(buffer_org, size_org,
						(size_t)(offset - offset_org), handle->skipdata_setup.user_data);
				if (skipdata_bytes > size)
					// remaining data is not enough
					break;

				if (!skipdata_bytes)
					// user requested not to skip data, so bail out
					break;
			} else
				skipdata_bytes = handle->skipdata_size;

			// we have to skip some amount of data, depending on arch & mode
			insn_cache->id = 0;	// invalid ID for this "data" instruction
			insn_cache->address = offset;
			insn_cache->size = (uint16_t)skipdata_bytes;
			memcpy(insn_cache->bytes, buffer, skipdata_bytes);
#ifdef CAPSTONE_DIET
 			insn_cache->mnemonic[0] = '\0';
			insn_cache->op_str[0] = '\0';
#else
			strncpy(insn_cache->mnemonic, handle->skipdata_setup.mnemonic,
  					sizeof(insn_cache->mnemonic) - 1);
  			skipdata_opstr(insn_cache->op_str, buffer, skipdata_bytes);
#endif
			insn_cache->detail = NULL;

			next_offset = skipdata_bytes;
		}

		// one more instruction entering the cache
		f++;

		// one more instruction disassembled
		c++;
		if (count > 0 && c == count)
			// already got requested number of instructions
			break;

		if (f == cache_size) {
			// full cache, so expand the cache to contain incoming insns
			cache_size = cache_size * 8 / 5; // * 1.6 ~ golden ratio
			total_size += (sizeof(cs_insn) * cache_size);
			tmp = cs_mem_realloc(total, total_size);
			if (tmp == NULL) {	// insufficient memory
				if (handle->detail) {
					insn_cache = (cs_insn *)total;
					for (i = 0; i < c; i++, insn_cache++)
						cs_mem_free(insn_cache->detail);
				}

				cs_mem_free(total);
				*insn = NULL;
				handle->errnum = CS_ERR_MEM;
				return 0;
			}

			total = tmp;
			// continue to fill in the cache after the last instruction
			insn_cache = (cs_insn *)((char *)total + sizeof(cs_insn) * c);

			// reset f back to 0, so we fill in the cache from begining
			f = 0;
		} else
			insn_cache++;

		buffer += next_offset;
		size -= next_offset;
		offset += next_offset;
	}

	if (!c) {
		// we did not disassemble any instruction
		cs_mem_free(total);
		total = NULL;
	} else if (f != cache_size) {
		// total did not fully use the last cache, so downsize it
		tmp = cs_mem_realloc(total, total_size - (cache_size - f) * sizeof(*insn_cache));
		if (tmp == NULL) {	// insufficient memory
			// free all detail pointers
			if (handle->detail) {
				insn_cache = (cs_insn *)total;
				for (i = 0; i < c; i++, insn_cache++)
					cs_mem_free(insn_cache->detail);
			}

			cs_mem_free(total);
			*insn = NULL;

			handle->errnum = CS_ERR_MEM;
			return 0;
		}

		total = tmp;
	}

	*insn = total;

	return c;
}
Exemplo n.º 5
0
static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info)
{
#define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg)))
	SStream ss;
	const char *opCode;
	char *tmp, *AsmMnem, *AsmOps, *c;
	int OpIdx, PrintMethodIdx;
	int decCtr = false, needComma = false;
	MCRegisterInfo *MRI = (MCRegisterInfo *)info;

	SStream_Init(&ss);
	switch (MCInst_getOpcode(MI)) {
		default: return NULL;
		case PPC_gBC:
				 opCode = "b%s";
				 break;
		case PPC_gBCA:
				 opCode = "b%sa";
				 break;
		case PPC_gBCCTR:
				 opCode = "b%sctr";
				 break;
		case PPC_gBCCTRL:
				 opCode = "b%sctrl";
				 break;
		case PPC_gBCL:
				 opCode = "b%sl";
				 break;
		case PPC_gBCLA:
				 opCode = "b%sla";
				 break;
		case PPC_gBCLR:
				 opCode = "b%slr";
				 break;
		case PPC_gBCLRL:
				 opCode = "b%slrl";
				 break;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) {
		SStream_concat(&ss, opCode, "dnzf");
		decCtr = true;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) {
		SStream_concat(&ss, opCode, "dzf");
		decCtr = true;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) &&
			MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
			GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
		int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
		switch(cr) {
			case CREQ:
				SStream_concat(&ss, opCode, "ne");
				break;
			case CRGT:
				SStream_concat(&ss, opCode, "le");
				break;
			case CRLT:
				SStream_concat(&ss, opCode, "ge");
				break;
			case CRUN:
				SStream_concat(&ss, opCode, "ns");
				break;
		}

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
			SStream_concat0(&ss, "-");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
			SStream_concat0(&ss, "+");

		decCtr = false;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) {
		SStream_concat(&ss, opCode, "dnzt");
		decCtr = true;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) {
		SStream_concat(&ss, opCode, "dzt");
		decCtr = true;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) &&
			MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
			GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
		int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
		switch(cr) {
			case CREQ:
				SStream_concat(&ss, opCode, "eq");
				break;
			case CRGT:
				SStream_concat(&ss, opCode, "gt");
				break;
			case CRLT:
				SStream_concat(&ss, opCode, "lt");
				break;
			case CRUN:
				SStream_concat(&ss, opCode, "so");
				break;
		}

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
			SStream_concat0(&ss, "-");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15)
			SStream_concat0(&ss, "+");

		decCtr = false;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) {
		SStream_concat(&ss, opCode, "dnz");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24)
			SStream_concat0(&ss, "-");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25)
			SStream_concat0(&ss, "+");

		needComma = false;
	}

	if (MCInst_getNumOperands(MI) == 3 &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) {
		SStream_concat(&ss, opCode, "dz");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26)
			SStream_concat0(&ss, "-");

		if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27)
			SStream_concat0(&ss, "+");

		needComma = false;
	}

	if (MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
			GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) &&
			MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
			(MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) {
		int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));

		if (decCtr) {
			needComma = true;
			SStream_concat0(&ss, " ");

			if (cr > PPC_CR0) {
				SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0);
			}

			cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
			switch(cr) {
				case CREQ:
					SStream_concat0(&ss, "eq");
					op_addBC(MI, PPC_BC_EQ);
					break;
				case CRGT:
					SStream_concat0(&ss, "gt");
					op_addBC(MI, PPC_BC_GT);
					break;
				case CRLT:
					SStream_concat0(&ss, "lt");
					op_addBC(MI, PPC_BC_LT);
					break;
				case CRUN:
					SStream_concat0(&ss, "so");
					op_addBC(MI, PPC_BC_SO);
					break;
			}

			cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));
			if (cr > PPC_CR0) {
				if (MI->csh->detail) {
					MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_CRX;
					MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.scale = 4;
					MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.reg = PPC_REG_CR0 + cr - PPC_CR0;
					MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.cond = MI->flat_insn->detail->ppc.bc;
					MI->flat_insn->detail->ppc.op_count++;
				}
			}
		} else {
			if (cr > PPC_CR0) {
				needComma = true;
				SStream_concat(&ss, " cr%d", cr - PPC_CR0);
				op_addReg(MI, PPC_REG_CR0 + cr - PPC_CR0);
			}
		}
	}

	if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
			MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) {
		if (needComma)
			SStream_concat0(&ss, ",");

		SStream_concat0(&ss, " $\xFF\x03\x01");
	}

	tmp = cs_strdup(ss.buffer);
	AsmMnem = tmp;
	for(AsmOps = tmp; *AsmOps; AsmOps++) {
		if (*AsmOps == ' ' || *AsmOps == '\t') {
			*AsmOps = '\0';
			AsmOps++;
			break;
		}
	}

	SStream_concat0(OS, AsmMnem);
	if (*AsmOps) {
		SStream_concat0(OS, "\t");
		for (c = AsmOps; *c; c++) {
			if (*c == '$') {
				c += 1;
				if (*c == (char)0xff) {
					c += 1;
					OpIdx = *c - 1;
					c += 1;
					PrintMethodIdx = *c - 1;
					printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);
				} else
					printOperand(MI, *c - 1, OS);
			} else {
				SStream_concat(OS, "%c", *c);
			}
		}
	}

	return tmp;
}
Exemplo n.º 6
0
void X86_ATT_printInst(MCInst *MI, SStream *OS, void *info)
{
	char *mnem;
	x86_reg reg, reg2;
	enum cs_ac_type access1, access2;
	int i;

	// perhaps this instruction does not need printer
	if (MI->assembly[0]) {
		strncpy(OS->buffer, MI->assembly, sizeof(OS->buffer));
		return;
	}

	// Output CALLpcrel32 as "callq" in 64-bit mode.
	// In Intel annotation it's always emitted as "call".
	//
	// TODO: Probably this hack should be redesigned via InstAlias in
	// InstrInfo.td as soon as Requires clause is supported properly
	// for InstAlias.
	if (MI->csh->mode == CS_MODE_64 && MCInst_getOpcode(MI) == X86_CALLpcrel32) {
		SStream_concat0(OS, "callq\t");
		MCInst_setOpcodePub(MI, X86_INS_CALL);
		printPCRelImm(MI, 0, OS);
		return;
	}

	// Try to print any aliases first.
	mnem = printAliasInstr(MI, OS, info);
	if (mnem)
		cs_mem_free(mnem);
	else
		printInstruction(MI, OS, info);

	// HACK TODO: fix this in machine description
	switch(MI->flat_insn->id) {
		default: break;
		case X86_INS_SYSEXIT:
				 SStream_Init(OS);
				 SStream_concat0(OS, "sysexit");
				 break;
	}

	if (MI->has_imm) {
		// if op_count > 1, then this operand's size is taken from the destination op
		if (MI->flat_insn->detail->x86.op_count > 1) {
			if (MI->flat_insn->id != X86_INS_LCALL && MI->flat_insn->id != X86_INS_LJMP) {
				for (i = 0; i < MI->flat_insn->detail->x86.op_count; i++) {
					if (MI->flat_insn->detail->x86.operands[i].type == X86_OP_IMM)
						MI->flat_insn->detail->x86.operands[i].size =
							MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count - 1].size;
				}
			}
		} else
			MI->flat_insn->detail->x86.operands[0].size = MI->imm_size;
	}

	if (MI->csh->detail) {
		uint8_t access[6] = {0};

		// some instructions need to supply immediate 1 in the first op
		switch(MCInst_getOpcode(MI)) {
			default:
				break;
			case X86_SHL8r1:
			case X86_SHL16r1:
			case X86_SHL32r1:
			case X86_SHL64r1:
			case X86_SAL8r1:
			case X86_SAL16r1:
			case X86_SAL32r1:
			case X86_SAL64r1:
			case X86_SHR8r1:
			case X86_SHR16r1:
			case X86_SHR32r1:
			case X86_SHR64r1:
			case X86_SAR8r1:
			case X86_SAR16r1:
			case X86_SAR32r1:
			case X86_SAR64r1:
			case X86_RCL8r1:
			case X86_RCL16r1:
			case X86_RCL32r1:
			case X86_RCL64r1:
			case X86_RCR8r1:
			case X86_RCR16r1:
			case X86_RCR32r1:
			case X86_RCR64r1:
			case X86_ROL8r1:
			case X86_ROL16r1:
			case X86_ROL32r1:
			case X86_ROL64r1:
			case X86_ROR8r1:
			case X86_ROR16r1:
			case X86_ROR32r1:
			case X86_ROR64r1:
			case X86_SHL8m1:
			case X86_SHL16m1:
			case X86_SHL32m1:
			case X86_SHL64m1:
			case X86_SAL8m1:
			case X86_SAL16m1:
			case X86_SAL32m1:
			case X86_SAL64m1:
			case X86_SHR8m1:
			case X86_SHR16m1:
			case X86_SHR32m1:
			case X86_SHR64m1:
			case X86_SAR8m1:
			case X86_SAR16m1:
			case X86_SAR32m1:
			case X86_SAR64m1:
			case X86_RCL8m1:
			case X86_RCL16m1:
			case X86_RCL32m1:
			case X86_RCL64m1:
			case X86_RCR8m1:
			case X86_RCR16m1:
			case X86_RCR32m1:
			case X86_RCR64m1:
			case X86_ROL8m1:
			case X86_ROL16m1:
			case X86_ROL32m1:
			case X86_ROL64m1:
			case X86_ROR8m1:
			case X86_ROR16m1:
			case X86_ROR32m1:
			case X86_ROR64m1:
				// shift all the ops right to leave 1st slot for this new register op
				memmove(&(MI->flat_insn->detail->x86.operands[1]), &(MI->flat_insn->detail->x86.operands[0]),
						sizeof(MI->flat_insn->detail->x86.operands[0]) * (ARR_SIZE(MI->flat_insn->detail->x86.operands) - 1));
				MI->flat_insn->detail->x86.operands[0].type = X86_OP_IMM;
				MI->flat_insn->detail->x86.operands[0].imm = 1;
				MI->flat_insn->detail->x86.operands[0].size = 1;
				MI->flat_insn->detail->x86.op_count++;
		}

		// special instruction needs to supply register op
		// first op can be embedded in the asm by llvm.
		// so we have to add the missing register as the first operand

		//printf(">>> opcode = %u\n", MCInst_getOpcode(MI));

		reg = X86_insn_reg_att(MCInst_getOpcode(MI), &access1);
		if (reg) {
			// shift all the ops right to leave 1st slot for this new register op
			memmove(&(MI->flat_insn->detail->x86.operands[1]), &(MI->flat_insn->detail->x86.operands[0]),
					sizeof(MI->flat_insn->detail->x86.operands[0]) * (ARR_SIZE(MI->flat_insn->detail->x86.operands) - 1));
			MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
			MI->flat_insn->detail->x86.operands[0].reg = reg;
			MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
			MI->flat_insn->detail->x86.operands[0].access = access1;

			MI->flat_insn->detail->x86.op_count++;
		} else {
			if (X86_insn_reg_att2(MCInst_getOpcode(MI), &reg, &access1, &reg2, &access2)) {

				MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
				MI->flat_insn->detail->x86.operands[0].reg = reg;
				MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
				MI->flat_insn->detail->x86.operands[0].access = access1;
				MI->flat_insn->detail->x86.operands[1].type = X86_OP_REG;
				MI->flat_insn->detail->x86.operands[1].reg = reg2;
				MI->flat_insn->detail->x86.operands[1].size = MI->csh->regsize_map[reg2];
				MI->flat_insn->detail->x86.operands[0].access = access2;
				MI->flat_insn->detail->x86.op_count = 2;
			}
		}

#ifndef CAPSTONE_DIET
		get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
		MI->flat_insn->detail->x86.operands[0].access = access[0];
		MI->flat_insn->detail->x86.operands[1].access = access[1];
#endif
	}
}