Fix unchecked allocations (#2844)

* Fix trivial unchecked allocations

* Move instruction lookup caching allocation into the core

* Apply formatting nitpicks

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>

* Assert to avoid an integer overflow in lookup_insn_map()

* Remove unused member from cs_struct

* Document what happens when lookup_insn_map() fails

---------

Co-authored-by: Samuel Arnold <samuel.arnold@crowdstrike.com>
Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>
This commit is contained in:
Grond66 2026-02-14 05:55:33 -08:00 committed by GitHub
parent 6705cb8120
commit a7399233eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 260 additions and 145 deletions

View file

@ -7,34 +7,53 @@
#include "cs_priv.h"
#include "utils.h"
// create a cache for fast id lookup
static unsigned short *make_id2insn(const insn_map *insns, unsigned int size)
// Create a cache to map LLVM instruction IDs to capstone instruction IDs, if
// the architecture needs this.
cs_err populate_insn_map_cache(cs_struct *handle)
{
// 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;
unsigned short *cache =
(unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache));
// If this architecture doesn't use instruction mapping, do nothing
if (!handle->insn_map || handle->insn_map_size <= 0)
return CS_ERR_OK;
for (i = 1; i < size; i++)
cache[insns[i].id] = i;
// Since the instruction map is assumed to be stored in ascending
// order, we can get the maximum LLVM instruction id just by looking at
// the last element.
unsigned int cache_elements =
handle->insn_map[handle->insn_map_size - 1].id + 1;
return cache;
// This should not be initialized yet.
CS_ASSERT(!handle->insn_cache);
unsigned short *cache = cs_mem_calloc(cache_elements, sizeof(*cache));
if (!cache) {
handle->errnum = CS_ERR_MEM;
return CS_ERR_MEM;
}
handle->insn_cache = cache;
for (i = 1; i < handle->insn_map_size; ++i)
handle->insn_cache[handle->insn_map[i].id] = i;
return CS_ERR_OK;
}
// 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(const insn_map *insns, unsigned int max,
unsigned int id, unsigned short **cache)
const insn_map *lookup_insn_map(cs_struct *handle, unsigned short id)
{
if (id > insns[max - 1].id)
return 0;
// If this is getting called, we need the cache to already be populated
// (this should be done when populate_insn_map_cache() gets called).
CS_ASSERT(handle->insn_cache);
CS_ASSERT(handle->insn_map_size);
if (*cache == NULL)
*cache = make_id2insn(insns, max);
unsigned short highest_id =
handle->insn_map[handle->insn_map_size - 1].id;
if (id > highest_id)
return NULL;
return (*cache)[id];
unsigned short i = handle->insn_cache[id];
return &handle->insn_map[i];
}
// Gives the id for the given @name if it is saved in @map.

View file

@ -15,35 +15,16 @@
#include <assert.h>
#include <string.h>
// map instruction to its characteristics
typedef struct insn_map {
unsigned short id; // The LLVM instruction id
unsigned short mapid; // The Capstone instruction id
#ifndef CAPSTONE_DIET
uint16_t regs_use[MAX_IMPL_R_REGS]; ///< list of implicit registers used by
///< this instruction
uint16_t regs_mod[MAX_IMPL_W_REGS]; ///< list of implicit registers modified
///< by this instruction
unsigned char groups
[MAX_NUM_GROUPS]; ///< list of group this instruction belong to
bool branch; // branch instruction?
bool indirect_branch; // indirect branch instruction?
union {
ppc_suppl_info ppc;
loongarch_suppl_info loongarch;
aarch64_suppl_info aarch64;
systemz_suppl_info systemz;
arm_suppl_info arm;
xtensa_suppl_info xtensa;
sparc_suppl_info sparc;
} suppl_info; // Supplementary information for each instruction.
#endif
} insn_map;
// Create a cache to map LLVM instruction IDs to capstone instruction IDs, if
// the architecture needs this.
cs_err populate_insn_map_cache(cs_struct *handle);
// 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(const insn_map *m, unsigned int max, unsigned int id,
unsigned short **cache);
// Lookup the insn_map instance for an LLVM instruction ID. This method assumes
// that this architecture uses the instruction mapping functionality available
// from populate_insn_map_cache().
// Returns NULL in case id is larger than the maximum mapped LLVM instruction
// ID.
const insn_map *lookup_insn_map(cs_struct *handle, unsigned short id);
unsigned int find_cs_id(unsigned MC_Opcode, const insn_map *imap,
unsigned imap_size);

