|
7 | 7 | #include "cs_priv.h" |
8 | 8 | #include "utils.h" |
9 | 9 |
|
10 | | -// create a cache for fast id lookup |
11 | | -static unsigned short *make_id2insn(const insn_map *insns, unsigned int size) |
| 10 | +// Create a cache to map LLVM instruction IDs to capstone instruction IDs, if |
| 11 | +// the architecture needs this. |
| 12 | +cs_err populate_insn_map_cache(cs_struct *handle) |
12 | 13 | { |
13 | | - // NOTE: assume that the max id is always put at the end of insns array |
14 | | - unsigned short max_id = insns[size - 1].id; |
15 | 14 | unsigned int i; |
16 | 15 |
|
17 | | - unsigned short *cache = |
18 | | - (unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache)); |
| 16 | + // If this architecture doesn't use instruction mapping, do nothing |
| 17 | + if (!handle->insn_map || handle->insn_map_size <= 0) |
| 18 | + return CS_ERR_OK; |
19 | 19 |
|
20 | | - for (i = 1; i < size; i++) |
21 | | - cache[insns[i].id] = i; |
| 20 | + // Since the instruction map is assumed to be stored in ascending |
| 21 | + // order, we can get the maximum LLVM instruction id just by looking at |
| 22 | + // the last element. |
| 23 | + unsigned int cache_elements = |
| 24 | + handle->insn_map[handle->insn_map_size - 1].id + 1; |
22 | 25 |
|
23 | | - return cache; |
| 26 | + // This should not be initialized yet. |
| 27 | + CS_ASSERT(!handle->insn_cache); |
| 28 | + |
| 29 | + unsigned short *cache = cs_mem_calloc(cache_elements, sizeof(*cache)); |
| 30 | + if (!cache) { |
| 31 | + handle->errnum = CS_ERR_MEM; |
| 32 | + return CS_ERR_MEM; |
| 33 | + } |
| 34 | + handle->insn_cache = cache; |
| 35 | + |
| 36 | + for (i = 1; i < handle->insn_map_size; ++i) |
| 37 | + handle->insn_cache[handle->insn_map[i].id] = i; |
| 38 | + |
| 39 | + return CS_ERR_OK; |
24 | 40 | } |
25 | 41 |
|
26 | | -// look for @id in @insns, given its size in @max. first time call will update |
27 | | -// @cache. return 0 if not found |
28 | | -unsigned short insn_find(const insn_map *insns, unsigned int max, |
29 | | - unsigned int id, unsigned short **cache) |
| 42 | +const insn_map *lookup_insn_map(cs_struct *handle, unsigned short id) |
30 | 43 | { |
31 | | - if (id > insns[max - 1].id) |
32 | | - return 0; |
| 44 | + // If this is getting called, we need the cache to already be populated |
| 45 | + // (this should be done when populate_insn_map_cache() gets called). |
| 46 | + CS_ASSERT(handle->insn_cache); |
| 47 | + CS_ASSERT(handle->insn_map_size); |
| 48 | + |
| 49 | + unsigned short highest_id = |
| 50 | + handle->insn_map[handle->insn_map_size - 1].id; |
| 51 | + if (id > highest_id) |
| 52 | + return NULL; |
33 | 53 |
|
34 | | - if (*cache == NULL) |
35 | | - *cache = make_id2insn(insns, max); |
| 54 | + unsigned short i = handle->insn_cache[id]; |
36 | 55 |
|
37 | | - return (*cache)[id]; |
| 56 | + return &handle->insn_map[i]; |
38 | 57 | } |
39 | 58 |
|
40 | 59 | // Gives the id for the given @name if it is saved in @map. |
|
0 commit comments