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)