From 40ca3deb44de79b81ec6c33a504853ca17a1eb5c Mon Sep 17 00:00:00 2001 From: Denis Drakhnia Date: Sun, 26 May 2024 11:09:42 +0300 Subject: [PATCH] Add cs_buffer. Breaking API change. Remove cs_malloc() and cs_free(). API change unifies disassembly process. Before, there were two separate functions to disassemble one instruction at a time in a loop and many instructions into a dynamic buffer. Commit will introduce user allocatable buffer that can be used in both situations with one function. cs_disasm_iter() is a tiny wrapper around cs_disasm(). Updating the use of cs_disasm_iter(): // old api cs_insn *insn = cs_malloc(handle); while (cs_disasm_iter(handle, &code, &code_size, &ip, insn)) { disassembled_instructions += 1; } cs_free(insn); Must be changed to: // new api cs_buffer *buffer = cs_buffer_new(1); // create buffer with 1 element while (cs_disasm_iter(handle, &code, &code_size, &ip, buffer)) { cs_insn *insn = &buffer->insn[0]; // get first insn in a buffer disassembled_instructions += 1; } cs_buffer_free(buffer); // free buffer Updating the use of cs_disasm() is straightforward, just use cs_buffer_new(0) to create a buffer and pass it to cs_disasm(). --- bindings/python/capstone/__init__.py | 123 ++++---- bindings/python/pyx/ccapstone.pxd | 17 +- bindings/python/pyx/ccapstone.pyx | 16 +- cs.c | 420 ++++++++++---------------- cstool/cstool.c | 22 +- include/capstone/capstone.h | 151 +++++---- suite/arm/test_arm_regression.c | 22 +- suite/benchmark/test_file_benchmark.c | 12 +- suite/benchmark/test_iter_benchmark.c | 8 +- suite/cstest/src/capstone_test.c | 27 +- suite/fuzz/fuzz_diff.c | 11 +- suite/fuzz/fuzz_disasm.c | 8 +- tests/test_aarch64.c | 10 +- tests/test_alpha.c | 10 +- tests/test_arm.c | 11 +- tests/test_basic.c | 12 +- tests/test_bpf.c | 11 +- tests/test_customized_mnem.c | 9 +- tests/test_detail.c | 14 +- tests/test_evm.c | 11 +- tests/test_hppa.c | 10 +- tests/test_iter.c | 13 +- tests/test_m680x.c | 10 +- tests/test_m68k.c | 10 +- tests/test_mips.c | 10 +- tests/test_mos65xx.c | 10 +- tests/test_ppc.c | 10 +- tests/test_riscv.c | 10 +- tests/test_sh.c | 10 +- tests/test_skipdata.c | 10 +- tests/test_sparc.c | 10 +- tests/test_systemz.c | 10 +- tests/test_tms320c64x.c | 10 +- tests/test_tricore.c | 10 +- tests/test_wasm.c | 11 +- tests/test_x86.c | 10 +- tests/test_xcore.c | 10 +- 37 files changed, 531 insertions(+), 568 deletions(-) diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py index 154e6f1105..3a782a4af4 100755 --- a/bindings/python/capstone/__init__.py +++ b/bindings/python/capstone/__init__.py @@ -503,6 +503,13 @@ class _cs_insn(ctypes.Structure): ('detail', ctypes.POINTER(_cs_detail)), ) +class _cs_buffer(ctypes.Structure): + _fields_ = ( + ('insn', ctypes.POINTER(_cs_insn)), + ('capacity', ctypes.c_size_t), + ('count', ctypes.c_size_t), + ) + # callback for SKIPDATA option CS_SKIPDATA_CALLBACK = ctypes.CFUNCTYPE(ctypes.c_size_t, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_size_t, ctypes.c_void_p) @@ -525,11 +532,12 @@ def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).argtypes = argtypes _setup_prototype(_cs, "cs_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t)) +_setup_prototype(_cs, "cs_buffer_new", ctypes.POINTER(_cs_buffer), ctypes.c_size_t) +_setup_prototype(_cs, "cs_buffer_free", None, ctypes.POINTER(_cs_buffer)) _setup_prototype(_cs, "cs_disasm", ctypes.c_size_t, ctypes.c_size_t, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, \ - ctypes.c_uint64, ctypes.c_size_t, ctypes.POINTER(ctypes.POINTER(_cs_insn))) + ctypes.c_uint64, ctypes.c_size_t, ctypes.POINTER(_cs_buffer)) _setup_prototype(_cs, "cs_disasm_iter", ctypes.c_bool, ctypes.c_size_t, ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_size_t), \ - ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(_cs_insn)) -_setup_prototype(_cs, "cs_free", None, ctypes.c_void_p, ctypes.c_size_t) + ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(_cs_buffer)) _setup_prototype(_cs, "cs_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t)) _setup_prototype(_cs, "cs_reg_name", ctypes.c_char_p, ctypes.c_size_t, ctypes.c_uint) _setup_prototype(_cs, "cs_insn_name", ctypes.c_char_p, ctypes.c_size_t, ctypes.c_uint) @@ -599,20 +607,21 @@ def cs_disasm_quick(arch, mode, code, offset, count=0): if status != CS_ERR_OK: raise CsError(status) - all_insn = ctypes.POINTER(_cs_insn)() - res = _cs.cs_disasm(csh, code, len(code), offset, count, ctypes.byref(all_insn)) - if res > 0: - try: + buffer = _cs.cs_buffer_new(0) + try: + res = _cs.cs_disasm(csh, code, len(code), offset, count, buffer) + all_insn = buffer.contents.insn + if res > 0: for i in range(res): yield CsInsn(_dummy_cs(csh, arch), all_insn[i]) - finally: - _cs.cs_free(all_insn, res) - else: - status = _cs.cs_errno(csh) - if status != CS_ERR_OK: - raise CsError(status) - return - yield + else: + status = _cs.cs_errno(csh) + if status != CS_ERR_OK: + raise CsError(status) + return + yield + finally: + _cs.cs_buffer_free(buffer) status = _cs.cs_close(ctypes.byref(csh)) if status != CS_ERR_OK: @@ -639,21 +648,22 @@ def cs_disasm_lite(arch, mode, code, offset, count=0): if status != CS_ERR_OK: raise CsError(status) - all_insn = ctypes.POINTER(_cs_insn)() - res = _cs.cs_disasm(csh, code, len(code), offset, count, ctypes.byref(all_insn)) - if res > 0: - try: + buffer = _cs.cs_buffer_new(0) + res = _cs.cs_disasm(csh, code, len(code), offset, count, buffer) + all_insn = buffer.contents.insn + try: + if res > 0: for i in range(res): insn = all_insn[i] yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) - finally: - _cs.cs_free(all_insn, res) - else: - status = _cs.cs_errno(csh) - if status != CS_ERR_OK: - raise CsError(status) - return - yield + else: + status = _cs.cs_errno(csh) + if status != CS_ERR_OK: + raise CsError(status) + return + yield + finally: + _cs.cs_buffer_free(buffer) status = _cs.cs_close(ctypes.byref(csh)) if status != CS_ERR_OK: @@ -1214,7 +1224,6 @@ def group_name(self, group_id, default=None): # Disassemble binary & return disassembled instructions in CsInsn objects def disasm(self, code, offset, count=0): - all_insn = ctypes.POINTER(_cs_insn)() '''if not _python2: print(code) code = code.encode() @@ -1226,19 +1235,21 @@ def disasm(self, code, offset, count=0): code = ctypes.byref(ctypes.c_char.from_buffer(view)) elif not isinstance(code, bytes): code = view.tobytes() - res = _cs.cs_disasm(self.csh, code, size, offset, count, ctypes.byref(all_insn)) - if res > 0: - try: + buffer = _cs.cs_buffer_new(0) + res = _cs.cs_disasm(self.csh, code, size, offset, count, buffer) + all_insn = buffer.contents.insn + try: + if res > 0: for i in range(res): yield CsInsn(self, all_insn[i]) - finally: - _cs.cs_free(all_insn, res) - else: - status = _cs.cs_errno(self.csh) - if status != CS_ERR_OK: - raise CsError(status) - return - yield + else: + status = _cs.cs_errno(self.csh) + if status != CS_ERR_OK: + raise CsError(status) + return + yield + finally: + _cs.cs_buffer_free(buffer) # This function matches the cs_disasm_iter implementation which # *should* be much faster via the C API due to pre-allocating @@ -1264,8 +1275,13 @@ def disasm_iter(self, code, offset): # the typical auto conversion, so we have to cast it here. code = ctypes.cast(code, ctypes.POINTER(ctypes.c_char)) address = ctypes.c_uint64(offset) - while _cs.cs_disasm_iter(self.csh, ctypes.byref(code), ctypes.byref(size), ctypes.byref(address), ctypes.byref(insn)): - yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) + buffer = _cs.cs_buffer_new(0) + try: + while _cs.cs_disasm_iter(self.csh, ctypes.byref(code), ctypes.byref(size), ctypes.byref(address), buffer): + insn = buffer.contents.insn[0] + yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) + finally: + _cs.cs_buffer_free(buffer) # Light function to disassemble binary. This is about 20% faster than disasm() because # unlike disasm(), disasm_lite() only return tuples of (address, size, mnemonic, op_str), @@ -1275,7 +1291,6 @@ def disasm_lite(self, code, offset, count=0): # Diet engine cannot provide @mnemonic & @op_str raise CsError(CS_ERR_DIET) - all_insn = ctypes.POINTER(_cs_insn)() size = len(code) # Pass a bytearray by reference view = memoryview(code) @@ -1283,20 +1298,22 @@ def disasm_lite(self, code, offset, count=0): code = ctypes.byref(ctypes.c_char.from_buffer(view)) elif not isinstance(code, bytes): code = view.tobytes() - res = _cs.cs_disasm(self.csh, code, size, offset, count, ctypes.byref(all_insn)) - if res > 0: - try: + buffer = _cs.cs_buffer_new(0) + res = _cs.cs_disasm(self.csh, code, size, offset, count, buffer) + all_insn = buffer.contents.insn + try: + if res > 0: for i in range(res): insn = all_insn[i] yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) - finally: - _cs.cs_free(all_insn, res) - else: - status = _cs.cs_errno(self.csh) - if status != CS_ERR_OK: - raise CsError(status) - return - yield + else: + status = _cs.cs_errno(self.csh) + if status != CS_ERR_OK: + raise CsError(status) + return + yield + finally: + _cs.cs_buffer_free(buffer) # print out debugging info diff --git a/bindings/python/pyx/ccapstone.pxd b/bindings/python/pyx/ccapstone.pxd index 176dd43b20..4970c45a4b 100644 --- a/bindings/python/pyx/ccapstone.pxd +++ b/bindings/python/pyx/ccapstone.pxd @@ -28,6 +28,11 @@ cdef extern from "": bool usesAliasDetails; cs_detail *detail + ctypedef struct cs_buffer: + cs_insn *insn + size_t capacity; + size_t count; + ctypedef enum cs_err: pass @@ -44,11 +49,21 @@ cdef extern from "": cs_err cs_errno(csh handle) + cs_buffer * cs_buffer_new(size_t capacity) + + void cs_buffer_free(cs_buffer *buffer) + + void cs_buffer_clear(cs_buffer *buffer) + + bool cs_buffer_reserve_exact(cs_buffer *buffer, size_t capacity) + + bool cs_buffer_reserve(cs_buffer *buffer, size_t additional) + size_t cs_disasm(csh handle, const uint8_t *code, size_t code_size, uint64_t address, size_t count, - cs_insn **insn) + cs_buffer *buffer) cs_err cs_option(csh handle, cs_opt_type type, size_t value) diff --git a/bindings/python/pyx/ccapstone.pyx b/bindings/python/pyx/ccapstone.pyx index d1a9aceb07..3079ae8424 100644 --- a/bindings/python/pyx/ccapstone.pyx +++ b/bindings/python/pyx/ccapstone.pyx @@ -311,11 +311,11 @@ cdef class Cs(object): # Disassemble binary & return disassembled instructions in CsInsn objects def disasm(self, code, addr, count=0): - cdef cc.cs_insn *allinsn - - cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn) + buffer = cc.cs_buffer_new(0) + cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, buffer) detail = self._cs.detail arch = self._cs.arch + allinsn = buffer.insn try: for i from 0 <= i < res: @@ -328,7 +328,7 @@ cdef class Cs(object): dummy._csh = self._csh yield dummy finally: - cc.cs_free(allinsn, res) + cc.cs_buffer_free(buffer) # Light function to disassemble binary. This is about 20% faster than disasm() because @@ -336,20 +336,20 @@ cdef class Cs(object): # rather than CsInsn objects. def disasm_lite(self, code, addr, count=0): # TODO: don't need detail, so we might turn off detail, then turn on again when done - cdef cc.cs_insn *allinsn if _diet: # Diet engine cannot provide @mnemonic & @op_str raise CsError(capstone.CS_ERR_DIET) - cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn) + buffer = cc.cs_buffer_new(0) + cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, buffer) try: for i from 0 <= i < res: - insn = allinsn[i] + insn = buffer.insn[i] yield (insn.address, insn.size, insn.mnemonic, insn.op_str) finally: - cc.cs_free(allinsn, res) + cc.cs_buffer_free(buffer) # print out debugging info diff --git a/cs.c b/cs.c index dfeaaa0e1e..d65675f5e1 100644 --- a/cs.c +++ b/cs.c @@ -1094,6 +1094,92 @@ cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, size_t value) return arch_configs[handle->arch].arch_option(handle, type, value); } +CAPSTONE_EXPORT +cs_buffer * CAPSTONE_API cs_buffer_new(size_t capacity) { + cs_buffer *buffer = cs_mem_malloc(sizeof(cs_buffer)); + if (!buffer) { + return NULL; + } + buffer->count = 0; + buffer->capacity = capacity ? capacity : 64; + buffer->insn = cs_mem_calloc(sizeof(cs_insn), buffer->capacity); + if (!buffer->insn) { + cs_mem_free(buffer); + return NULL; + } + return buffer; +} + +CAPSTONE_EXPORT +void CAPSTONE_API cs_buffer_free(cs_buffer *buffer) { + for (size_t i = 0; i < buffer->capacity; ++i) { + // can be allocated in cs_disasm() + if (buffer->insn[i].detail) { + cs_mem_free(buffer->insn[i].detail); + } + } + cs_mem_free(buffer->insn); + cs_mem_free(buffer); +} + +CAPSTONE_EXPORT +void CAPSTONE_API cs_buffer_clear(cs_buffer *buffer) { + buffer->count = 0; +} + +CAPSTONE_EXPORT +bool CAPSTONE_API cs_buffer_reserve_exact(cs_buffer *buffer, size_t required) { + cs_insn *insn; + + // free is required if user requested buffer shrink + // details can be allocated by previous cs_disasm() calls + if (required < buffer->capacity) { + // set count to a required capacity because we will free + // instruction details in a loop bellow and in case realloc() will fail + if (required < buffer->count) { + buffer->count = required; + } + + for (size_t i = required; i < buffer->capacity; ++i) { + if (buffer->insn[i].detail) { + cs_mem_free(buffer->insn[i].detail); + } + } + } + + insn = cs_mem_realloc(buffer->insn, required * sizeof(cs_insn)); + if (!insn) { + return false; + } + + // set to NULL all pointers in cs_insn if buffer grows in size + if (required > buffer->capacity) { + size_t diff = required - buffer->capacity; + memset(&insn[buffer->capacity], 0, diff * sizeof(cs_insn)); + } + + buffer->insn = insn; + buffer->capacity = required; + + return true; +} + +CAPSTONE_EXPORT +bool CAPSTONE_API cs_buffer_reserve(cs_buffer *buffer, size_t additional) { + size_t required = buffer->capacity + additional; + size_t capacity = buffer->capacity * 8 / 5; // * 1.6 ~ golden ratio + // increase capacity by 1.6 factor if the requested capacity change is too small + if (capacity < required) { + // use requested capacity change if it is more then 1.6 ratio increase + capacity = required; + } + // make sure there is some capacity to work with + if (capacity < 16) { + capacity = 16; + } + return cs_buffer_reserve_exact(buffer, capacity); +} + // generate @op_str for data instruction of SKIPDATA #ifndef CAPSTONE_DIET static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size) @@ -1126,29 +1212,20 @@ static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size) } #endif -// dynamically 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) +size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *code, size_t code_size, + uint64_t address, size_t count, cs_buffer *buffer) { - struct cs_struct *handle; - MCInst mci; + cs_struct *handle = (cs_struct *) (uintptr_t) ud; + const uint8_t *code_org; // save all the original info of the buffer + size_t code_size_org; + uint64_t address_org; + size_t next_offset; 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; + cs_insn *insn; + MCInst mci; 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; @@ -1157,66 +1234,60 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64 handle->errnum = CS_ERR_OK; -#ifdef CAPSTONE_USE_SYS_DYN_MEM - if (count > 0 && count <= INSN_CACHE_SIZE) - cache_size = (unsigned int) count; -#endif + cs_buffer_clear(buffer); // 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_calloc(sizeof(cs_insn), cache_size); - if (total == NULL) { - // insufficient memory - handle->errnum = CS_ERR_MEM; - return 0; - } + code_org = code; + code_size_org = code_size; + address_org = address; - insn_cache = total; + for (; code_size && (count == 0 || buffer->count < count); ++buffer->count) { + if (buffer->capacity <= buffer->count && !cs_buffer_reserve(buffer, code_size / 4)) { + // insufficient memory + handle->errnum = CS_ERR_MEM; + return 0; + } - while (size > 0) { MCInst_Init(&mci); mci.csh = handle; - + mci.flat_insn = insn = &buffer->insn[buffer->count]; // relative branches need to know the address & size of current insn - mci.address = offset; + mci.address = address; if (handle->detail_opt) { - // allocate memory for @detail pointer - insn_cache->detail = cs_mem_malloc(sizeof(cs_detail)); - } else { - insn_cache->detail = NULL; + if (!insn->detail) { + insn->detail = cs_mem_malloc(sizeof(cs_detail)); + } + } else if (insn->detail) { + cs_mem_free(insn->detail); + insn->detail = NULL; } // save all the information for non-detailed mode - mci.flat_insn = insn_cache; - mci.flat_insn->address = offset; + insn->address = address; #ifdef CAPSTONE_DIET // zero out mnemonic & op_str - mci.flat_insn->mnemonic[0] = '\0'; - mci.flat_insn->op_str[0] = '\0'; + insn->mnemonic[0] = '\0'; + insn->op_str[0] = '\0'; #endif - r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info); - if (r) { + if (handle->disasm(ud, code, code_size, &mci, &insn_size, address, + handle->getinsn_info)) + { SStream ss; SStream_Init(&ss); - mci.flat_insn->size = insn_size; + insn->size = insn_size; // map internal instruction opcode to public insn ID - - handle->insn_id(handle, insn_cache, mci.Opcode); - + handle->insn_id(handle, insn, mci.Opcode); handle->printer(&mci, &ss, handle->printer_info); - fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer); + + fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, code); // adjust for pseudo opcode (X86) - if (handle->arch == CS_ARCH_X86 && insn_cache->id != X86_INS_VCMP) - insn_cache->id += mci.popcode_adjust; + if (handle->arch == CS_ARCH_X86 && insn->id != X86_INS_VCMP) + insn->id += mci.popcode_adjust; next_offset = insn_size; } else { @@ -1224,18 +1295,19 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64 // free memory of @detail pointer if (handle->detail_opt) { - cs_mem_free(insn_cache->detail); + cs_mem_free(insn->detail); } + insn->detail = NULL; // if there is no request to skip data, or remaining data is too small, // then bail out - if (!handle->skipdata || handle->skipdata_size > size) + if (!handle->skipdata || handle->skipdata_size > code_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) + skipdata_bytes = handle->skipdata_setup.callback(code_org, code_size_org, + (size_t)(address - address_org), handle->skipdata_setup.user_data); + if (skipdata_bytes > code_size) // remaining data is not enough break; @@ -1246,228 +1318,42 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64 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); + 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_cache->mnemonic[0] = '\0'; - insn_cache->op_str[0] = '\0'; + insn->mnemonic[0] = '\0'; + insn->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); + strncpy(insn->mnemonic, handle->skipdata_setup.mnemonic, + sizeof(insn->mnemonic) - 1); + skipdata_opstr(insn->op_str, code, 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_opt) { - 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 beginning - 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_opt) { - 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; + code += next_offset; + code_size -= next_offset; + address += next_offset; } - *insn = total; - - return c; + return buffer->count; } -CAPSTONE_EXPORT -void CAPSTONE_API cs_free(cs_insn *insn, size_t count) -{ - size_t i; - - // free all detail pointers - for (i = 0; i < count; i++) - cs_mem_free(insn[i].detail); - - // then free pointer to cs_insn array - cs_mem_free(insn); -} - -CAPSTONE_EXPORT -cs_insn * CAPSTONE_API 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_opt) { - // 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 bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size, - uint64_t *address, cs_insn *insn) + uint64_t *address, cs_buffer *buffer) { - 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); - - // adjust for pseudo opcode (X86) - if (handle->arch == CS_ARCH_X86) - insn->id += mci.popcode_adjust; - - *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; -#ifdef CAPSTONE_DIET - insn->mnemonic[0] = '\0'; - insn->op_str[0] = '\0'; -#else - 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); -#endif - - *code += skipdata_bytes; - *size -= skipdata_bytes; - *address += skipdata_bytes; - } - - return true; + bool ret = cs_disasm(ud, *code, *size, *address, 1, buffer); + if (ret) { + cs_insn *insn = &buffer->insn[0]; + *code += insn->size; + *size -= insn->size; + *address += insn->size; + } + return ret; } // return friendly name of register in a string diff --git a/cstool/cstool.c b/cstool/cstool.c index 670450eaf9..51399673ec 100644 --- a/cstool/cstool.c +++ b/cstool/cstool.c @@ -444,7 +444,7 @@ int main(int argc, char **argv) uint8_t *assembly; size_t count, size; uint64_t address = 0LL; - cs_insn *insn; + cs_buffer *buffer; cs_err err; cs_mode md; cs_arch arch = CS_ARCH_ALL; @@ -454,6 +454,7 @@ int main(int argc, char **argv) bool custom_reg_alias = false; bool set_real_detail = false; int args_left; + int ret = 0; while ((c = getopt (argc, argv, "rasudhv")) != -1) { switch (c) { @@ -643,8 +644,14 @@ int main(int argc, char **argv) cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL); } - count = cs_disasm(handle, assembly, size, address, 0, &insn); + buffer = cs_buffer_new(0); + if (!buffer) { + printf("ERROR: Failed on cs_buffer_new(), quit!\n"); + return -1; + } + count = cs_disasm(handle, assembly, size, address, 0, buffer); if (count > 0) { + cs_insn *insn = buffer->insn; for (i = 0; i < count; i++) { int j; @@ -676,17 +683,14 @@ int main(int argc, char **argv) print_details(handle, arch, md, &insn[i]); } } - - cs_free(insn, count); - free(assembly); } else { printf("ERROR: invalid assembly code\n"); - cs_close(&handle); - free(assembly); - return(-4); + ret = -4; } + cs_buffer_free(buffer); cs_close(&handle); + free(assembly); - return 0; + return ret; } diff --git a/include/capstone/capstone.h b/include/capstone/capstone.h index 4fed66ef08..7d4cc28308 100644 --- a/include/capstone/capstone.h +++ b/include/capstone/capstone.h @@ -487,6 +487,15 @@ typedef struct cs_insn { /// NOTE: this macro works with position (>=1), not index #define CS_INSN_OFFSET(insns, post) (insns[post - 1].address - insns[0].address) +/// Dynamic buffer for disassembled instructions. +typedef struct cs_buffer { + /// Dynamic array for disassembled instructions. + cs_insn *insn; + /// Capacity of @insn array. + size_t capacity; + /// The number of disassembled instructions in @insn. + size_t count; +} cs_buffer; /// All type of errors encountered by Capstone API. /// These are values returned by cs_errno() @@ -654,96 +663,112 @@ CAPSTONE_EXPORT const char * CAPSTONE_API cs_strerror(cs_err code); /** - Disassemble binary code, given the code buffer, size, address and number - of instructions to be decoded. - This API dynamically allocate memory to contain disassembled instruction. - Resulting instructions will be put into @*insn - - NOTE 1: this API will automatically determine memory needed to contain - output disassembled instructions in @insn. - - NOTE 2: caller must free the allocated memory itself to avoid memory leaking. - - NOTE 3: for system with scarce memory to be dynamically allocated such as - OS kernel or firmware, the API cs_disasm_iter() might be a better choice than - cs_disasm(). The reason is that with cs_disasm(), based on limited available - memory, we have to calculate in advance how many instructions to be disassembled, - which complicates things. This is especially troublesome for the case @count=0, - when cs_disasm() runs uncontrollably (until either end of input buffer, or - when it encounters an invalid instruction). - - @handle: handle returned by cs_open() - @code: buffer containing raw binary code to be disassembled. - @code_size: size of the above code buffer. - @address: address of the first instruction in given raw code buffer. - @insn: array of instructions filled in by this API. - NOTE: @insn will be allocated by this function, and should be freed - with cs_free() API. - @count: number of instructions to be disassembled, or 0 to get all of them + Allocate dynamic buffer for instructions to be used by cs_disasm(). - @return: the number of successfully disassembled instructions, - or 0 if this function failed to disassemble the given code + Use cs_buffer_free() to free memory. - On failure, call cs_errno() for error code. + @capacity: initial capacity of the buffer. Pass 0 to use default. + + @return: returns a pointer to new instruction buffer. */ CAPSTONE_EXPORT -size_t CAPSTONE_API cs_disasm(csh handle, - const uint8_t *code, size_t code_size, - uint64_t address, - size_t count, - cs_insn **insn); +cs_buffer * CAPSTONE_API cs_buffer_new(size_t capacity); /** - Free memory allocated by cs_malloc() or cs_disasm() (argument @insn) + Free an instruction buffer. - @insn: pointer returned by @insn argument in cs_disasm() or cs_malloc() - @count: number of cs_insn structures returned by cs_disasm(), or 1 - to free memory allocated by cs_malloc(). + @buffer: buffer returned by cs_buffer_new(). */ CAPSTONE_EXPORT -void CAPSTONE_API cs_free(cs_insn *insn, size_t count); +void CAPSTONE_API cs_buffer_free(cs_buffer *buffer); + +/** + Clears an instruction buffer. + + cs_buffer_clear() will not free allocated memory use cs_buffer_free() instead. + + @buffer: buffer returned by cs_buffer_new(). + */ +CAPSTONE_EXPORT +void CAPSTONE_API cs_buffer_clear(cs_buffer *buffer); + +/** + Reserve exact size in an instruction buffer. + + If buffer instruction count is greater than @capacity then the instruction + count will be set to @capacity even if call fails. + + @buffer: buffer returned by cs_buffer_new(). + @capacity: required capacity. + + @return: true if this API successfully reserved memory or false otherwise. + */ +CAPSTONE_EXPORT +bool CAPSTONE_API cs_buffer_reserve_exact(cs_buffer *buffer, size_t capacity); + +/** + Reserve additional size in a buffer. + NOTE: cs_buffer_reserve() can reserve more capacity then requested. Use cs_buffer_reserve_exact() + if you need exact buffer capacity. + + The minimum reserved capacity is 16. For example: + cs_buffer *buf = cs_buffer_new(1); + cs_buffer_reserve(buf, 1); + assert(buf->capacity == 16); // but not 2 + + @buffer: buffer returned by cs_buffer_new(). + @additional: additional capacity to allocate. + + @return: true if this API successfully reserved memory or false otherwise. + */ +CAPSTONE_EXPORT +bool CAPSTONE_API cs_buffer_reserve(cs_buffer *buffer, size_t additional); /** - Allocate memory for 1 instruction to be used by cs_disasm_iter(). + Disassemble binary code, given the code @buffer, size, address and number + of instructions to be decoded. + + This API dynamically expands @buffer to fill it with @count instructions. + Clears @buffer before filling it. @handle: handle returned by cs_open() + @code: buffer containing raw binary code to be disassembled. + @code_size: size of the above code buffer. + @address: address of the first instruction in given raw code buffer. + @count: number of instructions to be disassembled, or 0 to get all of them + @buffer: buffer filled in by this API. + + @return: the number of successfully disassembled instructions, + or 0 if this function failed to disassemble the given code - NOTE: when no longer in use, you can reclaim the memory allocated for - this instruction with cs_free(insn, 1) + On failure, call cs_errno() for error code. */ CAPSTONE_EXPORT -cs_insn * CAPSTONE_API cs_malloc(csh handle); +size_t CAPSTONE_API cs_disasm(csh handle, + const uint8_t *code, size_t code_size, + uint64_t address, size_t count, + cs_buffer *buffer); /** - Fast API to disassemble binary code, given the code buffer, size, address - and number of instructions to be decoded. - This API puts the resulting instruction into a given cache in @insn. + Wrapper around cs_disasm() to disassemble one instruction. + + This API puts the resulting instruction into a given @buffer. See tests/test_iter.c for sample code demonstrating this API. - NOTE 1: this API will update @code, @size & @address to point to the next + NOTE 1: this API will update @code, @size and @address to point to the next instruction in the input buffer. Therefore, it is convenient to use cs_disasm_iter() inside a loop to quickly iterate all the instructions. While decoding one instruction at a time can also be achieved with - cs_disasm(count=1), some benchmarks shown that cs_disasm_iter() can be 30% - faster on random input. - - NOTE 2: the cache in @insn can be created with cs_malloc() API. - - NOTE 3: for system with scarce memory to be dynamically allocated such as - OS kernel or firmware, this API is recommended over cs_disasm(), which - allocates memory based on the number of instructions to be disassembled. - The reason is that with cs_disasm(), based on limited available memory, - we have to calculate in advance how many instructions to be disassembled, - which complicates things. This is especially troublesome for the case - @count=0, when cs_disasm() runs uncontrollably (until either end of input - buffer, or when it encounters an invalid instruction). - + cs_disasm(count=1). + @handle: handle returned by cs_open() @code: buffer containing raw binary code to be disassembled @size: size of above code @address: address of the first insn in given raw code buffer @insn: pointer to instruction to be filled in by this API. + @count: number of instructions to be disassembled, or 0 to get all of them + @buffer: buffer filled in by this API. @return: true if this API successfully decode 1 instruction, or false otherwise. @@ -752,8 +777,8 @@ cs_insn * CAPSTONE_API cs_malloc(csh handle); */ CAPSTONE_EXPORT bool CAPSTONE_API cs_disasm_iter(csh handle, - const uint8_t **code, size_t *size, - uint64_t *address, cs_insn *insn); + const uint8_t **code, size_t *size, + uint64_t *address, cs_buffer *buffer); /** Return friendly name of register in a string. diff --git a/suite/arm/test_arm_regression.c b/suite/arm/test_arm_regression.c index fade56b490..fd0db762ea 100644 --- a/suite/arm/test_arm_regression.c +++ b/suite/arm/test_arm_regression.c @@ -171,7 +171,7 @@ static void test_invalids() struct invalid_instructions * invalid = NULL; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; int j; size_t count; @@ -205,12 +205,14 @@ static void test_invalids() free(hex_str); - count = cs_disasm(handle, - invalid_code->code, invalid_code->size, address, 0, &insn - ); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, invalid_code->code, invalid_code->size, + address, 0, buffer); if (count) { size_t k; + cs_insn *insn = buffer->insn; + printf(" ERROR:\n"); for (k = 0; k < count; k++) { @@ -218,13 +220,13 @@ static void test_invalids() insn[k].address, insn[k].mnemonic, insn[k].op_str); print_insn_detail(&insn[k]); } - cs_free(insn, count); } else { printf(" SUCCESS: invalid\n"); } } + cs_buffer_free(buffer); cs_close(&handle); } } @@ -286,7 +288,7 @@ static void test_valids() struct valid_instructions *valid = NULL; - cs_insn *insn; + cs_buffer *buffer; int i; int j; size_t count; @@ -333,15 +335,17 @@ static void test_valids() free(hex_str); + buffer = cs_buffer_new(0); count = cs_disasm(handle, valid_code->code, valid_code->size, - valid_code->start_addr, 0, &insn + valid_code->start_addr, 0, buffer ); if (count) { size_t k; size_t max_len = 0; size_t tmp_len = 0; + cs_insn *insn = buffer->insn; for (k = 0; k < count; k++) { _this_printf( @@ -368,14 +372,12 @@ static void test_valids() } else { printf(" SUCCESS: valid\n"); } - - cs_free(insn, count); - } else { printf("ERROR: invalid\n"); } } + cs_buffer_free(buffer); cs_close(&handle); } diff --git a/suite/benchmark/test_file_benchmark.c b/suite/benchmark/test_file_benchmark.c index 3ffe01e63f..c9f83abc98 100644 --- a/suite/benchmark/test_file_benchmark.c +++ b/suite/benchmark/test_file_benchmark.c @@ -7,7 +7,7 @@ int main(int argc, char* argv[]) { csh handle = 0; - cs_insn *insn = NULL; + cs_buffer *buffer = NULL; int ret = 0; const uint8_t *code_iter = NULL; size_t code_len_iter = 0; @@ -31,8 +31,8 @@ int main(int argc, char* argv[]) goto leave; } - insn = cs_malloc(handle); - if (!insn) + buffer = cs_buffer_new(0); + if (!buffer) { fputs("Failed to allocate memory\n", stderr); ret = 1; @@ -51,7 +51,7 @@ int main(int argc, char* argv[]) &code_iter, &code_len_iter, &ip, - insn + buffer )) { ++code_iter; @@ -75,8 +75,8 @@ int main(int argc, char* argv[]) ); leave: - if (insn) cs_free(insn, 1); + if (buffer) cs_buffer_free(buffer); if (handle) cs_close(&handle); if (code) free(code); return ret; -} \ No newline at end of file +} diff --git a/suite/benchmark/test_iter_benchmark.c b/suite/benchmark/test_iter_benchmark.c index 860f2628f9..52cbd4129e 100644 --- a/suite/benchmark/test_iter_benchmark.c +++ b/suite/benchmark/test_iter_benchmark.c @@ -57,7 +57,7 @@ static void test() csh handle; uint64_t address; - cs_insn *insn; + cs_buffer *buffer; int i; cs_err err; const uint8_t *code; @@ -76,16 +76,16 @@ static void test() start = clock(); int maxcount = 10000000; - insn = cs_malloc(handle); + buffer = cs_buffer_new(1); for (i = 0; i < maxcount;) { code = (const uint8_t *)X86_CODE32; address = 0x1000; size = sizeof(X86_CODE32) - 1; - while(cs_disasm_iter(handle, &code, &size, &address, insn)) { + while(cs_disasm_iter(handle, &code, &size, &address, buffer)) { i++; } } - cs_free(insn, 1); + cs_buffer_free(buffer); cs_close(&handle); end = clock(); timeUsed = (double)(end - start) / CLOCKS_PER_SEC; diff --git a/suite/cstest/src/capstone_test.c b/suite/cstest/src/capstone_test.c index 91ccbd7280..ff286b12cd 100644 --- a/suite/cstest/src/capstone_test.c +++ b/suite/cstest/src/capstone_test.c @@ -13,6 +13,7 @@ void test_single_MC(csh *handle, int mc_mode, char *line) int size_part, size_byte; int i, count; unsigned char *code; + cs_buffer *buffer; cs_insn *insn; char tmp[MAXMEM], tmp_mc[MAXMEM], origin[MAXMEM], tmp_noreg[MAXMEM]; char **offset_opcode; @@ -41,7 +42,9 @@ void test_single_MC(csh *handle, int mc_mode, char *line) } ((struct cs_struct *)(uintptr_t)*handle)->PrintBranchImmNotAsAddress = true; - count = cs_disasm(*handle, code, size_byte, offset, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(*handle, code, size_byte, offset, 0, buffer); + insn = buffer->insn; if (count == 0) { fprintf(stderr, "[ ERROR ] --- %s --- Failed to disassemble given code!\n", list_part[0]); free_strs(list_part, size_part); @@ -85,11 +88,8 @@ void test_single_MC(csh *handle, int mc_mode, char *line) // and laeds to wrong results. cs_arch arch = ((struct cs_struct *)(uintptr_t)*handle)->arch; if (arch != CS_ARCH_ARM) { - if (insn->detail) { - free(insn->detail); - } - free(insn); - cs_disasm(*handle, code, size_byte, offset, 0, &insn); + cs_disasm(*handle, code, size_byte, offset, 0, buffer); + insn = buffer->insn; strcpy(tmp_noreg, insn[0].mnemonic); if (strlen(insn[0].op_str) > 0) { @@ -107,7 +107,7 @@ void test_single_MC(csh *handle, int mc_mode, char *line) free_strs(offset_opcode, size_offset_opcode); free_strs(list_byte, size_byte); free(code); - cs_free(insn, count); + cs_buffer_free(buffer); _fail(__FILE__, __LINE__); } } else if (strcmp(tmp, tmp_mc)) { @@ -116,7 +116,7 @@ void test_single_MC(csh *handle, int mc_mode, char *line) free_strs(offset_opcode, size_offset_opcode); free_strs(list_byte, size_byte); free(code); - cs_free(insn, count); + cs_buffer_free(buffer); _fail(__FILE__, __LINE__); } @@ -124,7 +124,7 @@ void test_single_MC(csh *handle, int mc_mode, char *line) free_strs(offset_opcode, size_offset_opcode); free_strs(list_byte, size_byte); free(code); - cs_free(insn, count); + cs_buffer_free(buffer); } int get_value(single_dict d[], unsigned int size, const char *str) @@ -217,6 +217,7 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) int size_part, size_byte, size_part_issue_result; int i, count, j; unsigned char *code; + cs_buffer *buffer; cs_insn *insn; char *cs_result, *tmp, *p; char **offset_opcode; @@ -243,7 +244,9 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) code[i] = (unsigned char)strtol(list_byte[i], NULL, 16); } - count = cs_disasm(*handle, code, size_byte, offset, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(*handle, code, size_byte, offset, 0, buffer); + insn = buffer->insn; free_strs(list_byte, size_byte); free(code); for (i = 0; i < count; ++i) { @@ -285,7 +288,7 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) if ((strstr(cs_result, tmptmp)) == NULL) { fprintf(stderr, "[ ERROR ] --- %s --- \"%s\" not in \"%s\"\n", list_part[0], list_part_issue_result[i], cs_result); - cs_free(insn, count); + cs_buffer_free(buffer); free_strs(list_part, size_part); free(cs_result); // free_strs(list_part_cs_result, size_part_cs_result); @@ -296,7 +299,7 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) free(tmptmp); } - cs_free(insn, count); + cs_buffer_free(buffer); free_strs(list_part, size_part); free(cs_result); // free_strs(list_part_cs_result, size_part_cs_result); diff --git a/suite/fuzz/fuzz_diff.c b/suite/fuzz/fuzz_diff.c index f0f39fdc67..56308523ad 100644 --- a/suite/fuzz/fuzz_diff.c +++ b/suite/fuzz/fuzz_diff.c @@ -179,7 +179,7 @@ int LLVMFuzzerReturnOneInput(const uint8_t *Data, size_t Size, char * AssemblyTe int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { csh handle; - cs_insn *insn; + cs_buffer *buffer; cs_err err; const uint8_t **Datap = &Data; size_t * Sizep = &Size; @@ -216,11 +216,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; } - insn = cs_malloc(handle); + buffer = cs_buffer_new(1); Data++; Size--; - assert(insn); - if (cs_disasm_iter(handle, Datap, Sizep, &address, insn)) { + assert(buffer); + if (cs_disasm_iter(handle, Datap, Sizep, &address, buffer)) { + cs_insn *insn = buffer->insn; snprintf(CapstoneAssemblyText, 80, "\t%s\t%s", insn->mnemonic, insn->op_str); if (strcmp(CapstoneAssemblyText, LLVMAssemblyText) != 0) { printf("capstone %s != llvm %s", CapstoneAssemblyText, LLVMAssemblyText); @@ -230,7 +231,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { printf("capstone failed with llvm %s", LLVMAssemblyText); abort(); } - cs_free(insn, 1); + cs_buffer_free(buffer); cs_close(&handle); return 0; diff --git a/suite/fuzz/fuzz_disasm.c b/suite/fuzz/fuzz_disasm.c index b402e7eecd..90c99e60b1 100644 --- a/suite/fuzz/fuzz_disasm.c +++ b/suite/fuzz/fuzz_disasm.c @@ -18,7 +18,7 @@ static FILE *outfile = NULL; int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { csh handle; - cs_insn *all_insn; + cs_buffer *buffer; cs_detail *detail; cs_err err; unsigned int i; @@ -52,12 +52,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); } + buffer = cs_buffer_new(0); uint64_t address = 0x1000; - size_t count = cs_disasm(handle, Data+1, Size-1, address, 0, &all_insn); + size_t count = cs_disasm(handle, Data+1, Size-1, address, 0, buffer); if (count) { size_t j; unsigned int n; + cs_insn *all_insn = buffer->insn; for (j = 0; j < count; j++) { cs_insn *insn = &(all_insn[j]); @@ -90,9 +92,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { } fprintf(outfile, "0x%"PRIx64":\n", all_insn[j-1].address + all_insn[j-1].size); - cs_free(all_insn, count); } + cs_buffer_free(buffer); cs_close(&handle); return 0; diff --git a/tests/test_aarch64.c b/tests/test_aarch64.c index a5e74f19e8..5ba766cad4 100644 --- a/tests/test_aarch64.c +++ b/tests/test_aarch64.c @@ -288,7 +288,7 @@ static void test() }; uint64_t address = 0x2c; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -301,9 +301,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -315,9 +317,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -328,6 +327,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_alpha.c b/tests/test_alpha.c index 0206f25f66..4034ed40e5 100644 --- a/tests/test_alpha.c +++ b/tests/test_alpha.c @@ -85,7 +85,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -100,10 +100,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + buffer = cs_buffer_new(0); count = cs_disasm(handle, platforms[i].code, platforms[i].size, - address, 0, &insn); + address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -119,9 +121,6 @@ static void test() } printf("0x%" PRIx64 ":\n", insn[j - 1].address + insn[j - 1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -132,6 +131,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_arm.c b/tests/test_arm.c index 0696de5729..ade520f455 100644 --- a/tests/test_arm.c +++ b/tests/test_arm.c @@ -279,7 +279,7 @@ static void test() }; uint64_t address = 0x80001000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -295,9 +295,12 @@ static void test() if (platforms[i].syntax) cs_option(handle, CS_OPT_SYNTAX, platforms[i].syntax); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; + printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex("Code:", platforms[i].code, platforms[i].size); @@ -308,9 +311,6 @@ static void test() print_insn_detail(handle, &insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -321,6 +321,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_basic.c b/tests/test_basic.c index dbd37a9ffd..628ec725b9 100644 --- a/tests/test_basic.c +++ b/tests/test_basic.c @@ -424,7 +424,7 @@ static void test() csh handle; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; cs_err err; @@ -441,9 +441,11 @@ static void test() if (platforms[i].opt_type) cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); @@ -455,9 +457,6 @@ static void test() // print out the next offset, after the last insn printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -468,6 +467,9 @@ static void test() printf("\n"); + + // free memory allocated by cs_buffer_new() + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_bpf.c b/tests/test_bpf.c index b97e330cbf..320fc93ef3 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -140,7 +140,7 @@ static void test() }, }; uint64_t address = 0x0; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -153,9 +153,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; + printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex("Code:", platforms[i].code, platforms[i].size); @@ -165,9 +168,6 @@ static void test() printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); print_insn_detail(handle, &insn[j]); } - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -176,6 +176,7 @@ static void test() abort(); } + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_customized_mnem.c b/tests/test_customized_mnem.c index 5d523def9e..b02b413300 100644 --- a/tests/test_customized_mnem.c +++ b/tests/test_customized_mnem.c @@ -26,19 +26,20 @@ static void print_string_hex(unsigned char *str, size_t len) // Print one instruction static void print_insn(csh handle) { - cs_insn *insn; + cs_buffer *buffer; size_t count; - count = cs_disasm(handle, (const uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1, 0x1000, 1, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, (const uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1, 0x1000, 1, buffer); if (count) { + cs_insn *insn = buffer->insn; print_string_hex((unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1); printf("\t%s\t%s\n", insn[0].mnemonic, insn[0].op_str); - // Free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("ERROR: Failed to disasm given code!\n"); abort(); } + cs_buffer_free(buffer); } static void test() diff --git a/tests/test_detail.c b/tests/test_detail.c index ab8de7e1f5..736d8a0734 100644 --- a/tests/test_detail.c +++ b/tests/test_detail.c @@ -341,8 +341,7 @@ static void test() csh handle; uint64_t address = 0x1000; - cs_insn *all_insn; - cs_detail *detail; + cs_buffer *buffer; int i; size_t count; cs_err err; @@ -361,10 +360,13 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &all_insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; int n; + cs_insn *all_insn = buffer->insn; + cs_detail *detail; print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); @@ -407,9 +409,6 @@ static void test() // print out the next offset, after the last insn printf("0x%" PRIx64 ":\n", all_insn[j-1].address + all_insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(all_insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -420,6 +419,9 @@ static void test() printf("\n"); + + // free memory allocated by cs_buffer_new() + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_evm.c b/tests/test_evm.c index 7fd0aa30ff..9b1ade04b2 100644 --- a/tests/test_evm.c +++ b/tests/test_evm.c @@ -74,7 +74,7 @@ static void test() }; uint64_t address = 0x80001000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -87,9 +87,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; + printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex("Code:", platforms[i].code, platforms[i].size); @@ -100,9 +103,6 @@ static void test() print_insn_detail(handle, &insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -113,6 +113,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_hppa.c b/tests/test_hppa.c index d96693cc76..c4b4f5d922 100644 --- a/tests/test_hppa.c +++ b/tests/test_hppa.c @@ -127,7 +127,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -142,10 +142,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + buffer = cs_buffer_new(0); count = cs_disasm(handle, platforms[i].code, platforms[i].size, - address, 0, &insn); + address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -161,9 +163,6 @@ static void test() } printf("0x%" PRIx64 ":\n", insn[j - 1].address + insn[j - 1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -174,6 +173,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_iter.c b/tests/test_iter.c index 172d2c6a39..7bcef4c25e 100644 --- a/tests/test_iter.c +++ b/tests/test_iter.c @@ -1,7 +1,7 @@ /* Capstone Disassembler Engine */ /* By Nguyen Anh Quynh , 2013-2019 */ -// This sample code demonstrates the APIs cs_malloc() & cs_disasm_iter(). +// This sample code demonstrates the APIs cs_buffer_new() & cs_disasm_iter(). #include #include @@ -324,7 +324,7 @@ struct platform platforms[] = { csh handle; uint64_t address; - cs_insn *insn; + cs_buffer *buffer; cs_detail *detail; int i; cs_err err; @@ -346,7 +346,7 @@ struct platform platforms[] = { cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); // allocate memory for the cache to be used by cs_disasm_iter() - insn = cs_malloc(handle); + buffer = cs_buffer_new(1); print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); @@ -354,8 +354,9 @@ struct platform platforms[] = { address = 0x1000; code = platforms[i].code; size = platforms[i].size; - while(cs_disasm_iter(handle, &code, &size, &address, insn)) { + while(cs_disasm_iter(handle, &code, &size, &address, buffer)) { int n; + cs_insn *insn = buffer->insn; printf("0x%" PRIx64 ":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", insn->address, insn->mnemonic, insn->op_str, @@ -393,9 +394,7 @@ struct platform platforms[] = { printf("\n"); - // free memory allocated by cs_malloc() - cs_free(insn, 1); - + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_m680x.c b/tests/test_m680x.c index aa1f572723..4cfb450266 100644 --- a/tests/test_m680x.c +++ b/tests/test_m680x.c @@ -322,7 +322,7 @@ static void test() uint64_t address = 0x1000; csh handle; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; const char *nine_spaces = " "; @@ -344,11 +344,13 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); #endif + buffer = cs_buffer_new(0); count = cs_disasm(handle, platforms[i].code, platforms[i].size, - address, 0, &insn); + address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("********************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -371,9 +373,6 @@ static void test() print_insn_detail(handle, &insn[j]); #endif } - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("********************\n"); @@ -384,6 +383,7 @@ static void test() abort(); } + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_m68k.c b/tests/test_m68k.c index e003f486be..41ae933b27 100644 --- a/tests/test_m68k.c +++ b/tests/test_m68k.c @@ -168,7 +168,7 @@ static void test() }; uint64_t address = 0x01000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -181,9 +181,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -197,9 +199,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -210,6 +209,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_mips.c b/tests/test_mips.c index e5c5a400c9..40235172a1 100644 --- a/tests/test_mips.c +++ b/tests/test_mips.c @@ -123,7 +123,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -136,9 +136,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -150,9 +152,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -163,6 +162,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_mos65xx.c b/tests/test_mos65xx.c index bb53bea2e8..405e585155 100644 --- a/tests/test_mos65xx.c +++ b/tests/test_mos65xx.c @@ -176,7 +176,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -190,10 +190,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_MOTOROLA); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -206,9 +208,6 @@ static void test() puts(""); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -219,6 +218,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_ppc.c b/tests/test_ppc.c index 2a21cbe7c1..3a90ff3619 100644 --- a/tests/test_ppc.c +++ b/tests/test_ppc.c @@ -126,7 +126,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -139,9 +139,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -153,9 +155,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -166,6 +165,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_riscv.c b/tests/test_riscv.c index 5b5d67c4b7..545ef827cd 100644 --- a/tests/test_riscv.c +++ b/tests/test_riscv.c @@ -101,7 +101,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -116,9 +116,11 @@ static void test() //cs_option(handle, CS_OPT_DETAIL, CS_OPT_OFF); cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -130,9 +132,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -142,6 +141,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_sh.c b/tests/test_sh.c index de49fa0166..fdd20bd167 100644 --- a/tests/test_sh.c +++ b/tests/test_sh.c @@ -188,7 +188,7 @@ static void test() uint64_t address = 0x80000000; csh handle; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -209,11 +209,13 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); #endif + buffer = cs_buffer_new(0); count = cs_disasm(handle, platforms[i].code, platforms[i].size, - address, 0, &insn); + address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -228,9 +230,6 @@ static void test() #endif } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); @@ -241,6 +240,7 @@ static void test() abort(); } + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_skipdata.c b/tests/test_skipdata.c index 8ab046f103..bdb276c796 100644 --- a/tests/test_skipdata.c +++ b/tests/test_skipdata.c @@ -104,7 +104,7 @@ static void test() csh handle; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; cs_err err; int i; size_t count; @@ -125,9 +125,11 @@ static void test() cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); @@ -139,9 +141,6 @@ static void test() // print out the next offset, after the last insn printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -152,6 +151,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_sparc.c b/tests/test_sparc.c index 98c39494eb..0130a43c98 100644 --- a/tests/test_sparc.c +++ b/tests/test_sparc.c @@ -100,7 +100,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -113,9 +113,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -127,9 +129,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -140,6 +139,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_systemz.c b/tests/test_systemz.c index f662247b89..64bed27013 100644 --- a/tests/test_systemz.c +++ b/tests/test_systemz.c @@ -93,7 +93,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -106,9 +106,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -120,9 +122,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -133,6 +132,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_tms320c64x.c b/tests/test_tms320c64x.c index 28bc05e286..464c8fa121 100644 --- a/tests/test_tms320c64x.c +++ b/tests/test_tms320c64x.c @@ -142,7 +142,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -155,9 +155,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -169,9 +171,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%"PRIx64":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -181,6 +180,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_tricore.c b/tests/test_tricore.c index 38e71ba6e8..e7dd671c9c 100644 --- a/tests/test_tricore.c +++ b/tests/test_tricore.c @@ -88,7 +88,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -103,10 +103,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + buffer = cs_buffer_new(0); count = cs_disasm(handle, platforms[i].code, platforms[i].size, - address, 0, &insn); + address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -122,9 +124,6 @@ static void test() } printf("0x%" PRIx64 ":\n", insn[j - 1].address + insn[j - 1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -133,6 +132,7 @@ static void test() printf("ERROR: Failed to disasm given code!\n"); } + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_wasm.c b/tests/test_wasm.c index 95e387d193..7993a8f170 100644 --- a/tests/test_wasm.c +++ b/tests/test_wasm.c @@ -108,7 +108,7 @@ static void test() }; uint64_t address = 0xffff; - cs_insn *insn; + cs_buffer *buffer; size_t count; int i; @@ -121,9 +121,12 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; + printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex("Code: ", platforms[i].code, platforms[i].size); @@ -134,9 +137,6 @@ static void test() print_insn_detail(handle, &insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -147,6 +147,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_x86.c b/tests/test_x86.c index 775c096d33..a8f3f661dc 100644 --- a/tests/test_x86.c +++ b/tests/test_x86.c @@ -409,7 +409,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -425,9 +425,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -439,9 +441,6 @@ static void test() print_insn_detail(handle, platforms[i].mode, &insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -452,6 +451,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } } diff --git a/tests/test_xcore.c b/tests/test_xcore.c index 12cc1f1bba..9a2aa871b7 100644 --- a/tests/test_xcore.c +++ b/tests/test_xcore.c @@ -88,7 +88,7 @@ static void test() }; uint64_t address = 0x1000; - cs_insn *insn; + cs_buffer *buffer; int i; size_t count; @@ -101,9 +101,11 @@ static void test() cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + buffer = cs_buffer_new(0); + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, buffer); if (count) { size_t j; + cs_insn *insn = buffer->insn; printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -115,9 +117,6 @@ static void test() print_insn_detail(&insn[j]); } printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); - - // free memory allocated by cs_disasm() - cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); @@ -128,6 +127,7 @@ static void test() printf("\n"); + cs_buffer_free(buffer); cs_close(&handle); } }