diff --git a/.github/workflows/CITest.yml b/.github/workflows/CITest.yml index 261948d69b..e37375b08b 100644 --- a/.github/workflows/CITest.yml +++ b/.github/workflows/CITest.yml @@ -36,6 +36,7 @@ jobs: python-arch: x64, python-version: '3.6', build-system: 'cmake', + enable-asan: 'OFF' } - { name: 'ubuntu-22.04 x64 python3.9 make', @@ -44,7 +45,8 @@ jobs: python-arch: x64, python-version: '3.9', build-system: 'make', - } + enable-asan: 'OFF' + } - { name: 'ubuntu-22.04 x64 python3.9 cmake', os: ubuntu-22.04, @@ -52,6 +54,7 @@ jobs: python-arch: x64, python-version: '3.9', build-system: 'cmake', + enable-asan: 'OFF' } - { name: 'ubuntu-22.04 x64 python3.11 cmake', @@ -60,6 +63,16 @@ jobs: python-arch: x64, python-version: '3.11', build-system: 'cmake', + enable-asan: 'OFF' + } + - { + name: 'ubuntu-22.04 x64 python3.11 ASAN', + os: ubuntu-latest, + arch: x64, + python-arch: x64, + python-version: '3.11', + build-system: 'cmake', + enable-asan: 'ON' } steps: @@ -88,35 +101,61 @@ jobs: - name: cmake if: startsWith(matrix.config.build-system, 'cmake') + env: + asan: ${{ matrix.config.enable-asan }} run: | mkdir build && cd build # build static library - cmake -DCAPSTONE_INSTALL=1 -DCMAKE_INSTALL_PREFIX=/usr .. + cmake -DCAPSTONE_INSTALL=1 -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_ASAN=${asan} -DCAPSTONE_BUILD_DIET=${diet_build} .. cmake --build . --config Release # build shared library - cmake -DCAPSTONE_INSTALL=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX=/usr .. + cmake -DCAPSTONE_INSTALL=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX=/usr -DCAPSTONE_BUILD_CSTEST=ON -DENABLE_ASAN=${asan} .. sudo cmake --build . --config Release --target install cp libcapstone.* ../ cp libcapstone.* ../tests/ cp test_* ../tests/ + - name: Lower number of KASL randomized address bits + run: | + # Work-around ASAN bug https://github.com/google/sanitizers/issues/1716 + sudo sysctl vm.mmap_rnd_bits=28 + - name: "Compatibility header test build" + if: matrix.config.diet-build == 'OFF' + env: + asan: ${{ matrix.config.enable-asan }} run: | cd "$(git rev-parse --show-toplevel)/suite/auto-sync/c_tests/" - clang -lcapstone src/test_arm64_compatibility_header.c -o test_arm64_compatibility_header + if [ "$asan" = "ON" ]; then + clang -lcapstone -fsanitize=address src/test_arm64_compatibility_header.c -o test_arm64_compatibility_header + else + clang -lcapstone src/test_arm64_compatibility_header.c -o test_arm64_compatibility_header + fi ./test_arm64_compatibility_header + cd "$(git rev-parse --show-toplevel)" - name: cstool - reaches disassembler engine run: | sh suite/run_invalid_cstool.sh - - name: cstest + - name: cstest (cmake) + if: startsWith(matrix.config.build-system, 'cmake') + run: | + python suite/cstest/cstest_report.py -D -d suite/MC + python suite/cstest/cstest_report.py -D -f suite/cstest/issues.cs + python suite/cstest/cstest_report.py -D -f tests/cs_details/issue.cs + + - name: cstest (make) + if: startsWith(matrix.config.build-system, 'make') run: | cd suite/cstest && ./build_cstest.sh python cstest_report.py -D -t build/cstest -d ../MC - python cstest_report.py -D -t build/cstest -f issues.cs; cd .. + python cstest_report.py -D -t build/cstest -f issues.cs + python cstest_report.py -D -t build/cstest -f ../../tests/cs_details/issue.cs + cd ../../ - name: verify python binding + if: matrix.config.enable-asan == 'OFF' run: | mkdir -p bindings/python/capstone/lib && cp libcapstone.so.5.* bindings/python/capstone/lib/libcapstone.so cd bindings/python @@ -136,6 +175,7 @@ jobs: make check - name: run python binding test + if: matrix.config.enable-asan == 'OFF' run: | cp libcapstone.* bindings/python/prebuilt cd bindings/python @@ -144,6 +184,7 @@ jobs: BUILD_TESTS=no make tests - name: run cython binding test + if: matrix.config.enable-asan == 'OFF' run: | pip install cython cd bindings/python diff --git a/CMakeLists.txt b/CMakeLists.txt index e7df843f47..f5ef275162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,13 @@ option(CAPSTONE_USE_ARCH_REGISTRATION "Use explicit architecture registration" O option(CAPSTONE_ARCHITECTURE_DEFAULT "Whether architectures are enabled by default" ON) option(CAPSTONE_DEBUG "Whether to enable extra debug assertions" OFF) option(CAPSTONE_INSTALL "Generate install target" ${PROJECT_IS_TOP_LEVEL}) +option(ENABLE_ASAN "Enable address sanitizer" OFF) + +if (ENABLE_ASAN) + add_definitions(-DASAN_ENABLED) + add_compile_options(-fsanitize=address) + add_link_options(-fsanitize=address) +endif() # If building for OSX it's best to allow CMake to handle building both architectures if(APPLE AND NOT CAPSTONE_BUILD_MACOS_THIN) @@ -855,16 +862,28 @@ if(CAPSTONE_BUILD_CSTOOL) endif() if(CAPSTONE_BUILD_CSTEST) - find_package(PkgConfig REQUIRED) - pkg_check_modules(CMOCKA REQUIRED IMPORTED_TARGET cmocka) + include(ExternalProject) + ExternalProject_Add(cmocka_ext + PREFIX extern + GIT_REPOSITORY "https://git.cryptomilk.org/projects/cmocka.git" + GIT_TAG "origin/stable-1.1" + CONFIGURE_COMMAND cmake -DBUILD_SHARED_LIBS=OFF ../cmocka_ext/ + BUILD_COMMAND cmake --build . --config Release + INSTALL_COMMAND "" + ) + set(CMOCKA_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/extern/src/cmocka_ext/include) + set(CMOCKA_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/extern/src/cmocka_ext-build/src/) + add_library(cmocka STATIC IMPORTED) + set_target_properties(cmocka PROPERTIES IMPORTED_LOCATION ${CMOCKA_LIB_DIR}/libcmocka.a) file(GLOB CSTEST_SRC suite/cstest/src/*.c) add_executable(cstest ${CSTEST_SRC}) - target_link_libraries(cstest PUBLIC capstone PkgConfig::CMOCKA) + add_dependencies(cstest cmocka_ext) + target_link_libraries(cstest PUBLIC capstone cmocka) target_include_directories(cstest PRIVATE $ ${PROJECT_SOURCE_DIR}/suite/cstest/include - ${CMOCKA_INCLUDE_DIRS} + ${CMOCKA_INCLUDE_DIR} ) if(CAPSTONE_INSTALL) diff --git a/COMPILE_CMAKE.TXT b/COMPILE_CMAKE.TXT index dfe491f966..a35396d511 100644 --- a/COMPILE_CMAKE.TXT +++ b/COMPILE_CMAKE.TXT @@ -56,6 +56,8 @@ Get CMake for free from http://www.cmake.org. - CAPSTONE_X86_REDUCE: change this to ON to make X86 binary smaller. - CAPSTONE_X86_ATT_DISABLE: change this to ON to disable AT&T syntax on x86. - CAPSTONE_DEBUG: change this to ON to enable extra debug assertions. + - CAPSTONE_BUILD_CSTEST: Build `cstest` in `suite/cstest/` + - ENABLE_ASAN: Compiles Capstone with the address sanitizer. By default, Capstone use system dynamic memory management, and both DIET and X86_REDUCE modes are disabled. To use your own memory allocations, turn ON both DIET & diff --git a/Mapping.h b/Mapping.h index 9b5de0afe0..aaaf6446d0 100644 --- a/Mapping.h +++ b/Mapping.h @@ -74,17 +74,27 @@ const cs_ac_type mapping_get_op_access(MCInst *MI, unsigned OpNum, /// Macro for easier access of operand types from the map. /// Assumes the istruction operands map is called "insn_operands" /// Only usable by `auto-sync` archs! +#ifndef CAPSTONE_DIET #define map_get_op_type(MI, OpNum) \ mapping_get_op_type(MI, OpNum, (const map_insn_ops *)insn_operands, \ sizeof(insn_operands) / sizeof(insn_operands[0])) +#else +#define map_get_op_type(MI, OpNum) \ + CS_OP_INVALID +#endif /// Macro for easier access of operand access flags from the map. /// Assumes the istruction operands map is called "insn_operands" /// Only usable by `auto-sync` archs! +#ifndef CAPSTONE_DIET #define map_get_op_access(MI, OpNum) \ mapping_get_op_access(MI, OpNum, (const map_insn_ops *)insn_operands, \ sizeof(insn_operands) / \ sizeof(insn_operands[0])) +#else +#define map_get_op_access(MI, OpNum) \ + CS_AC_INVALID +#endif ///< Map for ids to their string typedef struct name_map { @@ -212,4 +222,4 @@ bool map_use_alias_details(const MCInst *MI); void map_set_alias_id(MCInst *MI, const SStream *O, const name_map *alias_mnem_id_map, int map_size); -#endif // CS_MAPPING_H \ No newline at end of file +#endif // CS_MAPPING_H diff --git a/arch/ARM/ARMMapping.c b/arch/ARM/ARMMapping.c index beb0214a02..b11326aef3 100644 --- a/arch/ARM/ARMMapping.c +++ b/arch/ARM/ARMMapping.c @@ -762,11 +762,11 @@ void ARM_init_mri(MCRegisterInfo *MRI) ARR_SIZE(ARMSubRegIdxLists), 0); } +#ifndef CAPSTONE_DIET static const map_insn_ops insn_operands[] = { #include "ARMGenCSMappingInsnOp.inc" }; -#ifndef CAPSTONE_DIET void ARM_reg_access(const cs_insn *insn, cs_regs regs_read, uint8_t *regs_read_count, cs_regs regs_write, uint8_t *regs_write_count) diff --git a/arch/HPPA/HPPAInstPrinter.c b/arch/HPPA/HPPAInstPrinter.c index 69e248cc72..9e4aad9e47 100644 --- a/arch/HPPA/HPPAInstPrinter.c +++ b/arch/HPPA/HPPAInstPrinter.c @@ -760,6 +760,7 @@ static void add_groups(MCInst *MI) } } +#ifndef CAPSTONE_DIET static void update_regs_access(MCInst *MI, unsigned int opcode) { if (opcode == HPPA_INS_INVALID) @@ -803,6 +804,7 @@ static void update_regs_access(MCInst *MI, unsigned int opcode) break; } } +#endif void HPPA_printInst(MCInst *MI, SStream *O, void *Info) { diff --git a/arch/HPPA/HPPAMapping.c b/arch/HPPA/HPPAMapping.c index 7922861c41..0c14d0e498 100644 --- a/arch/HPPA/HPPAMapping.c +++ b/arch/HPPA/HPPAMapping.c @@ -300,6 +300,7 @@ const char *HPPA_insn_name(csh handle, unsigned int id) #endif } +#ifndef CAPSTONE_DIET /* Integer register names, indexed by the numbers which appear in the opcodes. */ static const char *const reg_names[] = { @@ -341,6 +342,7 @@ static const char *const sp_fp_reg[] = { "fr16R", "fr17R", "fr18R", "fr19R", "fr20R", "fr21R", "fr22R", "fr23R", "fr24R", "fr25R", "fr26R", "fr27R", "fr28R", "fr29R", "fr30R", "fr31R" }; +#endif const char *HPPA_reg_name(csh handle, unsigned int reg) { @@ -437,4 +439,4 @@ void HPPA_reg_access(const cs_insn *insn, cs_regs regs_read, sort_and_uniq(regs_write, write_count, regs_write_count); } -#endif \ No newline at end of file +#endif diff --git a/arch/PowerPC/PPCMapping.c b/arch/PowerPC/PPCMapping.c index 2d11674389..725f4838a6 100644 --- a/arch/PowerPC/PPCMapping.c +++ b/arch/PowerPC/PPCMapping.c @@ -225,8 +225,10 @@ void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) MI->fillDetailOps = detail_is_set(MI); MI->flat_insn->usesAliasDetails = map_use_alias_details(MI); PPC_LLVM_printInst(MI, MI->address, "", O); +#ifndef CAPSTONE_DIET map_set_alias_id(MI, O, insn_alias_mnem_map, ARR_SIZE(insn_alias_mnem_map)); +#endif } bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len, @@ -264,9 +266,11 @@ bool PPC_getFeatureBits(unsigned int mode, unsigned int feature) return true; } +#ifndef CAPSTONE_DIET static const map_insn_ops insn_operands[] = { #include "PPCGenCSMappingInsnOp.inc" }; +#endif /// @brief Handles memory operands. /// @param MI The MCInst. diff --git a/cs.c b/cs.c index aac3d4c758..dfeaaa0e1e 100644 --- a/cs.c +++ b/cs.c @@ -697,7 +697,7 @@ CAPSTONE_EXPORT cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle) { cs_err err; - struct cs_struct *ud; + struct cs_struct *ud = NULL; if (!cs_mem_malloc || !cs_mem_calloc || !cs_mem_realloc || !cs_mem_free || !cs_vsnprintf) // Error: before cs_open(), dynamic memory management must be initialized // with cs_option(CS_OPT_MEM) @@ -736,6 +736,7 @@ cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle) return CS_ERR_OK; } else { + cs_mem_free(ud); *handle = 0; return CS_ERR_ARCH; } @@ -744,8 +745,8 @@ cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle) CAPSTONE_EXPORT cs_err CAPSTONE_API cs_close(csh *handle) { - struct cs_struct *ud; - struct insn_mnem *next, *tmp; + struct cs_struct *ud = NULL; + struct insn_mnem *next = NULL, *tmp = NULL; if (*handle == 0) // invalid handle diff --git a/cstool/cstool.c b/cstool/cstool.c index 795850840f..670450eaf9 100644 --- a/cstool/cstool.c +++ b/cstool/cstool.c @@ -678,13 +678,15 @@ int main(int argc, char **argv) } cs_free(insn, count); + free(assembly); } else { printf("ERROR: invalid assembly code\n"); + cs_close(&handle); + free(assembly); return(-4); } cs_close(&handle); - free(assembly); return 0; } diff --git a/cstool/cstool_arm.c b/cstool/cstool_arm.c index a5882e1941..439d11063e 100644 --- a/cstool/cstool_arm.c +++ b/cstool/cstool_arm.c @@ -58,6 +58,8 @@ void print_insn_detail_arm(csh handle, cs_insn *ins) printf("\t\t\toperands[%u].mem.scale: %d\n", i, op->mem.scale); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + if (op->mem.align != 0) + printf("\t\t\toperands[%u].mem.align: 0x%x\n", i, op->mem.align); if (op->mem.lshift != 0) printf("\t\t\toperands[%u].mem.lshift: 0x%x\n", i, op->mem.lshift); diff --git a/docs/cs_v6_release_guide.md b/docs/cs_v6_release_guide.md index 896479c91a..bdaf379585 100644 --- a/docs/cs_v6_release_guide.md +++ b/docs/cs_v6_release_guide.md @@ -174,6 +174,7 @@ These features are only supported by `auto-sync`-enabled architectures. **More code quality checks** - `clang-tidy` is now run on all files changed by a PR. +- ASAN: All tests are now run with the address sanitizer enabled. This includes checking for leaks. **Instruction formats for PPC** diff --git a/suite/cstest/Makefile b/suite/cstest/Makefile index a5ad34a798..ae80597807 100644 --- a/suite/cstest/Makefile +++ b/suite/cstest/Makefile @@ -6,7 +6,7 @@ LIBRARY = -lcmocka -lcapstone -L../.. all: rm -rf $(BUILD) mkdir $(BUILD) - $(CC) $(SOURCE)/*.c $(INCLUDE:%=-I %) -g -o $(BUILD)/cstest $(LIBRARY) + $(CC) $(SOURCE)/*.c $(INCLUDE:%=-I %) ${CMAKE_C_FLAGS} -g -o $(BUILD)/cstest $(LIBRARY) cstest: $(BUILD)/cstest -d ../MC clean: diff --git a/suite/cstest/README.md b/suite/cstest/README.md index d2d2b4cc8e..dfc31cdea3 100644 --- a/suite/cstest/README.md +++ b/suite/cstest/README.md @@ -13,23 +13,12 @@ brew install cmocka - Build Cmocka -``` -cd cmocka_dir -mkdir build -cd build -cmake .. -make -sudo make install -``` - ## Build -- Build `cstest` +You can build `cstest` with `cmake` when building Capstone. Just pass the `CAPSTONE_BUILD_CSTEST` flag +during configuration. -``` -cd suite/cstest -make -``` +Alternatively you can use the `build_cstest.sh` file in this directory. ## Usage diff --git a/suite/cstest/build_cstest.sh b/suite/cstest/build_cstest.sh index 5b4ba4c2b5..ba3c81d81c 100755 --- a/suite/cstest/build_cstest.sh +++ b/suite/cstest/build_cstest.sh @@ -1,9 +1,21 @@ -#!/bin/sh +#!/bin/sh -x + +cd cmocka +mkdir build +cd build -cd cmocka && mkdir build && cd build if [ "$(uname)" = Darwin ]; then -cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. && make -j2 && sudo make install + cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. && make -j2 && sudo make install +elif [ "$asan" = "ON" ]; then + CMAKE_C_FLAGS="-fsanitize=address" CMAKE_LINK_FLAGS="-fsanitize=address" cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. && make -j2 && sudo make install else # Linux -cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j2 && sudo make install + cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j2 && sudo make install +fi + +cd ../.. + +if [ "$asan" = "ON" ]; then + CMAKE_C_FLAGS="-fsanitize=address" make +else + make fi -cd ../.. && make diff --git a/suite/cstest/cstest_report.py b/suite/cstest/cstest_report.py index 56854aa4f6..45254c65c0 100755 --- a/suite/cstest/cstest_report.py +++ b/suite/cstest/cstest_report.py @@ -15,7 +15,7 @@ def Usage(s): sys.exit(-1) def get_report_file(toolpath, filepath, getDetails, cmt_out): - cmd = [toolpath, '-f', filepath] + cmd = [toolpath if toolpath else "cstest", '-f', filepath] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() if process.returncode != 0: diff --git a/suite/cstest/include/helper.h b/suite/cstest/include/helper.h index fcdeabffaa..a20dcca13b 100644 --- a/suite/cstest/include/helper.h +++ b/suite/cstest/include/helper.h @@ -17,7 +17,7 @@ #define X86_32 1 #define X86_64 2 -char **split(char *str, char *delim, int *size); +char **split(const char *str, const char *delim, int *size); void print_strs(char **list_str, int size); void free_strs(char **list_str, int size); void add_str(char **src, const char *format, ...); diff --git a/suite/cstest/src/arm_detail.c b/suite/cstest/src/arm_detail.c index 2e0647eff8..42ac67e5eb 100644 --- a/suite/cstest/src/arm_detail.c +++ b/suite/cstest/src/arm_detail.c @@ -52,6 +52,8 @@ char *get_detail_arm(csh *handle, cs_mode mode, cs_insn *ins) add_str(&result, " ; operands[%u].mem.scale: %d", i, op->mem.scale); if (op->mem.disp != 0) add_str(&result, " ; operands[%u].mem.disp: 0x%x", i, op->mem.disp); + if (op->mem.align != 0) + add_str(&result, " ; operands[%u].mem.align: 0x%x", i, op->mem.align); if (op->mem.lshift != 0) add_str(&result, " ; operands[%u].mem.lshift: 0x%x", i, op->mem.lshift); diff --git a/suite/cstest/src/capstone_test.c b/suite/cstest/src/capstone_test.c index 1cb8ae5cf9..91ccbd7280 100644 --- a/suite/cstest/src/capstone_test.c +++ b/suite/cstest/src/capstone_test.c @@ -85,6 +85,10 @@ void test_single_MC(csh *handle, int mc_mode, char *line) // and laeds to wrong results. cs_arch arch = ((struct cs_struct *)(uintptr_t)*handle)->arch; if (arch != CS_ARCH_ARM) { + if (insn->detail) { + free(insn->detail); + } + free(insn); cs_disasm(*handle, code, size_byte, offset, 0, &insn); strcpy(tmp_noreg, insn[0].mnemonic); @@ -232,6 +236,7 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) offset = 0; list_byte = split(offset_opcode[0], ",", &size_byte); } + free_strs(offset_opcode, size_offset_opcode); code = (unsigned char *)malloc(sizeof(char) * size_byte); for (i = 0; i < size_byte; ++i) { @@ -239,6 +244,8 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) } count = cs_disasm(*handle, code, size_byte, offset, 0, &insn); + free_strs(list_byte, size_byte); + free(code); for (i = 0; i < count; ++i) { tmp = (char *)malloc(strlen(insn[i].mnemonic) + strlen(insn[i].op_str) + 100); strcpy(tmp, insn[i].mnemonic); @@ -280,10 +287,10 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) fprintf(stderr, "[ ERROR ] --- %s --- \"%s\" not in \"%s\"\n", list_part[0], list_part_issue_result[i], cs_result); cs_free(insn, count); free_strs(list_part, size_part); - free_strs(list_byte, size_byte); free(cs_result); // free_strs(list_part_cs_result, size_part_cs_result); free_strs(list_part_issue_result, size_part_issue_result); + free(tmptmp); _fail(__FILE__, __LINE__); } free(tmptmp); @@ -291,7 +298,6 @@ void test_single_issue(csh *handle, cs_mode mode, char *line, int detail) cs_free(insn, count); free_strs(list_part, size_part); - free_strs(list_byte, size_byte); free(cs_result); // free_strs(list_part_cs_result, size_part_cs_result); free_strs(list_part_issue_result, size_part_issue_result); diff --git a/suite/cstest/src/helper.c b/suite/cstest/src/helper.c index ccf9f1d466..6c3080e7f6 100644 --- a/suite/cstest/src/helper.c +++ b/suite/cstest/src/helper.c @@ -4,15 +4,12 @@ #include "helper.h" -char **split(char *str, char *delim, int *size) +char **split(const char *str, const char *delim, int *size) { - char **result; - char *token, *src; - int cnt; - - cnt = 0; - src = str; - result = NULL; + char **result = NULL; + char *token = NULL; + const char *src = str; + int cnt = 0; while ((token = strstr(src, delim)) != NULL) { result = (char **)realloc(result, sizeof(char *) * (cnt + 1)); diff --git a/suite/cstest/src/main.c b/suite/cstest/src/main.c index 0a02449ec8..651bda683f 100644 --- a/suite/cstest/src/main.c +++ b/suite/cstest/src/main.c @@ -431,6 +431,11 @@ static void test_file(const char *filename) printf("[!] Noted:\n[ ERROR ] --- \"\" != \"\"\n"); printf("\n\n"); free_strs(list_lines, size_lines); + for (int k = 0; tests && k < number_of_tests; k++) { + free((char *)tests[k].name); + } + free(tests); + free(content); } static void test_folder(const char *folder) diff --git a/suite/run_invalid_cstool.sh b/suite/run_invalid_cstool.sh index 48d327f1a3..e0ca532cb9 100644 --- a/suite/run_invalid_cstool.sh +++ b/suite/run_invalid_cstool.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -x cstool -d x64 0x4 | grep "ERROR: invalid assembly code" && cstool -d arm 0x1 | grep "ERROR: invalid assembly code" && @@ -27,3 +27,5 @@ cstool -d riscv64 0x1 | grep "ERROR: invalid assembly code" && cstool -d sh 0x1 | grep "ERROR: invalid assembly code" && cstool -d tc162 0x1 | grep "ERROR: invalid assembly code" +# One successful disassembly +cstool -d x64 0xc5,0xca,0x58,0xd4 diff --git a/tests/cs_details/issue.cs b/tests/cs_details/issue.cs index 0c991439e2..a4cd5cbd6d 100644 --- a/tests/cs_details/issue.cs +++ b/tests/cs_details/issue.cs @@ -130,7 +130,7 @@ !# issue 0 ARM operand groups 0xa4,0xf9,0x6d,0x0e == vld3.16 {d0[], d2[], d4[]}, [r4]! ; !# CS_ARCH_ARM, CS_MODE_THUMB, CS_OPT_DETAIL -0xa4,0xf9,0x6d,0x0e == vld3.16 {d0[], d2[], d4[]}, [r4]! ; op_count: 4 ; operands[0].type: REG = d0 ; operands[0].access: WRITE ; operands[1].type: REG = d2 ; operands[1].access: WRITE ; operands[2].type: REG = d4 ; operands[2].access: WRITE ; operands[3].type: MEM ; operands[3].mem.index: REG = r4 ; operands[3].access: READ ; Write-back: True ; Registers read: r4 ; Registers modified: r4 d0 d2 d4 +0xa4,0xf9,0x6d,0x0e == vld3.16 {d0[], d2[], d4[]}, [r4]! ; op_count: 4 ; operands[0].type: REG = d0 ; operands[0].access: WRITE ; operands[1].type: REG = d2 ; operands[1].access: WRITE ; operands[2].type: REG = d4 ; operands[2].access: WRITE ; operands[3].type: MEM ; operands[3].mem.base: REG = r4 ; operands[3].access: READ | WRITE ; Write-back: True ; Registers read: r4 ; Registers modified: r4 d0 d2 d4 !# issue 0 ARM operand groups 0x0d,0x50,0x66,0xe4 == strbt r5, [r6], #-13 ; !# CS_ARCH_ARM, CS_MODE_ARM, CS_OPT_DETAIL @@ -166,7 +166,7 @@ !# issue 0 ARM operand groups 0xa4,0xf9,0xed,0x0b == vld4.32 {d0[1], d2[1], d4[1], d6[1]}, [r4:128]! ; !# CS_ARCH_ARM, CS_MODE_THUMB, CS_OPT_DETAIL -0xa4,0xf9,0xed,0x0b == vld4.32 {d0[1], d2[1], d4[1], d6[1]}, [r4:0x80]! ; op_count: 5 ; operands[0].type: REG = d0 ; operands[0].neon_lane = 1 ; operands[0].access: READ | WRITE ; operands[1].type: REG = d2 ; operands[1].neon_lane = 1 ; operands[1].access: READ | WRITE ; operands[2].type: REG = d4 ; operands[2].neon_lane = 1 ; operands[2].access: READ | WRITE ; operands[3].type: REG = d6 ; operands[3].neon_lane = 1 ; operands[3].access: READ | WRITE ; operands[4].type: MEM ; operands[4].mem.index: REG = r4 ; operands[4].mem.disp: 0x80 ; operands[4].access: READ ; Write-back: True ; Registers read: d0 d2 d4 d6 r4 ; Registers modified: r4 d0 d2 d4 d6 +0xa4,0xf9,0xed,0x0b == vld4.32 {d0[1], d2[1], d4[1], d6[1]}, [r4:0x80]! ; op_count: 5 ; operands[0].type: REG = d0 ; operands[0].neon_lane = 1 ; operands[0].access: READ | WRITE ; operands[1].type: REG = d2 ; operands[1].neon_lane = 1 ; operands[1].access: READ | WRITE ; operands[2].type: REG = d4 ; operands[2].neon_lane = 1 ; operands[2].access: READ | WRITE ; operands[3].type: REG = d6 ; operands[3].neon_lane = 1 ; operands[3].access: READ | WRITE ; operands[4].type: MEM ; operands[4].mem.base: REG = r4 ; operands[4].mem.align: 0x80 ; operands[4].access: READ | WRITE ; Write-back: True ; Registers read: d0 d2 d4 d6 r4 ; Registers modified: r4 d0 d2 d4 d6 !# issue 0 ARM operand groups 0x42,0x03,0xb0,0xf3 == aesd.8 q0, q1 ; !# CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_V8, CS_OPT_DETAIL @@ -202,5 +202,5 @@ !# issue 0 ARM operand groups 0xef,0xf3,0x11,0x85 == ldrhi pc, [r1, #-0x3ef] !# CS_ARCH_ARM, CS_MODE_ARM, CS_OPT_DETAIL -0xef,0xf3,0x11,0x85 == ldrhi pc, [r1, #-0x3ef] ; op_count: 2 ; operands[0].type: REG = r15 ; operands[0].access: WRITE ; operands[1].type: MEM ; operands[1].mem.base: REG = r1 ; operands[1].mem.disp: 0x3ef ; operands[1].access: READ ; Code condition: 8 ; Registers read: cpsr r1 ; Registers modified: r15 ; Groups: IsARM +0xef,0xf3,0x11,0x85 == ldrhi pc, [r1, #-0x3ef] ; op_count: 2 ; operands[0].type: REG = r15 ; operands[0].access: WRITE ; operands[1].type: MEM ; operands[1].mem.base: REG = r1 ; operands[1].mem.disp: 0x3ef ; operands[1].access: READ ; Code condition: 8 ; Registers read: cpsr r1 ; Registers modified: r15 ; Groups: IsARM jump