new option CS_OPT_MNEMONIC to customize instruction mnemonic

This commit is contained in:
Nguyen Anh Quynh
2015-04-26 22:54:41 +08:00
parent 2f263f58d8
commit 0b96545f66
7 changed files with 202 additions and 3 deletions

1
.gitignore vendored
View File

@@ -58,6 +58,7 @@ tests/test_sparc
tests/test_systemz
tests/test_xcore
tests/*.static
tests/test_customized_mnem
# vim tmp file
*.swp

View File

@@ -80,7 +80,7 @@ set(HEADERS_COMMON
)
set(TEST_SOURCES test.c test_detail.c test_skipdata.c test_iter.c)
set(TEST_SOURCES test.c test_detail.c test_skipdata.c test_iter.c test_customized_mnem.c)
## architecture support
if (CAPSTONE_ARM_SUPPORT)

84
cs.c
View File

@@ -233,6 +233,7 @@ CAPSTONE_EXPORT
cs_err cs_close(csh *handle)
{
struct cs_struct *ud;
struct insn_mnem *next, *tmp;
if (*handle == 0)
// invalid handle
@@ -243,6 +244,14 @@ cs_err cs_close(csh *handle)
if (ud->printer_info)
cs_mem_free(ud->printer_info);
// free the linked list of customized mnemonic
tmp = ud->mnem_list;
while(tmp) {
next = tmp->next;
cs_mem_free(tmp);
tmp = next;
}
cs_mem_free(ud->insn_cache);
memset(ud, 0, sizeof(*ud));
@@ -294,6 +303,20 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
*mnem = '\0';
// we might have customized mnemonic
if (handle->mnem_list) {
struct insn_mnem *tmp = handle->mnem_list;
while(tmp) {
if (tmp->insn.id == insn->id) {
// found this instruction, so copy its mnemonic
(void)strncpy(insn->mnemonic, tmp->insn.mnemonic, sizeof(insn->mnemonic) - 1);
insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
break;
}
tmp = tmp->next;
}
}
// copy @op_str
if (*sp) {
// find the next non-space char
@@ -344,6 +367,8 @@ CAPSTONE_EXPORT
cs_err cs_option(csh ud, cs_opt_type type, size_t value)
{
struct cs_struct *handle;
cs_opt_mnem *opt;
archs_enable();
// cs_option() can be called with NULL handle just for CS_OPT_MEM
@@ -367,9 +392,11 @@ cs_err cs_option(csh ud, cs_opt_type type, size_t value)
switch(type) {
default:
break;
case CS_OPT_DETAIL:
handle->detail = (cs_opt_value)value;
return CS_ERR_OK;
case CS_OPT_SKIPDATA:
handle->skipdata = (value == CS_OPT_ON);
if (handle->skipdata) {
@@ -379,10 +406,67 @@ cs_err cs_option(csh ud, cs_opt_type type, size_t value)
}
}
return CS_ERR_OK;
case CS_OPT_SKIPDATA_SETUP:
if (value)
handle->skipdata_setup = *((cs_opt_skipdata *)value);
return CS_ERR_OK;
case CS_OPT_MNEMONIC:
opt = (cs_opt_mnem *)value;
if (opt->id) {
if (opt->mnemonic) {
struct insn_mnem *tmp;
// add new instruction, or replace existing instruction
// 1. find if we already had this insn in the linked list
tmp = handle->mnem_list;
while(tmp) {
if (tmp->insn.id == opt->id) {
// found this instruction, so replace its mnemonic
(void)strncpy(tmp->insn.mnemonic, opt->mnemonic, sizeof(tmp->insn.mnemonic) - 1);
tmp->insn.mnemonic[sizeof(tmp->insn.mnemonic) - 1] = '\0';
break;
}
tmp = tmp->next;
}
// 2. add this instruction if we have not had it yet
if (!tmp) {
tmp = cs_mem_malloc(sizeof(*tmp));
tmp->insn.id = opt->id;
(void)strncpy(tmp->insn.mnemonic, opt->mnemonic, sizeof(tmp->insn.mnemonic) - 1);
tmp->insn.mnemonic[sizeof(tmp->insn.mnemonic) - 1] = '\0';
// this new instruction is heading the list
tmp->next = handle->mnem_list;
handle->mnem_list = tmp;
}
return CS_ERR_OK;
} else {
struct insn_mnem *prev, *tmp;
// we want to delete an existing instruction
// iterate the list to find the instruction to remove it
tmp = handle->mnem_list;
prev = tmp;
while(tmp) {
if (tmp->insn.id == opt->id) {
// delete this instruction
if (tmp == prev) {
// head of the list
handle->mnem_list = tmp->next;
} else {
prev->next = tmp->next;
}
cs_mem_free(tmp);
break;
}
prev = tmp;
tmp = tmp->next;
}
}
}
return CS_ERR_OK;
}
return arch_option[handle->arch](handle, type, value);

View File

@@ -35,6 +35,19 @@ typedef struct ARM_ITStatus {
unsigned int size;
} ARM_ITStatus;
// Customize mnemonic for instructions with alternative name.
struct customized_mnem {
// ID of instruction to be customized.
unsigned int id;
// Customized instruction mnemonic.
char mnemonic[MNEMONIC_SIZE];
};
struct insn_mnem {
struct customized_mnem insn;
struct insn_mnem *next; // linked list of customized mnemonics
};
struct cs_struct {
cs_arch arch;
cs_mode mode;
@@ -60,6 +73,7 @@ struct cs_struct {
cs_opt_skipdata skipdata_setup; // user-defined skipdata setup
uint8_t *regsize_map; // map to register size (x86-only for now)
GetRegisterAccess_t reg_access;
struct insn_mnem *mnem_list; // linked list of customized instruction mnemonic
};
#define MAX_ARCH 8

View File

@@ -57,6 +57,8 @@ extern "C" {
// result of cs_version() API.
#define CS_MAKE_VERSION(major, minor) ((major << 8) + minor)
#define MNEMONIC_SIZE 32
// Handle using with all API
typedef size_t csh;
@@ -121,6 +123,17 @@ typedef struct cs_opt_mem {
cs_vsnprintf_t vsnprintf;
} cs_opt_mem;
// Customize mnemonic for instructions with alternative name.
// To reset existing customized instruction to its default mnemonic,
// call cs_option(CS_OPT_MNEMONIC) again with the same @id and NULL value
// for @mnemonic.
typedef struct cs_opt_mnem {
// ID of instruction to be customized.
unsigned int id;
// Customized instruction mnemonic.
char *mnemonic;
} cs_opt_mnem;
// Runtime option for the disassembled engine
typedef enum cs_opt_type {
CS_OPT_SYNTAX = 1, // Asssembly output syntax
@@ -129,6 +142,7 @@ typedef enum cs_opt_type {
CS_OPT_MEM, // User-defined dynamic memory related functions
CS_OPT_SKIPDATA, // Skip data when disassembling. Then engine is in SKIPDATA mode.
CS_OPT_SKIPDATA_SETUP, // Setup user-defined function for SKIPDATA option
CS_OPT_MNEMONIC, // Customize instruction mnemonic
} cs_opt_type;
// Runtime option value (associated with option type above)
@@ -270,7 +284,7 @@ typedef struct cs_insn {
// Ascii text of instruction mnemonic
// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
char mnemonic[32];
char mnemonic[MNEMONIC_SIZE];
// Ascii text of instruction operands
// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF

View File

@@ -64,7 +64,7 @@ endif
.PHONY: all clean
SOURCES = test.c test_detail.c test_skipdata.c test_iter.c
SOURCES = test.c test_detail.c test_skipdata.c test_iter.c test_customized_mnem.c
ifneq (,$(findstring arm,$(CAPSTONE_ARCHS)))
SOURCES += test_arm.c
endif

View File

@@ -0,0 +1,86 @@
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
// This sample code demonstrates the option CS_OPT_MNEMONIC
// to customize instruction mnemonic.
#include <stdio.h>
#include <stdlib.h>
#include "../myinttypes.h"
#include <capstone/capstone.h>
#define X86_CODE32 "\x75\x01"
// Print out the input code in hexadecimal format
static void print_string_hex(unsigned char *str, size_t len)
{
unsigned char *c;
for (c = str; c < str + len; c++) {
printf("%02x ", *c & 0xff);
}
printf("\t");
}
// Print one instruction
static void print_insn(csh handle)
{
cs_insn *insn;
size_t count;
count = cs_disasm(handle, (const uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1, 0x1000, 1, &insn);
if (count) {
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");
}
static void test()
{
csh handle;
cs_err err;
// Customize mnemonic JNE to "jnz"
cs_opt_mnem my_mnem = { X86_INS_JNE, "jnz" };
// Set .mnemonic to NULL to reset to default mnemonic
cs_opt_mnem default_mnem = { X86_INS_JNE, NULL };
err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
if (err) {
printf("Failed on cs_open() with error returned: %u\n", err);
return;
}
// 1. Print out the instruction in default setup.
printf("Disassemble X86 code with default instruction mnemonic\n");
print_string_hex((unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1);
print_insn(handle);
// Customized mnemonic JNE to JNZ using CS_OPT_MNEMONIC option
printf("\nNow customize engine to change mnemonic from 'JNE' to 'JNZ'\n");
cs_option(handle, CS_OPT_MNEMONIC, (size_t)&my_mnem);
// 2. Now print out the instruction in newly customized setup.
print_string_hex((unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1);
print_insn(handle);
// Reset engine to use the default mnemonic of JNE
printf("\nReset engine to use the default mnemonic\n");
cs_option(handle, CS_OPT_MNEMONIC, (size_t)&default_mnem);
// 3. Now print out the instruction in default setup.
print_string_hex((unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1);
print_insn(handle);
// Done
cs_close(&handle);
}
int main()
{
test();
return 0;
}