diff --git a/Makefile b/Makefile index 7033086f4..dc97192d8 100644 --- a/Makefile +++ b/Makefile @@ -409,6 +409,19 @@ dist: git archive --format=tar.gz --prefix=capstone-$(DIST_VERSION)/ $(TAG) > capstone-$(DIST_VERSION).tgz git archive --format=zip --prefix=capstone-$(DIST_VERSION)/ $(TAG) > capstone-$(DIST_VERSION).zip + +TESTS = test test_detail test_arm test_arm64 test_mips test_ppc test_sparc +TESTS += test_systemz test_x86 test_xcore +TESTS += test.static test_detail.static test_arm.static test_arm64.static +TESTS += test_mips.static test_ppc.static test_sparc.static +TESTS += test_systemz.static test_x86.static test_xcore.static +TESTS += test_skipdata test_skipdata.static +check: + @for t in $(TESTS); do \ + echo Check $$t ... ; \ + ./tests/$$t > /dev/null && echo OK || echo FAILED; \ + done + $(OBJDIR)/%.o: %.c @mkdir -p $(@D) ifeq ($(V),0) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4220f7705..f10ae505b 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,7 +1,3 @@ -Version 2.1.2 is a stable release that fixes some bugs deep in the core. -There is no update to any architectures or bindings, so older bindings -of release 2.1 can be used with this version 2.1.2 just fine. - -For this reason, after upgrading to 2.1.2, users do NOT need to upgrade -their bindings from release 2.1. - +The old bindings from version 2.x are not compatible with version 3.0, so +must be updated. For Java/Ocaml/Python bindings, see respective README files +under bindings/ directory in the source on how to reinstall them. diff --git a/TODO b/TODO index f6edd8a32..ebe94dfe3 100644 --- a/TODO +++ b/TODO @@ -18,4 +18,4 @@ Issues to be solved in next versions [Bindings] -- OCaml binding are broken due to many API changes. This should be fixed ASAP. +- OCaml binding is working, but still support the core API better. diff --git a/arch/AArch64/AArch64InstPrinter.c b/arch/AArch64/AArch64InstPrinter.c index d7def5db9..4af3aba3f 100644 --- a/arch/AArch64/AArch64InstPrinter.c +++ b/arch/AArch64/AArch64InstPrinter.c @@ -1342,9 +1342,6 @@ static void printMemExtend(MCInst *MI, unsigned OpNum, SStream *O, char SrcRegKi case 'w': MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTW; break; - case 'x': - MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTX; - break; } } else { switch(SrcRegKind) { diff --git a/arch/Mips/MipsDisassembler.c b/arch/Mips/MipsDisassembler.c index cd7c71f94..8814ee36b 100644 --- a/arch/Mips/MipsDisassembler.c +++ b/arch/Mips/MipsDisassembler.c @@ -441,8 +441,6 @@ static unsigned getReg(MCRegisterInfo *MRI, unsigned RC, unsigned RegNo) return rc->RegsBegin[RegNo]; } -#define nullptr NULL - static DecodeStatus DecodeINSVE_DF_4(MCInst *MI, uint32_t insn, uint64_t Address, MCRegisterInfo *Decoder) { @@ -451,7 +449,8 @@ static DecodeStatus DecodeINSVE_DF_4(MCInst *MI, uint32_t insn, // The register class also depends on this. uint32_t tmp = fieldFromInstruction(insn, 17, 5); unsigned NSize = 0; - DecodeFN RegDecoder = nullptr; + DecodeFN RegDecoder = NULL; + if ((tmp & 0x18) == 0x00) { // INSVE_B NSize = 4; RegDecoder = DecodeMSA128BRegisterClass; @@ -468,20 +467,27 @@ static DecodeStatus DecodeINSVE_DF_4(MCInst *MI, uint32_t insn, //assert(NSize != 0 && RegDecoder != nullptr); + if (RegDecoder == NULL) + return MCDisassembler_Fail; + // $wd tmp = fieldFromInstruction(insn, 6, 5); if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler_Fail) return MCDisassembler_Fail; + // $wd_in if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler_Fail) return MCDisassembler_Fail; + // $n tmp = fieldFromInstruction(insn, 16, NSize); MCOperand_CreateImm0(MI, tmp); + // $ws tmp = fieldFromInstruction(insn, 11, 5); if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler_Fail) return MCDisassembler_Fail; + // $n2 MCOperand_CreateImm0(MI, 0); diff --git a/arch/Mips/MipsMapping.c b/arch/Mips/MipsMapping.c index 76ababd3a..952baf993 100644 --- a/arch/Mips/MipsMapping.c +++ b/arch/Mips/MipsMapping.c @@ -186,6 +186,14 @@ static name_map reg_name_maps[] = { { MIPS_REG_HI, "hi"}, { MIPS_REG_LO, "lo"}, { MIPS_REG_PC, "pc"}, + + { MIPS_REG_P0, "p0"}, + { MIPS_REG_P1, "p1"}, + { MIPS_REG_P2, "p2"}, + + { MIPS_REG_MPL0, "mpl0"}, + { MIPS_REG_MPL1, "mpl1"}, + { MIPS_REG_MPL2, "mpl2"}, }; #endif diff --git a/arch/PowerPC/PPCInstPrinter.c b/arch/PowerPC/PPCInstPrinter.c index 7818ebb82..fcd3799aa 100644 --- a/arch/PowerPC/PPCInstPrinter.c +++ b/arch/PowerPC/PPCInstPrinter.c @@ -736,7 +736,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) #define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg))) SStream ss; const char* opCode; - int decCtr, needComma; + int decCtr = false, needComma = false; char *tmp, *AsmMnem, *AsmOps, *c; int OpIdx, PrintMethodIdx; MCRegisterInfo *MRI = (MCRegisterInfo *)info; @@ -774,7 +774,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) && (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) { SStream_concat(&ss, opCode, "dnzf"); - decCtr = 1; + decCtr = true; } if (MCInst_getNumOperands(MI) == 3 && @@ -782,7 +782,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) && (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) { SStream_concat(&ss, opCode, "dzf"); - decCtr = 1; + decCtr = true; } if (MCInst_getNumOperands(MI) == 3 && @@ -812,7 +812,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7) SStream_concat0(&ss, "+"); - decCtr = 0; + decCtr = false; } if (MCInst_getNumOperands(MI) == 3 && @@ -820,7 +820,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) && (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) { SStream_concat(&ss, opCode, "dnzt"); - decCtr = 1; + decCtr = true; } if (MCInst_getNumOperands(MI) == 3 && @@ -828,7 +828,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) && (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) { SStream_concat(&ss, opCode, "dzt"); - decCtr = 1; + decCtr = true; } if (MCInst_getNumOperands(MI) == 3 && @@ -858,7 +858,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15) SStream_concat0(&ss, "+"); - decCtr = 0; + decCtr = false; } if (MCInst_getNumOperands(MI) == 3 && @@ -871,7 +871,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25) SStream_concat0(&ss, "+"); - needComma = 0; + needComma = false; } if (MCInst_getNumOperands(MI) == 3 && @@ -884,7 +884,7 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27) SStream_concat0(&ss, "+"); - needComma = 0; + needComma = false; } if (MCOperand_isReg(MCInst_getOperand(MI, 1)) && @@ -892,8 +892,9 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) MCOperand_isImm(MCInst_getOperand(MI, 0)) && (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) { int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1))); + op_addReg(MI, PPC_REG_CR0+cr-PPC_CR0); if(decCtr) { - needComma = 1; + needComma = true; SStream_concat0(&ss, " "); if(cr > PPC_CR0) { SStream_concat(&ss, "4*cr%d+", cr-PPC_CR0); @@ -915,17 +916,15 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) } } else { if(cr > PPC_CR0) { - needComma = 1; + needComma = true; SStream_concat(&ss, " cr%d", cr-PPC_CR0); - } else { - needComma = 0; } } } if (MCOperand_isImm(MCInst_getOperand(MI, 2)) && MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) { - if(needComma) + if (needComma) SStream_concat0(&ss, ","); SStream_concat0(&ss, " $\xFF\x03\x01"); } diff --git a/arch/PowerPC/PPCMapping.c b/arch/PowerPC/PPCMapping.c index f1c9d7c24..de40fdc1f 100644 --- a/arch/PowerPC/PPCMapping.c +++ b/arch/PowerPC/PPCMapping.c @@ -8094,7 +8094,7 @@ bool PPC_alias_insn(const char *name, struct ppc_alias *alias) // not really an alias insn i = name2id(&insn_name_maps[1], ARR_SIZE(insn_name_maps) - 1, name); - if (i) { + if (i != -1) { alias->id = insn_name_maps[i].id; alias->cc = PPC_BC_INVALID; return true; diff --git a/arch/X86/X86DisassemblerDecoder.c b/arch/X86/X86DisassemblerDecoder.c index b10b23185..62d2ec56a 100644 --- a/arch/X86/X86DisassemblerDecoder.c +++ b/arch/X86/X86DisassemblerDecoder.c @@ -959,14 +959,13 @@ static bool is16BitEquivalent(unsigned orig, unsigned equiv) size_t i; uint16_t idx; - if ((idx = x86_16_bit_eq_lookup[orig]) != 0) - { - for (i = idx - 1; x86_16_bit_eq_tbl[i].first == orig && i < ARR_SIZE(x86_16_bit_eq_tbl); ++i) - { + if ((idx = x86_16_bit_eq_lookup[orig]) != 0) { + for (i = idx - 1; i < ARR_SIZE(x86_16_bit_eq_tbl) && x86_16_bit_eq_tbl[i].first == orig; i++) { if (x86_16_bit_eq_tbl[i].second == equiv) return true; } } + return false; } diff --git a/bindings/Makefile b/bindings/Makefile index e742b4f20..1ed2d2114 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -82,4 +82,9 @@ clean: cd python && $(MAKE) clean cd ocaml && $(MAKE) clean +check: + make -C ocaml check + make -C python check + make -C java check + FORCE: diff --git a/bindings/java/Makefile b/bindings/java/Makefile index 58b0cfd7c..896c30de0 100644 --- a/bindings/java/Makefile +++ b/bindings/java/Makefile @@ -59,3 +59,11 @@ ifdef BUILDDIR rm -rf $(BLDIR) rm -rf $(OBJDIR) endif + +TESTS = test arm arm64 mips ppc sparc systemz x86 xcore +check: + @for t in $(TESTS); do \ + echo Check $$t ... ; \ + ./run.sh $$t > /dev/null && echo OK || echo FAILED; \ + done + diff --git a/bindings/java/run.sh b/bindings/java/run.sh index 18b0b25ba..0f646505c 100755 --- a/bindings/java/run.sh +++ b/bindings/java/run.sh @@ -12,6 +12,7 @@ fi case "$1" in "") java -classpath ${JNA}:. Test ;; + "test") java -classpath ${JNA}:. Test ;; "arm") java -classpath ${JNA}:. TestArm ;; "arm64") java -classpath ${JNA}:. TestArm64 ;; "mips") java -classpath ${JNA}:. TestMips ;; diff --git a/bindings/ocaml/Makefile b/bindings/ocaml/Makefile index 88c571e7b..c9a984477 100644 --- a/bindings/ocaml/Makefile +++ b/bindings/ocaml/Makefile @@ -260,3 +260,11 @@ clean: gen_const: cd .. && python const_generator.py ocaml +TESTS = test test_detail test_arm test_arm64 test_mips test_ppc +TESTS += test_sparc test_systemz test_x86 test_xcore +check: + @for t in $(TESTS); do \ + echo Check $$t ... ; \ + ./$$t > /dev/null && echo OK || echo FAILED; \ + done + diff --git a/bindings/python/Makefile b/bindings/python/Makefile index 75446de38..9ac4c265f 100644 --- a/bindings/python/Makefile +++ b/bindings/python/Makefile @@ -47,3 +47,13 @@ install_cython: clean: rm -rf $(OBJDIR) rm -f capstone/*.so + + +TESTS = test.py test_detail.py test_arm.py test_arm64.py test_mips.py test_ppc.py +TESTS += test_sparc.py test_systemz.py test_x86.py test_xcore.py test_skipdata.py +check: + @for t in $(TESTS); do \ + echo Check $$t ... ; \ + ./$$t > /dev/null && echo OK || echo FAILED; \ + done + diff --git a/bindings/python/test_detail.py b/bindings/python/test_detail.py index 0a2eb3750..e61e8f8ee 100755 --- a/bindings/python/test_detail.py +++ b/bindings/python/test_detail.py @@ -65,7 +65,7 @@ def print_detail(insn): if len(insn.groups) > 0: print("\tThis instruction belongs to groups: ", end=''), for m in insn.groups: - print("%u " % m, end=''), + print("%s " % insn.group_name(m), end=''), print() diff --git a/cs.c b/cs.c index a66af4387..d21798791 100644 --- a/cs.c +++ b/cs.c @@ -422,10 +422,10 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si bool r; void *tmp; size_t skipdata_bytes; - // save all the original info of the buffer - uint64_t offset_org; + uint64_t offset_org; // save all the original info of the buffer size_t size_org; const uint8_t *buffer_org; + unsigned int cache_size = INSN_CACHE_SIZE; if (!handle) { // FIXME: how to handle this case: @@ -435,11 +435,17 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si handle->errnum = CS_ERR_OK; +#ifdef CAPSTONE_USE_SYS_DYN_MEM + if (count > 0 && count < INSN_CACHE_SIZE) + cache_size = count; +#endif + // save the original offset for SKIPDATA buffer_org = buffer; offset_org = offset; size_org = size; - total_size = (sizeof(cs_insn) * INSN_CACHE_SIZE); + + total_size = sizeof(cs_insn) * cache_size; total = cs_mem_malloc(total_size); insn_cache = total; @@ -475,10 +481,15 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si handle->printer(&mci, &ss, handle->printer_info); fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer); + c++; + if (count > 0 && c == count) + // disasm requested number of instructions + break; + f++; - if (f == INSN_CACHE_SIZE) { + if (f == cache_size) { // resize total to contain newly disasm insns - total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE); + total_size += (sizeof(cs_insn) * cache_size); tmp = cs_mem_realloc(total, total_size); if (tmp == NULL) { // insufficient memory if (handle->detail) { @@ -494,17 +505,13 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si } total = tmp; - insn_cache = (cs_insn *)((char *)total + total_size - (sizeof(cs_insn) * INSN_CACHE_SIZE)); + insn_cache = (cs_insn *)((char *)total + total_size - (sizeof(cs_insn) * cache_size)); // reset f back to 0 f = 0; } else insn_cache++; - c++; - if (count > 0 && c == count) - break; - buffer += insn_size; size -= insn_size; offset += insn_size; @@ -544,10 +551,10 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si insn_cache->detail = NULL; f++; - if (f == INSN_CACHE_SIZE) { + if (f == cache_size) { // resize total to contain newly disasm insns - total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE); + total_size += (sizeof(cs_insn) * cache_size); tmp = cs_mem_realloc(total, total_size); if (tmp == NULL) { // insufficient memory if (handle->detail) { @@ -563,7 +570,7 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si } total = tmp; - insn_cache = (cs_insn *)((char *)total + total_size - (sizeof(cs_insn) * INSN_CACHE_SIZE)); + insn_cache = (cs_insn *)((char *)total + total_size - (sizeof(cs_insn) * cache_size)); // reset f back to 0 f = 0; @@ -579,7 +586,7 @@ size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, si if (f) { // resize total to contain newly disasm insns - void *tmp = cs_mem_realloc(total, total_size - (INSN_CACHE_SIZE - f) * sizeof(*insn_cache)); + void *tmp = cs_mem_realloc(total, total_size - (cache_size - f) * sizeof(*insn_cache)); if (tmp == NULL) { // insufficient memory // free all detail pointers if (handle->detail) { diff --git a/tests/test_detail.c b/tests/test_detail.c index 1b51c7552..4039c011e 100644 --- a/tests/test_detail.c +++ b/tests/test_detail.c @@ -240,7 +240,7 @@ static void test() if (detail->groups_count > 0) { printf("\tThis instruction belongs to groups: "); for (n = 0; n < detail->groups_count; n++) { - printf("%u ", detail->groups[n]); + printf("%s ", cs_group_name(handle, detail->groups[n])); } printf("\n"); }