mirror of
https://gitlab.com/qemu-project/capstone.git
synced 2025-11-11 08:16:15 +08:00
new option CS_OPT_MNEMONIC to customize instruction mnemonic
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -58,6 +58,7 @@ tests/test_sparc
|
||||
tests/test_systemz
|
||||
tests/test_xcore
|
||||
tests/*.static
|
||||
tests/test_customized_mnem
|
||||
|
||||
# vim tmp file
|
||||
*.swp
|
||||
|
||||
@@ -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
84
cs.c
@@ -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);
|
||||
|
||||
14
cs_priv.h
14
cs_priv.h
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
86
tests/test_customized_mnem.c
Normal file
86
tests/test_customized_mnem.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user