New API: cs_disasm_iter
diff --git a/cs.c b/cs.c
index caeef8c..c47aa98 100644
--- a/cs.c
+++ b/cs.c
@@ -204,6 +204,7 @@
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 @@
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 @@
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 b56030c..0e8cb2b 100644
--- a/cs_priv.h
+++ b/cs_priv.h
@@ -54,6 +54,7 @@
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 a282c23..cf434b0 100644
--- a/include/capstone.h
+++ b/include/capstone.h
@@ -16,15 +16,15 @@
#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 @@
@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 @@
@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 @@
@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 @@
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,