diff --git a/Mapping.c b/Mapping.c index f019bdf5b..523994b2f 100644 --- a/Mapping.c +++ b/Mapping.c @@ -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. diff --git a/Mapping.h b/Mapping.h index c77af65bf..ea97ea4e7 100644 --- a/Mapping.h +++ b/Mapping.h @@ -15,35 +15,16 @@ #include #include -// 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); diff --git a/arch/AArch64/AArch64Module.c b/arch/AArch64/AArch64Module.c index f49f06312..2adf7810e 100644 --- a/arch/AArch64/AArch64Module.c +++ b/arch/AArch64/AArch64Module.c @@ -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; diff --git a/arch/ARC/ARCModule.c b/arch/ARC/ARCModule.c index f42b61348..6999e6614 100644 --- a/arch/ARC/ARCModule.c +++ b/arch/ARC/ARCModule.c @@ -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 \ No newline at end of file +#endif diff --git a/arch/ARM/ARMModule.c b/arch/ARM/ARMModule.c index ef8807476..7f124ca8b 100644 --- a/arch/ARM/ARMModule.c +++ b/arch/ARM/ARMModule.c @@ -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); diff --git a/arch/Alpha/AlphaMapping.c b/arch/Alpha/AlphaMapping.c index c3f06d2d1..62fdb164a 100644 --- a/arch/Alpha/AlphaMapping.c +++ b/arch/Alpha/AlphaMapping.c @@ -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 } } diff --git a/arch/Alpha/AlphaMapping.h b/arch/Alpha/AlphaMapping.h index 0ec7ee262..349194352 100644 --- a/arch/Alpha/AlphaMapping.h +++ b/arch/Alpha/AlphaMapping.h @@ -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); diff --git a/arch/Alpha/AlphaModule.c b/arch/Alpha/AlphaModule.c index 3bde3872d..520f204cc 100644 --- a/arch/Alpha/AlphaModule.c +++ b/arch/Alpha/AlphaModule.c @@ -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; } diff --git a/arch/LoongArch/LoongArchModule.c b/arch/LoongArch/LoongArchModule.c index 75a6c1951..fea4271a8 100644 --- a/arch/LoongArch/LoongArchModule.c +++ b/arch/LoongArch/LoongArchModule.c @@ -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); diff --git a/arch/MOS65XX/MOS65XXModule.c b/arch/MOS65XX/MOS65XXModule.c index ff93d7e94..5cdc63803 100644 --- a/arch/MOS65XX/MOS65XXModule.c +++ b/arch/MOS65XX/MOS65XXModule.c @@ -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; diff --git a/arch/Mips/MipsModule.c b/arch/Mips/MipsModule.c index 6a1a963cb..e774efa04 100644 --- a/arch/Mips/MipsModule.c +++ b/arch/Mips/MipsModule.c @@ -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); diff --git a/arch/PowerPC/PPCModule.c b/arch/PowerPC/PPCModule.c index 2cee59898..ea0d51ee6 100644 --- a/arch/PowerPC/PPCModule.c +++ b/arch/PowerPC/PPCModule.c @@ -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; diff --git a/arch/RISCV/RISCVMapping.c b/arch/RISCV/RISCVMapping.c index 37c6ce1a8..251ec0b24 100644 --- a/arch/RISCV/RISCVMapping.c +++ b/arch/RISCV/RISCVMapping.c @@ -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] = diff --git a/arch/RISCV/RISCVMapping.h b/arch/RISCV/RISCVMapping.h index 0a1600b06..f725f9b68 100644 --- a/arch/RISCV/RISCVMapping.h +++ b/arch/RISCV/RISCVMapping.h @@ -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); diff --git a/arch/RISCV/RISCVModule.c b/arch/RISCV/RISCVModule.c index c6bc50ea9..5b70ce2a3 100644 --- a/arch/RISCV/RISCVModule.c +++ b/arch/RISCV/RISCVModule.c @@ -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; } diff --git a/arch/Sparc/SparcModule.c b/arch/Sparc/SparcModule.c index 1178609af..e3684dd31 100644 --- a/arch/Sparc/SparcModule.c +++ b/arch/Sparc/SparcModule.c @@ -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; diff --git a/arch/SystemZ/SystemZModule.c b/arch/SystemZ/SystemZModule.c index a1ae2df5e..2dc87fa24 100644 --- a/arch/SystemZ/SystemZModule.c +++ b/arch/SystemZ/SystemZModule.c @@ -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; diff --git a/arch/TMS320C64x/TMS320C64xMapping.c b/arch/TMS320C64x/TMS320C64xMapping.c index d23c47433..59a0f4293 100644 --- a/arch/TMS320C64x/TMS320C64xMapping.c +++ b/arch/TMS320C64x/TMS320C64xMapping.c @@ -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; diff --git a/arch/TMS320C64x/TMS320C64xMapping.h b/arch/TMS320C64x/TMS320C64xMapping.h index 41fa09757..618007188 100644 --- a/arch/TMS320C64x/TMS320C64xMapping.h +++ b/arch/TMS320C64x/TMS320C64xMapping.h @@ -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); diff --git a/arch/TMS320C64x/TMS320C64xModule.c b/arch/TMS320C64x/TMS320C64xModule.c index bf4168eb2..7e6992993 100644 --- a/arch/TMS320C64x/TMS320C64xModule.c +++ b/arch/TMS320C64x/TMS320C64xModule.c @@ -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; } diff --git a/arch/TriCore/TriCoreModule.c b/arch/TriCore/TriCoreModule.c index fe90976c3..513461c2e 100644 --- a/arch/TriCore/TriCoreModule.c +++ b/arch/TriCore/TriCoreModule.c @@ -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; diff --git a/arch/X86/X86Module.c b/arch/X86/X86Module.c index f4f6a407f..716f9d6de 100644 --- a/arch/X86/X86Module.c +++ b/arch/X86/X86Module.c @@ -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); diff --git a/arch/XCore/XCoreMapping.c b/arch/XCore/XCoreMapping.c index 9ae629d1d..7e8cc5e48 100644 --- a/arch/XCore/XCoreMapping.c +++ b/arch/XCore/XCoreMapping.c @@ -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] = diff --git a/arch/XCore/XCoreMapping.h b/arch/XCore/XCoreMapping.h index 8dd3f0084..ff4c75dae 100644 --- a/arch/XCore/XCoreMapping.h +++ b/arch/XCore/XCoreMapping.h @@ -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); diff --git a/arch/XCore/XCoreModule.c b/arch/XCore/XCoreModule.c index 90940d48b..13a2e0cd7 100644 --- a/arch/XCore/XCoreModule.c +++ b/arch/XCore/XCoreModule.c @@ -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; } diff --git a/arch/Xtensa/XtensaModule.c b/arch/Xtensa/XtensaModule.c index e9c26c67d..c2d5d08df 100644 --- a/arch/Xtensa/XtensaModule.c +++ b/arch/Xtensa/XtensaModule.c @@ -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; -} \ No newline at end of file +} diff --git a/cs.c b/cs.c index 428d5e9fa..063e05f9e 100644 --- a/cs.c +++ b/cs.c @@ -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; } diff --git a/cs_priv.h b/cs_priv.h index a5ada1c65..26270c608 100644 --- a/cs_priv.h +++ b/cs_priv.h @@ -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