Skip to content

Commit

Permalink
New API: cs_disasm_iter
Browse files Browse the repository at this point in the history
  • Loading branch information
hlide committed Oct 5, 2014
1 parent 1b7ccbf commit 993f362
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 12 deletions.
89 changes: 89 additions & 0 deletions cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions cs_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 18 additions & 12 deletions include/capstone.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 993f362

Please sign in to comment.