View file

@ -13,6 +13,8 @@ cs_err AArch64_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
AArch64_init_mri(mri);
ud->printer = AArch64_printer;

View file

@ -14,6 +14,8 @@ cs_err ARC_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
ARC_init_mri(mri);
@ -49,4 +51,4 @@ cs_err ARC_option(cs_struct *handle, cs_opt_type type, size_t value)
return CS_ERR_OK;
}
#endif
#endif

View file

@ -14,6 +14,8 @@ cs_err ARM_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
ARM_init_mri(mri);

View file

@ -23,6 +23,9 @@ static const insn_map insns[] = {
#include "AlphaGenCSMappingInsn.inc"
};
const insn_map *Alpha_insns = insns;
const unsigned int Alpha_insn_count = ARR_SIZE(insns);
static const map_insn_ops insn_operands[] = {
#include "AlphaGenCSMappingInsnOp.inc"
};
@ -81,30 +84,28 @@ void Alpha_set_detail_op_reg(MCInst *MI, unsigned OpNum, alpha_op_type Reg)
// given internal insn id, return public instruction info
void Alpha_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
{
unsigned short i;
insn_map const *insn_map = NULL;
i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
if (i == 0) {
if (!(insn_map = lookup_insn_map(h, id)))
return;
}
insn->id = insns[i].mapid;
insn->id = insn_map->mapid;
if (insn->detail) {
#ifndef CAPSTONE_DIET
memcpy(insn->detail->regs_read, insns[i].regs_use,
sizeof(insns[i].regs_use));
memcpy(insn->detail->regs_read, insn_map->regs_use,
sizeof(insn_map->regs_use));
insn->detail->regs_read_count =
(uint8_t)count_positive(insns[i].regs_use);
(uint8_t)count_positive(insn_map->regs_use);
memcpy(insn->detail->regs_write, insns[i].regs_mod,
sizeof(insns[i].regs_mod));
memcpy(insn->detail->regs_write, insn_map->regs_mod,
sizeof(insn_map->regs_mod));
insn->detail->regs_write_count =
(uint8_t)count_positive(insns[i].regs_mod);
(uint8_t)count_positive(insn_map->regs_mod);
memcpy(insn->detail->groups, insns[i].groups,
sizeof(insns[i].groups));
memcpy(insn->detail->groups, insn_map->groups,
sizeof(insn_map->groups));
insn->detail->groups_count =
(uint8_t)count_positive8(insns[i].groups);
(uint8_t)count_positive8(insn_map->groups);
#endif
}
}

View file

@ -11,6 +11,9 @@
// unsigned int Alpha_map_insn_id(cs_struct *h, unsigned int id);
extern const insn_map *Alpha_insns;
extern const unsigned int Alpha_insn_count;
// given internal insn id, return public instruction info
void Alpha_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);

View file

@ -14,6 +14,8 @@ cs_err ALPHA_global_init(cs_struct *ud)
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
Alpha_init(mri);
ud->printer = Alpha_printInst;
@ -29,6 +31,8 @@ cs_err ALPHA_global_init(cs_struct *ud)
#ifndef CAPSTONE_DIET
ud->reg_access = Alpha_reg_access;
#endif
ud->insn_map = Alpha_insns;
ud->insn_map_size = Alpha_insn_count;
return CS_ERR_OK;
}

View file

@ -15,6 +15,8 @@ cs_err LoongArch_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
LoongArch_init_mri(mri);

