new option CS_OPT_MNEMONIC to customize instruction mnemonic
diff --git a/cs.c b/cs.c
index 6e2d112..1d60291 100644
--- a/cs.c
+++ b/cs.c
@@ -233,6 +233,7 @@
cs_err cs_close(csh *handle)
{
struct cs_struct *ud;
+ struct insn_mnem *next, *tmp;
if (*handle == 0)
// invalid handle
@@ -243,6 +244,14 @@
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 @@
*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 @@
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 @@
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 @@
}
}
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);