From 993f362ad82b4988f17916a1947b1748791b3dac Mon Sep 17 00:00:00 2001 From: hlide Date: Sun, 5 Oct 2014 18:14:40 +0200 Subject: [PATCH] New API: cs_disasm_iter --- cs.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++ cs_priv.h | 1 + include/capstone.h | 30 +++++++++------- 3 files changed, 108 insertions(+), 12 deletions(-) diff --git a/cs.c b/cs.c index caeef8cb1d..c47aa989cd 100644 --- a/cs.c +++ b/cs.c @@ -204,6 +204,7 @@ cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle) ud->big_endian = mode & CS_MODE_BIG_ENDIAN; // by default, do not break instruction into details ud->detail = CS_OPT_OFF; + ud->insn = NULL; // default skipdata setup ud->skipdata_setup.mnemonic = SKIPDATA_MNEM; @@ -235,6 +236,13 @@ cs_err cs_close(csh *handle) ud = (struct cs_struct *)(*handle); + if (ud->insn) { + if (ud->detail) + cs_free(ud->insn, 1); + else + cs_mem_free(ud->insn); + } + if (ud->printer_info) cs_mem_free(ud->printer_info); @@ -612,6 +620,87 @@ void cs_free(cs_insn *insn, size_t count) cs_mem_free(insn); } +// iterator for instruction "single-stepping" +CAPSTONE_EXPORT +cs_insn *cs_disasm_iter(csh ud, const uint8_t **code, size_t *size, uint64_t *address) +{ + struct cs_struct *handle; + cs_insn *insn_cache; + uint16_t insn_size; + MCInst mci; + bool r; + + handle = (struct cs_struct *)(uintptr_t)ud; + if (!handle) + { + return NULL; + } + + handle->errnum = CS_ERR_OK; + + insn_cache = handle->insn; + if (!insn_cache) + { + insn_cache = cs_mem_malloc(sizeof(cs_insn)); + if (!insn_cache) + { + handle->errnum = CS_ERR_MEM; + return NULL; + } + else + { + handle->insn = insn_cache; + if (handle->detail) + { + // allocate memory for @detail pointer + insn_cache->detail = cs_mem_malloc(sizeof(cs_detail)); + if (insn_cache->detail == NULL) + { // insufficient memory + cs_mem_free(insn_cache); + handle->errnum = CS_ERR_MEM; + return NULL; + } + } + else + insn_cache->detail = NULL; + } + } + + 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_cache; + 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; + handle->printer(&mci, &ss, handle->printer_info); + fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, *code); + *code += insn_size; + *size -= insn_size; + *address += insn_size; + } + else + { + insn_cache->id = 0; // invalid ID for this "data" instruction + } + return insn_cache; +} + // return friendly name of regiser in a string CAPSTONE_EXPORT const char *cs_reg_name(csh ud, unsigned int reg) diff --git a/cs_priv.h b/cs_priv.h index b56030c14f..0e8cb2b54e 100644 --- a/cs_priv.h +++ b/cs_priv.h @@ -54,6 +54,7 @@ struct cs_struct { uint8_t skipdata_size; // how many bytes to skip cs_opt_skipdata skipdata_setup; // user-defined skipdata setup uint8_t *regsize_map; // map to register size (x86-only for now) + cs_insn *insn; }; #define MAX_ARCH 8 diff --git a/include/capstone.h b/include/capstone.h index a282c2393b..cf434b05c5 100644 --- a/include/capstone.h +++ b/include/capstone.h @@ -16,15 +16,15 @@ extern "C" { #include "platform.h" #ifdef _MSC_VER - #pragma warning(disable:4201) - #pragma warning(disable:4100) - #ifdef CAPSTONE_SHARED - #define CAPSTONE_EXPORT __declspec(dllexport) - #else // defined(CAPSTONE_STATIC) - #define CAPSTONE_EXPORT - #endif + #pragma warning(disable:4201) + #pragma warning(disable:4100) + #ifdef CAPSTONE_SHARED + #define CAPSTONE_EXPORT __declspec(dllexport) + #else // defined(CAPSTONE_STATIC) + #define CAPSTONE_EXPORT + #endif #else - #define CAPSTONE_EXPORT + #define CAPSTONE_EXPORT #endif #ifdef __GNUC__ @@ -267,8 +267,8 @@ typedef enum cs_err { @minor: minor number of API version @return hexical number as (major << 8 | minor), which encodes both - major & minor versions. - NOTE: This returned value can be compared with version number made + major & minor versions. + NOTE: This returned value can be compared with version number made with macro CS_MAKE_VERSION For example, second API version would return 1 in @major, and 1 in @minor @@ -362,7 +362,7 @@ cs_err cs_errno(csh handle); @code: error code (see CS_ERR_* above) @return: returns a pointer to a string that describes the error code - passed in the argument @code + passed in the argument @code */ CAPSTONE_EXPORT const char *cs_strerror(cs_err code); @@ -380,7 +380,7 @@ const char *cs_strerror(cs_err code); @code_size: size of above code @address: address of the first insn in given raw code buffer @insn: array of insn filled in by this function - NOTE: @insn will be allocated by this function, and should be freed + NOTE: @insn will be allocated by this function, and should be freed with cs_free() API. @count: number of instrutions to be disassembled, or 0 to get all of them @return: the number of succesfully disassembled instructions, @@ -416,6 +416,12 @@ size_t cs_disasm_ex(csh handle, CAPSTONE_EXPORT void cs_free(cs_insn *insn, size_t count); +/* TODO */ +CAPSTONE_EXPORT +cs_insn *cs_disasm_iter(csh handle, + const uint8_t **code, size_t *size, + uint64_t *address); + /* Return friendly name of regiser in a string. Find the instruction id from header file of corresponding architecture (arm.h for ARM,