cache insns for fast lookup in mapping.c. based on the idea of Dang Hoang Vu

_v3_old
Nguyen Anh Quynh 11 years ago
parent e29eaf9cbb
commit b265406960
  1. 16
      arch/AArch64/mapping.c
  2. 3
      arch/AArch64/mapping.h
  3. 8
      arch/AArch64/module.c
  4. 21
      arch/ARM/mapping.c
  5. 3
      arch/ARM/mapping.h
  6. 6
      arch/ARM/module.c
  7. 16
      arch/Mips/mapping.c
  8. 3
      arch/Mips/mapping.h
  9. 6
      arch/Mips/module.c
  10. 5
      arch/PowerPC/module.c
  11. 15
      arch/X86/mapping.c
  12. 3
      arch/X86/mapping.h
  13. 6
      arch/X86/module.c
  14. 4
      cs.c
  15. 3
      cs_priv.h
  16. 4
      include/capstone.h
  17. 44
      utils.c
  18. 5
      utils.h

@ -254,6 +254,8 @@ const char *AArch64_reg_name(csh handle, unsigned int reg)
}
static insn_map insns[] = {
{ 0, 0, { 0 }, { 0 }, { 0 }, 0, 0 }, // dummy item
{ AArch64_ABS16b, ARM64_INS_ABS, { 0 }, { 0 }, { ARM64_GRP_NEON, 0 }, 0, 0 },
{ AArch64_ABS2d, ARM64_INS_ABS, { 0 }, { 0 }, { ARM64_GRP_NEON, 0 }, 0, 0 },
{ AArch64_ABS2s, ARM64_INS_ABS, { 0 }, { 0 }, { ARM64_GRP_NEON, 0 }, 0, 0 },
@ -2990,10 +2992,13 @@ static insn_map alias_insns[] = {
// { AArch64_SUBSxxx_lsl, ARM64_INS_NEGS, { 0 }, { ARM64_REG_NZCV, 0 }, { 0 } },
};
static unsigned short *insn_cache = NULL;
// given internal insn id, return public instruction info
void AArch64_get_insn_id(cs_insn *insn, unsigned int id, int detail)
{
int i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1) {
int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if (detail) {
@ -3523,3 +3528,10 @@ arm64_reg AArch64_map_insn(const char *name)
return (i != -1)? i : ARM64_REG_INVALID;
}
void AArch64_free_cache(void)
{
if (insn_cache)
free(insn_cache);
insn_cache = NULL;
}

@ -21,4 +21,7 @@ const char *AArch64_insn_name(csh handle, unsigned int id);
// map instruction name to public instruction ID
arm64_reg AArch64_map_insn(const char *name);
// free insn cache
void AArch64_free_cache(void);
#endif

@ -30,10 +30,16 @@ static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
static void destroy(cs_struct *handle)
{
AArch64_free_cache();
}
static void __attribute__ ((constructor)) __init_arm64__()
{
arch_init[CS_ARCH_ARM64] = init;
arch_option[CS_ARCH_ARM] = option;
arch_option[CS_ARCH_ARM64] = option;
arch_destroy[CS_ARCH_ARM64] = destroy;
// support this arch
all_arch |= (1 << CS_ARCH_ARM64);

@ -135,6 +135,8 @@ const char *ARM_reg_name(csh handle, unsigned int reg)
}
static insn_map insns[] = {
{ 0, 0, { 0 }, { 0 }, { 0 }, 0, 0 }, // dummy item
{ ARM_ADCri, ARM_INS_ADC, { ARM_REG_CPSR, 0 }, { ARM_REG_CPSR, 0 }, { ARM_GRP_ARM, 0 }, 0, 0 },
{ ARM_ADCrr, ARM_INS_ADC, { ARM_REG_CPSR, 0 }, { ARM_REG_CPSR, 0 }, { ARM_GRP_ARM, 0 }, 0, 0 },
{ ARM_ADCrsi, ARM_INS_ADC, { ARM_REG_CPSR, 0 }, { ARM_REG_CPSR, 0 }, { ARM_GRP_ARM, 0 }, 0, 0 },
@ -2298,10 +2300,13 @@ static insn_map insns[] = {
{ ARM_tUXTH, ARM_INS_UXTH, { 0 }, { 0 }, { ARM_GRP_THUMB, ARM_GRP_THUMB1ONLY, ARM_GRP_V6, 0 }, 0, 0 },
};
static unsigned short *insn_cache = NULL;
void ARM_get_insn_id(cs_insn *insn, unsigned int id, int detail)
{
int i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1) {
int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if (detail) {
@ -2788,11 +2793,19 @@ arm_reg ARM_map_insn(const char *name)
bool ARM_rel_branch(unsigned int id)
{
int i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1)
int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
if (i != 0)
return (insns[i].branch && !insns[i].indirect_branch);
else {
printf("ALERT: rel_branch() got incorrect id!\n");
return false;
}
}
void ARM_free_cache(void)
{
if (insn_cache)
free(insn_cache);
insn_cache = NULL;
}

@ -25,4 +25,7 @@ arm_reg ARM_map_insn(const char *name);
// check if this insn is relative branch
bool ARM_rel_branch(unsigned int insn_id);
// free insn cache
void ARM_free_cache(void);
#endif

@ -43,10 +43,16 @@ static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
static void destroy(cs_struct *handle)
{
ARM_free_cache();
}
static void __attribute__ ((constructor)) __init_arm__()
{
arch_init[CS_ARCH_ARM] = init;
arch_option[CS_ARCH_ARM] = option;
arch_destroy[CS_ARCH_ARM] = destroy;
// support this arch
all_arch |= (1 << CS_ARCH_ARM);

@ -182,6 +182,8 @@ const char *Mips_reg_name(csh handle, unsigned int reg)
}
static insn_map insns[] = {
{ 0, 0, { 0 }, { 0 }, { 0 }, 0, 0 }, // dummy item
{ Mips_ABSQ_S_PH, MIPS_INS_ABSQ_S, { 0 }, { MIPS_REG_DSPOUTFLAG20, 0 }, { MIPS_GRP_DSP, 0 }, 0, 0 },
{ Mips_ABSQ_S_QB, MIPS_INS_ABSQ_S, { 0 }, { MIPS_REG_DSPOUTFLAG20, 0 }, { MIPS_GRP_DSPR2, 0 }, 0, 0 },
{ Mips_ABSQ_S_W, MIPS_INS_ABSQ_S, { 0 }, { MIPS_REG_DSPOUTFLAG20, 0 }, { MIPS_GRP_DSP, 0 }, 0, 0 },
@ -1386,6 +1388,8 @@ static insn_map alias_insns[] = {
{ Mips_SUBu, MIPS_INS_NEGU, { 0 }, { 0 }, { MIPS_GRP_STDENC, 0 }, 0, 0 },
};
static unsigned short *insn_cache = NULL;
// given internal insn id, return public instruction info
void Mips_get_insn_id(cs_insn *insn, unsigned int id, int detail)
{
@ -1417,8 +1421,8 @@ void Mips_get_insn_id(cs_insn *insn, unsigned int id, int detail)
}
}
i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1) {
i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if (detail) {
@ -2030,3 +2034,11 @@ mips_reg Mips_map_register(unsigned int r)
// cannot find this register
return 0;
}
void Mips_free_cache(void)
{
if (insn_cache)
free(insn_cache);
insn_cache = NULL;
}

@ -25,4 +25,7 @@ mips_reg Mips_map_insn(const char *name);
// map internal raw register to 'public' register
mips_reg Mips_map_register(unsigned int r);
// free insn cache
void Mips_free_cache(void);
#endif

@ -41,10 +41,16 @@ static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
static void destroy(cs_struct *handle)
{
Mips_free_cache();
}
static void __attribute__ ((constructor)) __init_mips__()
{
arch_init[CS_ARCH_MIPS] = init;
arch_option[CS_ARCH_MIPS] = option;
arch_destroy[CS_ARCH_MIPS] = destroy;
// support this arch
all_arch |= (1 << CS_ARCH_MIPS);

@ -33,10 +33,15 @@ static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
static void destroy(cs_struct *handle)
{
}
static void __attribute__ ((constructor)) __init_mips__()
{
arch_init[CS_ARCH_PPC] = init;
arch_option[CS_ARCH_PPC] = option;
arch_destroy[CS_ARCH_PPC] = destroy;
// support this arch
all_arch |= (1 << CS_ARCH_PPC);

@ -1605,6 +1605,8 @@ x86_reg X86_map_insn(const char *name)
#include "X86GenInstrInfo.inc"
static insn_map insns[] = {
{ 0, 0, { 0 }, { 0 }, { 0 }, 0, 0 }, // dummy item
{ X86_AAA, X86_INS_AAA, { 0 }, { 0 }, { X86_GRP_MODE32, 0 }, 0, 0 },
{ X86_AAD8i8, X86_INS_AAD, { 0 }, { 0 }, { X86_GRP_MODE32, 0 }, 0, 0 },
{ X86_AAM8i8, X86_INS_AAM, { 0 }, { 0 }, { X86_GRP_MODE32, 0 }, 0, 0 },
@ -6604,11 +6606,13 @@ void X86_post_printer(csh handle, cs_insn *insn, char *insn_asm)
}
}
static unsigned short *insn_cache = NULL;
// given internal insn id, return public instruction info
void X86_get_insn_id(cs_insn *insn, unsigned int id, int detail)
{
int i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1) {
int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if (detail) {
@ -6636,3 +6640,10 @@ unsigned int X86_get_insn_id2(unsigned int id)
return insn_reverse_id(insns, ARR_SIZE(insns), id);
}
void X86_free_cache(void)
{
if (insn_cache)
free(insn_cache);
insn_cache = NULL;
}

@ -37,4 +37,7 @@ unsigned int X86_get_insn_id2(unsigned int insn_id);
// post printer for X86.
void X86_post_printer(csh handle, cs_insn *pub_insn, char *insn_asm);
// free insn cache
void X86_free_cache(void);
#endif

@ -44,10 +44,16 @@ static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
static void destroy(cs_struct *handle)
{
X86_free_cache();
}
static void __attribute__ ((constructor)) __init_x86__()
{
arch_init[CS_ARCH_X86] = init;
arch_option[CS_ARCH_X86] = option;
arch_destroy[CS_ARCH_X86] = destroy;
// support this arch
all_arch |= (1 << CS_ARCH_X86);

@ -15,6 +15,7 @@
cs_err (*arch_init[MAX_ARCH])(cs_struct *) = { NULL };
cs_err (*arch_option[MAX_ARCH]) (cs_struct*, cs_opt_type, size_t value);
void (*arch_destroy[MAX_ARCH]) (cs_struct*);
unsigned int all_arch = 0;
@ -101,6 +102,9 @@ cs_err cs_close(csh handle)
memset(ud, 0, sizeof(*ud));
free(ud);
if (arch_destroy[ud->arch])
arch_destroy[ud->arch](ud);
return CS_ERR_OK;
}

@ -54,6 +54,9 @@ extern cs_err (*arch_init[MAX_ARCH]) (cs_struct *);
// support cs_option() for all archs
extern cs_err (*arch_option[MAX_ARCH]) (cs_struct*, cs_opt_type, size_t value);
// deinitialized functions: to be called when cs_close() is called
extern void (*arch_destroy[MAX_ARCH]) (cs_struct*);
extern unsigned int all_arch;
#endif

@ -190,6 +190,10 @@ cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle);
/*
Close CS handle: MUST do to release the handle when it is not used anymore.
NOTE: this must be only called when there is no longer usage of Capstone,
not even access to cs_insn array. The reason is the this API releases some
cached memory, thus access to any Capstone API after cs_close() might crash
your application.
@handle: handle returned by cs_open()

@ -1,6 +1,7 @@
/* Capstone Disassembler Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */
#include <stdlib.h>
#include <string.h>
#include "utils.h"
@ -20,26 +21,32 @@ int str_in_list(char **list, char *s)
return -1;
}
// binary searching
int insn_find(insn_map *m, unsigned int max, unsigned int id)
// create a cache for fast id lookup
static unsigned short *make_id2insn(insn_map *insns, unsigned int size)
{
unsigned int i, begin, end;
begin = 0;
end = max;
while(begin <= end) {
i = (begin + end) / 2;
if (id == m[i].id)
return i;
else if (id < m[i].id)
end = i - 1;
else
begin = i + 1;
}
// NOTE: assume that the max id is always put at the end of insns array
unsigned short max_id = insns[size - 1].id;
unsigned int i;
// found nothing
return -1;
unsigned short *cache = (unsigned short *)calloc(sizeof(*cache), max_id);
for (i = 1; i < size; i++)
cache[insns[i].id] = i;
return cache;
}
// look for @id in @insns, given its size in @max. first time call will update @cache.
// return 0 if not found
unsigned short insn_find(insn_map *insns, unsigned int max, unsigned int id, unsigned short **cache)
{
if (id > insns[max - 1].id)
return 0;
if (*cache == NULL)
*cache = make_id2insn(insns, max);
return (*cache)[id];
}
int name2id(name_map* map, int max, const char *name)
@ -79,3 +86,4 @@ unsigned int count_positive(unsigned char *list)
return c;
}

@ -29,8 +29,9 @@ typedef struct insn_map {
// or -1 if given string is not in the list
int str_in_list(char **list, char *s);
// binary searching in @m, given its size in @max, and @id
int insn_find(insn_map *m, unsigned int max, unsigned int id);
// look for @id in @m, given its size in @max. first time call will update @cache.
// return 0 if not found
unsigned short insn_find(insn_map *m, unsigned int max, unsigned int id, unsigned short **cache);
// map id to string
typedef struct name_map {

Loading…
Cancel
Save