modify API cs_disasm_iter() and add new API cs_malloc(). also adds sample code test_iter.c
diff --git a/cs.c b/cs.c
index c47aa98..ff72d77 100644
--- a/cs.c
+++ b/cs.c
@@ -204,7 +204,6 @@
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;
@@ -236,19 +235,11 @@
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);
- // arch_destroy[ud->arch](ud);
-
cs_mem_free(ud->insn_cache);
+
memset(ud, 0, sizeof(*ud));
cs_mem_free(ud);
@@ -418,7 +409,7 @@
CAPSTONE_EXPORT
size_t cs_disasm(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;
+ struct cs_struct *handle;
MCInst mci;
uint16_t insn_size;
size_t c = 0, i;
@@ -435,6 +426,7 @@
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;
@@ -519,7 +511,7 @@
// 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;
+ insn_cache->size = (uint16_t)skipdata_bytes;
memcpy(insn_cache->bytes, buffer, skipdata_bytes);
strncpy(insn_cache->mnemonic, handle->skipdata_setup.mnemonic,
sizeof(insn_cache->mnemonic) - 1);
@@ -620,52 +612,50 @@
cs_mem_free(insn);
}
+CAPSTONE_EXPORT
+cs_insn *cs_malloc(csh ud)
+{
+ cs_insn *insn;
+ struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
+
+ insn = cs_mem_malloc(sizeof(cs_insn));
+ if (!insn) {
+ // insufficient memory
+ handle->errnum = CS_ERR_MEM;
+ return NULL;
+ } else {
+ if (handle->detail) {
+ // allocate memory for @detail pointer
+ insn->detail = cs_mem_malloc(sizeof(cs_detail));
+ if (insn->detail == NULL) { // insufficient memory
+ cs_mem_free(insn);
+ handle->errnum = CS_ERR_MEM;
+ return NULL;
+ }
+ } else
+ insn->detail = NULL;
+ }
+
+ return 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)
+bool cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
+ uint64_t *address, cs_insn *insn)
{
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)
- {
+ 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;
@@ -673,7 +663,7 @@
mci.address = *address;
// save all the information for non-detailed mode
- mci.flat_insn = insn_cache;
+ mci.flat_insn = insn;
mci.flat_insn->address = *address;
#ifdef CAPSTONE_DIET
// zero out mnemonic & op_str
@@ -682,23 +672,57 @@
#endif
r = handle->disasm(ud, *code, *size, &mci, &insn_size, *address, handle->getinsn_info);
- if (r)
- {
+ 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);
+ 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);
+ strncpy(insn->mnemonic, handle->skipdata_setup.mnemonic,
+ sizeof(insn->mnemonic) - 1);
+ skipdata_opstr(insn->op_str, *code, skipdata_bytes);
+
+ // NOTE: if detail mode is OFF, content of detail pointer is irrelevant
+ // to be sure, zero out content of detail pointer
+ if (insn->detail)
+ memset(insn->detail, 0, sizeof(cs_detail));
+
+ *code += skipdata_bytes;
+ *size -= skipdata_bytes;
+ *address += skipdata_bytes;
}
- else
- {
- insn_cache->id = 0; // invalid ID for this "data" instruction
- }
- return insn_cache;
+
+ return true;
}
// return friendly name of regiser in a string