Result Stream_InitStr(Stream* pfStream, const char* pszName, const char* psz) { pfStream->type = 2; return SStream_Init(&pfStream->streamObj.sstream, pszName, psz); }
// 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; }
// 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; }
// 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; }
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; }
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), ®, &access1, ®2, &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 } }