View file

@ -14,6 +14,9 @@ cs_err MOS65XX_global_init(cs_struct *ud)
mos65xx_info *info;
info = cs_mem_malloc(sizeof(*info));
if (!info)
return CS_ERR_MEM;
info->hex_prefix = NULL;
info->cpu_type = MOS65XX_CPU_TYPE_6502;
info->long_m = 0;

View file

@ -14,6 +14,8 @@ cs_err Mips_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
Mips_init_mri(mri);

View file

@ -12,6 +12,8 @@ cs_err PPC_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = (MCRegisterInfo *)cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
PPC_init_mri(mri);
ud->printer = PPC_printer;

View file

@ -36,6 +36,9 @@ static const insn_map insns[] = {
#include "RISCVGenCSMappingInsn.inc"
};
const insn_map *RISCV_insns = insns;
const unsigned int RISCV_insn_count = ARR_SIZE(insns);
#ifndef CAPSTONE_DIET
static const map_insn_ops insn_operands[] = {
@ -310,30 +313,29 @@ void RISCV_add_missing_write_access(MCInst *MI)
// given internal insn id, return public instruction info
void RISCV_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
{
unsigned int i;
insn_map const *insn_map = NULL;
i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if ((insn_map = lookup_insn_map(h, id))) {
insn->id = insn_map->mapid;
if (h->detail_opt) {
#ifndef CAPSTONE_DIET
memcpy(insn->detail->regs_read, insns[i].regs_use,
sizeof(insns[i].regs_use));
memcpy(insn->detail->regs_read, insn_map->regs_use,
sizeof(insn_map->regs_use));
insn->detail->regs_read_count =
(uint8_t)count_positive(insns[i].regs_use);
(uint8_t)count_positive(insn_map->regs_use);
memcpy(insn->detail->regs_write, insns[i].regs_mod,
sizeof(insns[i].regs_mod));
memcpy(insn->detail->regs_write, insn_map->regs_mod,
sizeof(insn_map->regs_mod));
insn->detail->regs_write_count =
(uint8_t)count_positive(insns[i].regs_mod);
(uint8_t)count_positive(insn_map->regs_mod);
memcpy(insn->detail->groups, insns[i].groups,
sizeof(insns[i].groups));
memcpy(insn->detail->groups, insn_map->groups,
sizeof(insn_map->groups));
insn->detail->groups_count =
(uint8_t)count_positive8(insns[i].groups);
(uint8_t)count_positive8(insn_map->groups);
if (insns[i].branch || insns[i].indirect_branch) {
if (insn_map->branch || insn_map->indirect_branch) {
// this insn also belongs to JUMP group. add JUMP group
insn->detail
->groups[insn->detail->groups_count] =

View file

@ -9,6 +9,9 @@ typedef enum {
#include "RISCVGenCSOpGroup.inc"
} riscv_op_group;
extern const insn_map *RISCV_insns;
extern const unsigned int RISCV_insn_count;
// given internal insn id, return public instruction info
void RISCV_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);

View file

@ -15,6 +15,8 @@ cs_err RISCV_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
RISCV_init(mri);
ud->printer = RISCV_LLVM_printInstruction;
@ -27,6 +29,8 @@ cs_err RISCV_global_init(cs_struct *ud)
ud->insn_id = RISCV_get_insn_id;
ud->insn_name = RISCV_insn_name;
ud->group_name = RISCV_group_name;
ud->insn_map = RISCV_insns;
ud->insn_map_size = RISCV_insn_count;
return CS_ERR_OK;
}

View file

@ -12,6 +12,8 @@ cs_err Sparc_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
Sparc_init_mri(mri);
ud->printer = Sparc_printer;

View file

@ -12,6 +12,8 @@ cs_err SystemZ_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
SystemZ_init_mri(mri);
ud->printer = SystemZ_printer;

View file

@ -2682,32 +2682,34 @@ static const insn_map insns[] = {
},
};
const insn_map *TMS320C64x_insns = insns;
const unsigned int TMS320C64x_insn_count = ARR_SIZE(insns);
void TMS320C64x_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
{
unsigned short i;
insn_map const *insn_map = NULL;
i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if ((insn_map = lookup_insn_map(h, id))) {
insn->id = insn_map->mapid;
if (h->detail_opt) {
#ifndef CAPSTONE_DIET
memcpy(insn->detail->regs_read, insns[i].regs_use,
sizeof(insns[i].regs_use));
memcpy(insn->detail->regs_read, insn_map->regs_use,
sizeof(insn_map->regs_use));
insn->detail->regs_read_count =
(uint8_t)count_positive(insns[i].regs_use);
(uint8_t)count_positive(insn_map->regs_use);
memcpy(insn->detail->regs_write, insns[i].regs_mod,
sizeof(insns[i].regs_mod));
memcpy(insn->detail->regs_write, insn_map->regs_mod,
sizeof(insn_map->regs_mod));
insn->detail->regs_write_count =
(uint8_t)count_positive(insns[i].regs_mod);
(uint8_t)count_positive(insn_map->regs_mod);
memcpy(insn->detail->groups, insns[i].groups,
sizeof(insns[i].groups));
memcpy(insn->detail->groups, insn_map->groups,
sizeof(insn_map->groups));
insn->detail->groups_count =
(uint8_t)count_positive8(insns[i].groups);
(uint8_t)count_positive8(insn_map->groups);
if (insns[i].branch || insns[i].indirect_branch) {
if (insn_map->branch || insn_map->indirect_branch) {
insn->detail
->groups[insn->detail->groups_count] =
TMS320C64X_GRP_JUMP;

View file

@ -6,6 +6,9 @@
#include "capstone/capstone.h"
extern const insn_map *TMS320C64x_insns;
extern const unsigned int TMS320C64x_insn_count;
// return name of register in friendly string
const char *TMS320C64x_reg_name(csh handle, unsigned int reg);

View file

@ -15,6 +15,8 @@ cs_err TMS320C64x_global_init(cs_struct *ud)
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
TMS320C64x_init(mri);
ud->printer = TMS320C64x_printInst;
@ -27,6 +29,8 @@ cs_err TMS320C64x_global_init(cs_struct *ud)
ud->insn_id = TMS320C64x_get_insn_id;
ud->insn_name = TMS320C64x_insn_name;
ud->group_name = TMS320C64x_group_name;
ud->insn_map = TMS320C64x_insns;
ud->insn_map_size = TMS320C64x_insn_count;
return CS_ERR_OK;
}

View file

@ -12,6 +12,9 @@ cs_err TRICORE_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_calloc(sizeof(*mri), 1);
if (!mri)
return CS_ERR_MEM;
TriCore_init_mri(mri);
ud->printer = TriCore_printInst;
ud->printer_info = mri;

View file

@ -14,6 +14,8 @@ cs_err X86_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
X86_init(mri);

View file

@ -88,33 +88,35 @@ static const insn_map insns[] = {
#include "XCoreMappingInsn.inc"
};
const insn_map *XCore_insns = insns;
const unsigned int XCore_insn_count = ARR_SIZE(insns);
// given internal insn id, return public instruction info
void XCore_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
{
unsigned short i;
insn_map const *insn_map = NULL;
i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
if (i != 0) {
insn->id = insns[i].mapid;
if ((insn_map = lookup_insn_map(h, id))) {
insn->id = insn_map->mapid;
if (h->detail_opt) {
#ifndef CAPSTONE_DIET
memcpy(insn->detail->regs_read, insns[i].regs_use,
sizeof(insns[i].regs_use));
memcpy(insn->detail->regs_read, insn_map->regs_use,
sizeof(insn_map->regs_use));
insn->detail->regs_read_count =
(uint8_t)count_positive(insns[i].regs_use);
(uint8_t)count_positive(insn_map->regs_use);
memcpy(insn->detail->regs_write, insns[i].regs_mod,
sizeof(insns[i].regs_mod));
memcpy(insn->detail->regs_write, insn_map->regs_mod,
sizeof(insn_map->regs_mod));
insn->detail->regs_write_count =
(uint8_t)count_positive(insns[i].regs_mod);
(uint8_t)count_positive(insn_map->regs_mod);
memcpy(insn->detail->groups, insns[i].groups,
sizeof(insns[i].groups));
memcpy(insn->detail->groups, insn_map->groups,
sizeof(insn_map->groups));
insn->detail->groups_count =
(uint8_t)count_positive8(insns[i].groups);
(uint8_t)count_positive8(insn_map->groups);
if (insns[i].branch || insns[i].indirect_branch) {
if (insn_map->branch || insn_map->indirect_branch) {
// this insn also belongs to JUMP group. add JUMP group
insn->detail
->groups[insn->detail->groups_count] =

View file

@ -6,6 +6,9 @@
#include "capstone/capstone.h"
extern const insn_map *XCore_insns;
extern const unsigned int XCore_insn_count;
// return name of register in friendly string
const char *XCore_reg_name(csh handle, unsigned int reg);

View file

@ -14,6 +14,8 @@ cs_err XCore_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_malloc(sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
XCore_init(mri);
ud->printer = XCore_printInst;
@ -26,6 +28,8 @@ cs_err XCore_global_init(cs_struct *ud)
ud->insn_id = XCore_get_insn_id;
ud->insn_name = XCore_insn_name;
ud->group_name = XCore_group_name;
ud->insn_map = XCore_insns;
ud->insn_map_size = XCore_insn_count;
return CS_ERR_OK;
}

View file

@ -11,6 +11,8 @@ cs_err Xtensa_global_init(cs_struct *ud)
{
MCRegisterInfo *mri;
mri = cs_mem_calloc(1, sizeof(*mri));
if (!mri)
return CS_ERR_MEM;
Xtensa_init_mri(mri);
ud->printer = Xtensa_printer;
@ -44,4 +46,4 @@ cs_err Xtensa_option(cs_struct *handle, cs_opt_type type, size_t value)
}
return CS_ERR_OK;
}
}

105
cs.c
View file

@ -16,6 +16,7 @@
#include "utils.h"
#include "MCRegisterInfo.h"
#include "Mapping.h"
#if defined(_KERNEL_MODE)
#include "windows\winkernel_mm.h"
@ -779,52 +780,59 @@ const char *CAPSTONE_API cs_strerror(cs_err code)
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle)
{
cs_err err;
cs_err err = CS_ERR_ARCH;
struct cs_struct *ud = NULL;
if (!cs_mem_malloc || !cs_mem_calloc || !cs_mem_realloc ||
!cs_mem_free || !cs_vsnprintf)
!cs_mem_free || !cs_vsnprintf) {
// Error: before cs_open(), dynamic memory management must be initialized
// with cs_option(CS_OPT_MEM)
return CS_ERR_MEMSETUP;
if (arch < CS_ARCH_MAX && arch_configs[arch].arch_init) {
// verify if requested mode is valid
if (mode & arch_configs[arch].arch_disallowed_mode_mask) {
*handle = 0;
return CS_ERR_MODE;
}
ud = cs_mem_calloc(1, sizeof(*ud));
if (!ud) {
// memory insufficient
return CS_ERR_MEM;
}
ud->errnum = CS_ERR_OK;
ud->arch = arch;
ud->mode = mode;
// by default, do not break instruction into details
ud->detail_opt = CS_OPT_OFF;
ud->PrintBranchImmAsAddress = true;
// default skipdata setup
ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
err = arch_configs[ud->arch].arch_init(ud);
if (err) {
cs_mem_free(ud);
*handle = 0;
return err;
}
*handle = (uintptr_t)ud;
return CS_ERR_OK;
} else {
cs_mem_free(ud);
*handle = 0;
return CS_ERR_ARCH;
err = CS_ERR_MEMSETUP;
goto fail;
}
if (arch >= CS_ARCH_MAX || !arch_configs[arch].arch_init) {
err = CS_ERR_ARCH;
goto fail;
}
// verify if requested mode is valid
if (mode & arch_configs[arch].arch_disallowed_mode_mask) {
err = CS_ERR_MODE;
goto fail;
}
ud = cs_mem_calloc(1, sizeof(*ud));
if (!ud) {
err = CS_ERR_MEM;
goto fail;
}
ud->errnum = CS_ERR_OK;
ud->arch = arch;
ud->mode = mode;
// by default, do not break instruction into details
ud->detail_opt = CS_OPT_OFF;
ud->PrintBranchImmAsAddress = true;
// default skipdata setup
ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
if ((err = arch_configs[ud->arch].arch_init(ud)))
goto fail;
if ((err = populate_insn_map_cache(ud)))
goto fail;
*handle = (uintptr_t)ud;
return CS_ERR_OK;
fail:
if (ud) {
cs_mem_free(ud);
}
*handle = 0;
return err;
}
CAPSTONE_EXPORT
@ -1113,6 +1121,10 @@ cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, uintptr_t value)
// 2. add this instruction if we have not had it yet
if (!tmp) {
tmp = cs_mem_malloc(sizeof(*tmp));
if (!tmp) {
return CS_ERR_MEM;
}
tmp->insn.id = opt->id;
(void)strncpy(
tmp->insn.mnemonic,
@ -1268,6 +1280,17 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size,
// allocate memory for @detail pointer
insn_cache->detail =
cs_mem_calloc(1, sizeof(cs_detail));
if (!insn_cache->detail) {
insn_cache = (cs_insn *)total;
for (i = 0; i < c; i++, insn_cache++)
cs_mem_free(insn_cache->detail);
cs_mem_free(total);
*insn = NULL;
handle->errnum = CS_ERR_MEM;
return 0;
}
} else {
insn_cache->detail = NULL;
}

View file

@ -57,6 +57,31 @@ struct insn_mnem {
struct insn_mnem *next; // linked list of customized mnemonics
};
// map instruction to its characteristics
typedef struct insn_map {
unsigned short id; // The LLVM instruction id
unsigned short mapid; // The Capstone instruction id
#ifndef CAPSTONE_DIET
uint16_t regs_use[MAX_IMPL_R_REGS]; ///< list of implicit registers used by
///< this instruction
uint16_t regs_mod[MAX_IMPL_W_REGS]; ///< list of implicit registers modified
///< by this instruction
unsigned char groups
[MAX_NUM_GROUPS]; ///< list of group this instruction belong to
bool branch; // branch instruction?
bool indirect_branch; // indirect branch instruction?
union {
ppc_suppl_info ppc;
loongarch_suppl_info loongarch;
aarch64_suppl_info aarch64;
systemz_suppl_info systemz;
arm_suppl_info arm;
xtensa_suppl_info xtensa;
sparc_suppl_info sparc;
} suppl_info; // Supplementary information for each instruction.
#endif
} insn_map;
struct cs_struct {
cs_arch arch;
cs_mode mode;
@ -79,6 +104,12 @@ struct cs_struct {
bool doing_mem; // handling memory operand in InstPrinter code
bool doing_SME_Index; // handling a SME instruction that has index
unsigned short *insn_cache; // index caching for mapping.c
// A mapping of LLVM instruction IDs to capstone instruction IDs, with
// some supplementary information, sorted in ascending order by LLVM
// instruction ID.
const insn_map *insn_map;
// The number of elements in the array pointed to by .insn_map
unsigned short insn_map_size;
bool skipdata; // set this to True if we skip data when disassembling
uint8_t skipdata_size; // how many bytes to skip
cs_opt_skipdata skipdata_setup; // user-defined skipdata setup