mirror of
https://github.com/capstone-engine/capstone.git
synced 2024-11-23 13:39:46 +00:00
API: support SKIPDATA option (off by default)
This commit is contained in:
parent
b6961b6ceb
commit
d3ffe37c47
127
cs.c
127
cs.c
@ -17,6 +17,9 @@
|
||||
#define INSN_CACHE_SIZE 8
|
||||
#endif
|
||||
|
||||
// default SKIPDATA mnemonic
|
||||
#define SKIPDATA_MNEM ".db"
|
||||
|
||||
cs_err (*arch_init[MAX_ARCH])(cs_struct *) = { NULL };
|
||||
cs_err (*arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = { NULL };
|
||||
void (*arch_destroy[MAX_ARCH]) (cs_struct *) = { NULL };
|
||||
@ -187,6 +190,9 @@ cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
|
||||
// by default, do not break instruction into details
|
||||
ud->detail = CS_OPT_OFF;
|
||||
|
||||
// default skipdata setup
|
||||
ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
|
||||
|
||||
cs_err err = arch_init[ud->arch](ud);
|
||||
if (err) {
|
||||
cs_mem_free(ud);
|
||||
@ -287,6 +293,27 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
|
||||
#endif
|
||||
}
|
||||
|
||||
// how many bytes will we skip when encountering data (CS_OPT_SKIPDATA)?
|
||||
static uint8_t skipdata_size(cs_struct *handle)
|
||||
{
|
||||
switch(handle->arch) {
|
||||
default:
|
||||
// should never reach
|
||||
return -1;
|
||||
case CS_ARCH_ARM:
|
||||
case CS_ARCH_ARM64:
|
||||
case CS_ARCH_MIPS:
|
||||
case CS_ARCH_PPC:
|
||||
case CS_ARCH_SPARC:
|
||||
case CS_ARCH_SYSZ:
|
||||
// skip 2 bytes due to instruction alignment
|
||||
return 2;
|
||||
case CS_ARCH_X86:
|
||||
// X86 has no restriction on instruction alignment
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
cs_err cs_option(csh ud, cs_opt_type type, size_t value)
|
||||
{
|
||||
archs_enable();
|
||||
@ -309,9 +336,25 @@ cs_err cs_option(csh ud, cs_opt_type type, size_t value)
|
||||
if (!handle)
|
||||
return CS_ERR_CSH;
|
||||
|
||||
if (type == CS_OPT_DETAIL) {
|
||||
handle->detail = value;
|
||||
return CS_ERR_OK;
|
||||
switch(type) {
|
||||
default:
|
||||
break;
|
||||
case CS_OPT_DETAIL:
|
||||
handle->detail = value;
|
||||
return CS_ERR_OK;
|
||||
case CS_OPT_SKIPDATA:
|
||||
handle->skipdata = (value == CS_OPT_ON);
|
||||
if (handle->skipdata) {
|
||||
if (handle->skipdata_size == 0) {
|
||||
// set the default skipdata size
|
||||
handle->skipdata_size = skipdata_size(handle);
|
||||
}
|
||||
}
|
||||
return CS_ERR_OK;
|
||||
case CS_OPT_SKIPDATA_SETUP:
|
||||
if (value)
|
||||
handle->skipdata_setup = *((cs_opt_skipdata *)value);
|
||||
return CS_ERR_OK;
|
||||
}
|
||||
|
||||
return arch_option[handle->arch](handle, type, value);
|
||||
@ -330,6 +373,26 @@ static cs_insn *get_prev_insn(cs_insn *cache, unsigned int f, void *total, size_
|
||||
return &cache[f - 1];
|
||||
}
|
||||
|
||||
static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size)
|
||||
{
|
||||
char *p = opstr;
|
||||
int len;
|
||||
size_t i;
|
||||
|
||||
if (!size) {
|
||||
opstr[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
len = sprintf(p, "0x%02x", buffer[0]);
|
||||
p+= len;
|
||||
|
||||
for(i = 1; i < size; i++) {
|
||||
len = sprintf(p, ", 0x%02x", buffer[i]);
|
||||
p+= len;
|
||||
}
|
||||
}
|
||||
|
||||
// dynamicly allocate memory to contain disasm insn
|
||||
// NOTE: caller must free() the allocated memory itself to avoid memory leaking
|
||||
size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
|
||||
@ -343,6 +406,8 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||
void *total = NULL;
|
||||
size_t total_size = 0;
|
||||
bool r;
|
||||
void *tmp;
|
||||
size_t skipdata_bytes;
|
||||
|
||||
if (!handle) {
|
||||
// FIXME: how to handle this case:
|
||||
@ -384,11 +449,8 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||
|
||||
if (!handle->check_combine || !handle->check_combine(handle, &insn_cache[f])) {
|
||||
f++;
|
||||
|
||||
if (f == ARR_SIZE(insn_cache)) {
|
||||
// resize total to contain newly disasm insns
|
||||
void *tmp;
|
||||
|
||||
total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
|
||||
tmp = cs_mem_realloc(total, total_size);
|
||||
if (tmp == NULL) { // insufficient memory
|
||||
@ -436,8 +498,57 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||
}
|
||||
} else {
|
||||
// encounter a broken instruction
|
||||
// XXX: TODO: JOXEAN continue here
|
||||
break;
|
||||
// if there is no request to skip data, or remaining data is too small,
|
||||
// then bail out
|
||||
if (!handle->skipdata || handle->skipdata_size > size)
|
||||
break;
|
||||
|
||||
if (handle->skipdata_setup.callback) {
|
||||
skipdata_bytes = handle->skipdata_setup.callback(offset,
|
||||
handle->skipdata_setup.user_data);
|
||||
if (skipdata_bytes > size)
|
||||
// remaining data is not enough
|
||||
break;
|
||||
|
||||
if (!skipdata_bytes)
|
||||
// user requested not to skip data, so bail out
|
||||
break;
|
||||
} else
|
||||
skipdata_bytes = handle->skipdata_size;
|
||||
|
||||
// we have to skip some amount of data, depending on arch & mode
|
||||
insn_cache[f].id = 0; // invalid ID for this "data" instruction
|
||||
insn_cache[f].address = offset;
|
||||
insn_cache[f].size = skipdata_bytes;
|
||||
memcpy(insn_cache[f].bytes, buffer, skipdata_bytes);
|
||||
strncpy(insn_cache[f].mnemonic, handle->skipdata_setup.mnemonic,
|
||||
sizeof(insn_cache[f].mnemonic) - 1);
|
||||
skipdata_opstr(insn_cache[f].op_str, buffer, skipdata_bytes);
|
||||
insn_cache[f].detail = NULL;
|
||||
|
||||
f++;
|
||||
if (f == ARR_SIZE(insn_cache)) {
|
||||
// resize total to contain newly disasm insns
|
||||
|
||||
total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
|
||||
tmp = cs_mem_realloc(total, total_size);
|
||||
if (tmp == NULL) { // insufficient memory
|
||||
cs_mem_free(total);
|
||||
handle->errnum = CS_ERR_MEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
total = tmp;
|
||||
memcpy((void*)((uintptr_t)total + total_size - sizeof(insn_cache)), insn_cache, sizeof(insn_cache));
|
||||
|
||||
// reset f back to 0
|
||||
f = 0;
|
||||
}
|
||||
|
||||
buffer += skipdata_bytes;
|
||||
size -= skipdata_bytes;
|
||||
offset += skipdata_bytes;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,9 @@ struct cs_struct {
|
||||
CombineInsn_t combine;
|
||||
GetRegisterName_t get_regname;
|
||||
uint8_t prev_prefix; // save previous prefix for combining instructions - X86 only.
|
||||
bool skipdata; // set this to True if we skip data when disassembling
|
||||
uint8_t skipdata_size; // how many bytes to skip
|
||||
cs_opt_skipdata skipdata_setup; // user-defined skipdata setup
|
||||
};
|
||||
|
||||
#define MAX_ARCH 8
|
||||
|
@ -90,18 +90,45 @@ typedef enum cs_opt_type {
|
||||
CS_OPT_DETAIL, // Break down instruction structure into details
|
||||
CS_OPT_MODE, // Change engine's mode at run-time
|
||||
CS_OPT_MEM, // User-defined dynamic memory related functions
|
||||
CS_OPT_SKIPDATA, // Skip data when disassembling
|
||||
CS_OPT_SKIPDATA_SETUP, // Setup user-defined function for SKIPDATA option
|
||||
} cs_opt_type;
|
||||
|
||||
// Runtime option value (associated with option type above)
|
||||
typedef enum cs_opt_value {
|
||||
CS_OPT_OFF = 0, // Turn OFF an option - default option for CS_OPT_DETAIL.
|
||||
CS_OPT_ON = 3, // Turn ON an option (CS_OPT_DETAIL).
|
||||
CS_OPT_OFF = 0, // Turn OFF an option - default option of CS_OPT_DETAIL, CS_OPT_SKIPDATA.
|
||||
CS_OPT_ON = 3, // Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
|
||||
CS_OPT_SYNTAX_DEFAULT = 0, // Default asm syntax (CS_OPT_SYNTAX).
|
||||
CS_OPT_SYNTAX_INTEL, // X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
|
||||
CS_OPT_SYNTAX_ATT, // X86 ATT asm syntax (CS_OPT_SYNTAX).
|
||||
CS_OPT_SYNTAX_NOREGNAME, // Prints register name with only number (CS_OPT_SYNTAX)
|
||||
} cs_opt_value;
|
||||
|
||||
// User-defined callback function for SKIPDATA option
|
||||
// @offset: offset of the input buffer passed to cs_disasm_ex().
|
||||
// This indicates the position of data Capstone is examining
|
||||
// @user_data: user-data passed to cs_option() via @user_data field in
|
||||
// cs_opt_skipdata struct below.
|
||||
// @return: return number of bytes to skip, or 0 to stop disassembling.
|
||||
typedef size_t (*cs_skipdata_cb_t)(size_t offset, void* user_data);
|
||||
|
||||
// User-defined setup for SKIPDATA option
|
||||
typedef struct cs_opt_skipdata {
|
||||
// Capstone considers data to skip as special "instructions".
|
||||
// User can specify the string for this instruction's "mnemonic" here.
|
||||
// By default (if @mnemonic is NULL), Capstone use ".db".
|
||||
const char *mnemonic;
|
||||
// User-defined callback function to be called when Capstone hits data.
|
||||
// If the returned value from this callback is positive (>0), Capstone will skip exactly
|
||||
// that number of bytes & continue. Otherwise, if the callback returns 0, Capstone stops
|
||||
// disassembling and returns immediately from cs_disasm_ex()
|
||||
// NOTE: if this callback pointer is NULL, Capstone skip 1 byte on X86, and 2 bytes on
|
||||
// every other architectures.
|
||||
cs_skipdata_cb_t callback; // default value is NULL
|
||||
// User-defined data to be passed to @callback function pointer.
|
||||
void *user_data;
|
||||
} cs_opt_skipdata;
|
||||
|
||||
|
||||
#include "arm.h"
|
||||
#include "arm64.h"
|
||||
|
Loading…
Reference in New Issue
Block a user