diff --git a/.github/workflows/build-uc2.yml b/.github/workflows/build-uc2.yml index 7e6b7839..5f34b64f 100644 --- a/.github/workflows/build-uc2.yml +++ b/.github/workflows/build-uc2.yml @@ -54,34 +54,34 @@ jobs: archiver: '7z a', generators: 'Ninja' } - - { - os: windows-2019, - arch: x64, - python-arch: x64, - python-ver: '3.8', - name: 'windows-x64 MINGW32 shared', - shared: "yes", - mingw: MINGW32, - mingw-arch: i686, - artifact: 'windows_mingw32.7z', - build_type: 'Debug', - archiver: '7z a', - generators: 'Ninja' - } - - { - os: windows-2019, - arch: x64, - python-arch: x64, - python-ver: '3.8', - name: 'windows-x64 MINGW32 static', - shared: "no", - mingw: MINGW32, - mingw-arch: i686, - artifact: 'windows_mingw32.7z', - build_type: 'Debug', - archiver: '7z a', - generators: 'Ninja' - } + # - { # This fails randomly which can't be reproduced. + # os: windows-2019, + # arch: x64, + # python-arch: x64, + # python-ver: '3.8', + # name: 'windows-x64 MINGW32 shared', + # shared: "yes", + # mingw: MINGW32, + # mingw-arch: i686, + # artifact: 'windows_mingw32.7z', + # build_type: 'Debug', + # archiver: '7z a', + # generators: 'Ninja' + # } + # - { # This fails randomly which can't be reproduced. + # os: windows-2019, + # arch: x64, + # python-arch: x64, + # python-ver: '3.8', + # name: 'windows-x64 MINGW32 static', + # shared: "no", + # mingw: MINGW32, + # mingw-arch: i686, + # artifact: 'windows_mingw32.7z', + # build_type: 'Debug', + # archiver: '7z a', + # generators: 'Ninja' + # } - { os: windows-2019, arch: x64, @@ -95,7 +95,7 @@ jobs: archiver: '7z a', generators: 'Visual Studio 16 2019' } - - { + - { os: windows-2019, arch: x86, python-arch: x86, @@ -328,9 +328,9 @@ jobs: brew install p7zip cmake ninja mkdir build mkdir instdir - cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk/21.4.7075529/build/cmake/android.toolchain.cmake" \ + cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk/25.0.8775105/build/cmake/android.toolchain.cmake" \ -DANDROID_PLATFORM=android-28 \ - -DANDROID_NDK="$ANDROID_HOME/ndk/21.4.7075529" \ + -DANDROID_NDK="$ANDROID_HOME/ndk/25.0.8775105" \ -DANDROID_ABI=${{ matrix.config.arch }} \ -DOLP_SDK_ENABLE_TESTING=NO \ -DOLP_SDK_BUILD_EXAMPLES=ON \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9574be94..85597f46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,16 +3,18 @@ cmake_minimum_required(VERSION 3.1) -if(MSVC) - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") - # set all policies to max supported by actual running cmake version - # mainly want the following: - # CMP0091: prevent msvcrt flags being added to default CMAKE__FLAGS_ - # CMP0092: prevent warning flags being added to default CMAKE__FLAGS - cmake_policy(VERSION ${CMAKE_VERSION}) - else() - message(FATAL_ERROR "please update cmake") - endif() +# Only required for MSVC, but we can't know the compiler at this point because we haven't +# called enable_language() or project(), and if we did that it would lock in the old +# policy. Setting these policies is harmless for non-MSVC though, so just enable them +# always. +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") + # Set explicitly the policies we want rather than raising the base to the current + # version. This prevents unintended behavior changes as CMake evolves and provides a + # consistent experience across different CMake versions. + # CMP0091: prevent msvcrt flags being added to default CMAKE__FLAGS_ + cmake_policy(SET CMP0091 NEW) + # CMP0092: prevent warning flags being added to default CMAKE__FLAGS for MSVC + cmake_policy(SET CMP0092 NEW) endif() # Workaround to fix wrong compiler on macos. @@ -31,6 +33,13 @@ endif() project(unicorn C) +# We depend on the availability of the CMAKE_MSVC_RUNTIME_LIBRARY, which is only +# available in CMake 3.15 and above (see also the comments above in regards to policy +# CMP0091). +if(MSVC AND CMAKE_VERSION VERSION_LESS "3.15") + message(FATAL_ERROR "Please update CMake to 3.15 or greater.") +endif() + # mainline qemu mostly just uses compiler default set(CMAKE_C_STANDARD 11) @@ -1403,6 +1412,9 @@ if(UNICORN_BUILD_TESTS) add_executable(${TEST_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/unit/${TEST_FILE}.c ) + target_compile_options(${TEST_FILE} PRIVATE + ${UNICORN_COMPILE_OPTIONS} + ) target_link_libraries(${TEST_FILE} PRIVATE ${SAMPLES_LIB} ) @@ -1412,6 +1424,9 @@ if(UNICORN_BUILD_TESTS) file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \"chmod +x /data/local/tmp/build/${TEST_FILE}\"\n") file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \'LD_LIBRARY_PATH=/data/local/tmp/build:$LD_LIBRARY_PATH /data/local/tmp/build/${TEST_FILE}\' || exit -1\n") endif() + if (UNICORN_TARGET_ARCH STREQUAL "aarch64" OR UNICORN_TARGET_ARCH STREQUAL "ppc") + target_compile_definitions(${TEST_FILE} PRIVATE TARGET_READ_INLINED) + endif() endforeach() endif() diff --git a/ChangeLog b/ChangeLog index c5db9c2a..85c2600c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ This file details the changelog of Unicorn Engine. ----------------------------------- -[Version 2.0.0]: May 25, 2022 +------------------------------- +[Version 2.0.0]: July 7th, 2022 Features: @@ -10,7 +10,7 @@ Features: Fixes/Improvements: - Build both shared library and static archive as unicorn1 does. -- Misc bindings improvements. #1569 #1600 #1609 #1613 #1616 +- Misc bindings improvements. #1569 #1600 #1609 #1613 #1616 - Make sure setjmp-setjmp-wrapper-win32 participates in the build. #1604 - Improve Rust bindings build logic. - Fix wrong python binding for UC_CTL_TB_REMOVE_CACHE @@ -21,11 +21,15 @@ Fixes/Improvements: - Add type annotations for python bindings. - Add CPUID hook for python bindings. #1618 - Don't repeat memory hooks if there is already an unhandled error. #1618 -- Support reads and writes over all Arm SIMD registers #1621 +- Support reads and writes over all Arm SIMD registers #1621 +- Fix wrong registers range in python bindings. +- Fix uc_mem_protect on mmio regions +- Fix a UAF caused by hook cache. +- Fix the value collision between UC_MODE_ARMBE8 and UC_MODE_ARM926 Thanks: -@AfoHT @mrexodia @bet4it @lowlyw @ekilmer @ondryaso @QDucasse @PalumboN +@AfoHT @mrexodia @bet4it @lowlyw @ekilmer @ondryaso @QDucasse @PalumboN @uberwoozle ---------------------------------- [Version 2.0.0 rc7]: April 17, 2022 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..5398de8c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,2 @@ +aquynh -at- gmail.com +mio -at- lazym.io diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index e233c479..af230df4 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -11,13 +11,13 @@ module Common = let UC_API_MINOR = 0 let UC_API_PATCH = 0 - let UC_API_EXTRA = 7 + let UC_API_EXTRA = 255 let UC_VERSION_MAJOR = 2 let UC_VERSION_MINOR = 0 let UC_VERSION_PATCH = 0 - let UC_VERSION_EXTRA = 7 + let UC_VERSION_EXTRA = 255 let UC_SECOND_SCALE = 1000000 let UC_MILISECOND_SCALE = 1000 let UC_ARCH_ARM = 1 @@ -39,7 +39,7 @@ module Common = let UC_MODE_THUMB = 16 let UC_MODE_MCLASS = 32 let UC_MODE_V8 = 64 - let UC_MODE_ARMBE8 = 128 + let UC_MODE_ARMBE8 = 1024 let UC_MODE_ARM926 = 128 let UC_MODE_ARM946 = 256 let UC_MODE_ARM1176 = 512 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 03ff44bc..107ef745 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -6,13 +6,13 @@ const ( API_MINOR = 0 API_PATCH = 0 - API_EXTRA = 7 + API_EXTRA = 255 VERSION_MAJOR = 2 VERSION_MINOR = 0 VERSION_PATCH = 0 - VERSION_EXTRA = 7 + VERSION_EXTRA = 255 SECOND_SCALE = 1000000 MILISECOND_SCALE = 1000 ARCH_ARM = 1 @@ -34,7 +34,7 @@ const ( MODE_THUMB = 16 MODE_MCLASS = 32 MODE_V8 = 64 - MODE_ARMBE8 = 128 + MODE_ARMBE8 = 1024 MODE_ARM926 = 128 MODE_ARM946 = 256 MODE_ARM1176 = 512 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 24dd7acf..04fb15dd 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -8,13 +8,13 @@ public interface UnicornConst { public static final int UC_API_MINOR = 0; public static final int UC_API_PATCH = 0; - public static final int UC_API_EXTRA = 7; + public static final int UC_API_EXTRA = 255; public static final int UC_VERSION_MAJOR = 2; public static final int UC_VERSION_MINOR = 0; public static final int UC_VERSION_PATCH = 0; - public static final int UC_VERSION_EXTRA = 7; + public static final int UC_VERSION_EXTRA = 255; public static final int UC_SECOND_SCALE = 1000000; public static final int UC_MILISECOND_SCALE = 1000; public static final int UC_ARCH_ARM = 1; @@ -36,7 +36,7 @@ public interface UnicornConst { public static final int UC_MODE_THUMB = 16; public static final int UC_MODE_MCLASS = 32; public static final int UC_MODE_V8 = 64; - public static final int UC_MODE_ARMBE8 = 128; + public static final int UC_MODE_ARMBE8 = 1024; public static final int UC_MODE_ARM926 = 128; public static final int UC_MODE_ARM946 = 256; public static final int UC_MODE_ARM1176 = 512; diff --git a/bindings/pascal/unicorn/UnicornConst.pas b/bindings/pascal/unicorn/UnicornConst.pas index f130dda9..faff27bf 100644 --- a/bindings/pascal/unicorn/UnicornConst.pas +++ b/bindings/pascal/unicorn/UnicornConst.pas @@ -9,13 +9,13 @@ const UC_API_MAJOR = 2; UC_API_MINOR = 0; UC_API_PATCH = 0; - UC_API_EXTRA = 7; + UC_API_EXTRA = 255; UC_VERSION_MAJOR = 2; UC_VERSION_MINOR = 0; UC_VERSION_PATCH = 0; - UC_VERSION_EXTRA = 7; + UC_VERSION_EXTRA = 255; UC_SECOND_SCALE = 1000000; UC_MILISECOND_SCALE = 1000; UC_ARCH_ARM = 1; @@ -37,7 +37,7 @@ const UC_API_MAJOR = 2; UC_MODE_THUMB = 16; UC_MODE_MCLASS = 32; UC_MODE_V8 = 64; - UC_MODE_ARMBE8 = 128; + UC_MODE_ARMBE8 = 1024; UC_MODE_ARM926 = 128; UC_MODE_ARM946 = 256; UC_MODE_ARM1176 = 512; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 28528448..5fdb8537 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -4,13 +4,13 @@ UC_API_MAJOR = 2 UC_API_MINOR = 0 UC_API_PATCH = 0 -UC_API_EXTRA = 7 +UC_API_EXTRA = 255 UC_VERSION_MAJOR = 2 UC_VERSION_MINOR = 0 UC_VERSION_PATCH = 0 -UC_VERSION_EXTRA = 7 +UC_VERSION_EXTRA = 255 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 @@ -32,7 +32,7 @@ UC_MODE_ARM = 0 UC_MODE_THUMB = 16 UC_MODE_MCLASS = 32 UC_MODE_V8 = 64 -UC_MODE_ARMBE8 = 128 +UC_MODE_ARMBE8 = 1024 UC_MODE_ARM926 = 128 UC_MODE_ARM946 = 256 UC_MODE_ARM1176 = 512 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb index d32f42da..1fb21968 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb @@ -6,13 +6,13 @@ module UnicornEngine UC_API_MINOR = 0 UC_API_PATCH = 0 - UC_API_EXTRA = 7 + UC_API_EXTRA = 255 UC_VERSION_MAJOR = 2 UC_VERSION_MINOR = 0 UC_VERSION_PATCH = 0 - UC_VERSION_EXTRA = 7 + UC_VERSION_EXTRA = 255 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 @@ -34,7 +34,7 @@ module UnicornEngine UC_MODE_THUMB = 16 UC_MODE_MCLASS = 32 UC_MODE_V8 = 64 - UC_MODE_ARMBE8 = 128 + UC_MODE_ARMBE8 = 1024 UC_MODE_ARM926 = 128 UC_MODE_ARM946 = 256 UC_MODE_ARM1176 = 512 diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index b226b8f8..7e8185d2 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -165,8 +165,8 @@ bitflags! { const THUMB = 0x10; const MCLASS = 0x20; const V8 = 0x40; - const ARMBE8 = 0x80; - const ARM926 = Self::ARMBE8.bits; + const ARMBE8 = 0x400; + const ARM926 = 0x80; const ARM946 = 0x100; const ARM1176 = 0x200; const MICRO = Self::THUMB.bits; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index c75c2f10..c8315b83 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -118,10 +118,10 @@ typedef enum uc_mode { UC_MODE_ARM = 0, // ARM mode UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2) // Depreciated, use UC_ARM_CPU_* with uc_ctl instead. - UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series. - UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM - UC_MODE_ARMBE8 = 1 << 7, // Big-endian data and Little-endian code. - // Legacy support for UC1 only. + UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series. + UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM + UC_MODE_ARMBE8 = 1 << 10, // Big-endian data and Little-endian code. + // Legacy support for UC1 only. // arm (32bit) cpu types // Depreciated, use UC_ARM_CPU_* with uc_ctl instead. diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index 471ddc94..05266c6f 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -86,11 +86,14 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) case UC_ERR_FETCH_UNALIGNED: break; default: - if (cc->synchronize_from_tb) { - cc->synchronize_from_tb(cpu, last_tb); - } else { - assert(cc->set_pc); - cc->set_pc(cpu, last_tb->pc); + // If we receive a quit request, users has sync-ed PC themselves. + if (!cpu->uc->quit_request) { + if (cc->synchronize_from_tb) { + cc->synchronize_from_tb(cpu, last_tb); + } else { + assert(cc->set_pc); + cc->set_pc(cpu, last_tb->pc); + } } } } @@ -595,6 +598,9 @@ int cpu_exec(struct uc_struct *uc, CPUState *cpu) } tb = tb_find(cpu, last_tb, tb_exit, cflags); + if (unlikely(cpu->exit_request)) { + continue; + } cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); /* Try to align the host and virtual clocks if the guest is in advance */ diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 62233bc0..9305b06c 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1451,7 +1451,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, addr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data))) + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size, 0, hook->user_data))) break; // the last callback may already asked to stop emulation @@ -1466,7 +1466,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, addr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data))) + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size, 0, hook->user_data))) break; // the last callback may already asked to stop emulation @@ -1518,7 +1518,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, addr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, size - uc->size_recur_mem, 0, hook->user_data))) + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, size, 0, hook->user_data))) break; // the last callback may already asked to stop emulation @@ -1546,7 +1546,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, addr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, size - uc->size_recur_mem, 0, hook->user_data))) + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, size, 0, hook->user_data))) break; // the last callback may already asked to stop emulation @@ -1635,11 +1635,15 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, target_ulong addr1, addr2; uint64_t r1, r2; unsigned shift; + int old_size; do_unaligned_access: addr1 = addr & ~((target_ulong)size - 1); addr2 = addr1 + size; + old_size = uc->size_recur_mem; + uc->size_recur_mem = size; r1 = full_load(env, addr1, oi, retaddr); r2 = full_load(env, addr2, oi, retaddr); + uc->size_recur_mem = old_size; shift = (addr & (size - 1)) * 8; if (memop_big_endian(op)) { @@ -1977,7 +1981,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, size_t size = memop_size(op); struct hook *hook; bool handled; - MemoryRegion *mr = memory_mapping(uc, addr); + MemoryRegion *mr; if (!uc->size_recur_mem) { // disabling write callback if in recursive call // Unicorn: callback on memory write @@ -1994,6 +1998,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, } } + // Load the latest memory mapping. + mr = memory_mapping(uc, addr); + // Unicorn: callback on invalid memory if (mr == NULL) { handled = false; @@ -2136,6 +2143,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, CPUTLBEntry *entry2; target_ulong page2, tlb_addr2; size_t size2; + int old_size; do_unaligned_access: /* @@ -2178,6 +2186,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, * This loop must go in the forward direction to avoid issues * with self-modifying code in Windows 64-bit. */ + old_size = uc->size_recur_mem; + uc->size_recur_mem = size; for (i = 0; i < size; ++i) { uint8_t val8; if (memop_big_endian(op)) { @@ -2189,6 +2199,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, } helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr); } + uc->size_recur_mem = old_size; return; } diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 232a9178..91dd5ce7 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1584,9 +1584,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu, phys_pc = get_page_addr_code(env, pc); if (phys_pc == -1) { - /* Generate a temporary TB with 1 insn in it */ - cflags &= ~CF_COUNT_MASK; - cflags |= CF_NOCACHE | 1; + /* Generate a temporary TB; do not cache */ + cflags |= CF_NOCACHE; } cflags &= ~CF_CLUSTER_MASK; diff --git a/qemu/ppc.h b/qemu/ppc.h index 7022629e..eff4b69d 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -1708,4 +1708,12 @@ #define ppc_dcr_init ppc_dcr_init_ppc #define ppc_cpu_pir ppc_cpu_pir_ppc #define ppc_irq_reset ppc_irq_reset_ppc +#define store_booke_tsr store_booke_tsr_ppc +#define get_pteg_offset32 get_pteg_offset32_ppc +#define ppc_booke_timers_init ppc_booke_timers_init_ppc +#define ppc_hash32_handle_mmu_fault ppc_hash32_handle_mmu_fault_ppc +#define gen_helper_store_booke_tsr gen_helper_store_booke_tsr_ppc +#define gen_helper_store_booke_tcr gen_helper_store_booke_tcr_ppc +#define store_booke_tcr store_booke_tcr_ppc +#define ppc_hash32_get_phys_page_debug ppc_hash32_get_phys_page_debug_ppc #endif diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 992caf87..c08ee2d6 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -1708,4 +1708,12 @@ #define ppc_dcr_init ppc_dcr_init_ppc64 #define ppc_cpu_pir ppc_cpu_pir_ppc64 #define ppc_irq_reset ppc_irq_reset_ppc64 +#define store_booke_tsr store_booke_tsr_ppc64 +#define get_pteg_offset32 get_pteg_offset32_ppc64 +#define ppc_booke_timers_init ppc_booke_timers_init_ppc64 +#define ppc_hash32_handle_mmu_fault ppc_hash32_handle_mmu_fault_ppc64 +#define gen_helper_store_booke_tsr gen_helper_store_booke_tsr_ppc64 +#define gen_helper_store_booke_tcr gen_helper_store_booke_tcr_ppc64 +#define store_booke_tcr store_booke_tcr_ppc64 +#define ppc_hash32_get_phys_page_debug ppc_hash32_get_phys_page_debug_ppc64 #endif diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index eef26242..b4dc56f2 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -3378,6 +3378,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, if (is_xmm) reg |= rex_r; mod = (modrm >> 6) & 3; + /* VEX.L (256 bit) encodings are not supported */ + if (s->vex_l != 0) { + goto illegal_op; // perhaps it should be unknown_op? + } if (sse_fn_epp == SSE_SPECIAL) { b |= (b1 << 8); switch(b) { diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index ffdde3fe..b157ce5a 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -109,6 +109,7 @@ static void ppc_release(void *ctx) int i; TCGContext *tcg_ctx = (TCGContext *)ctx; PowerPCCPU *cpu = (PowerPCCPU *)tcg_ctx->uc->cpu; + CPUPPCState *env = &cpu->env; CPUTLBDesc *d = cpu->neg.tlb.d; CPUTLBDescFast *f = cpu->neg.tlb.f; CPUTLBDesc *desc; @@ -132,6 +133,20 @@ static void ppc_release(void *ctx) // g_free(tcg_ctx->tb_ctx.tbs); + if (env->nb_tlb != 0) { + switch (env->tlb_type) { + case TLB_6XX: + g_free(env->tlb.tlb6); + break; + case TLB_EMB: + g_free(env->tlb.tlbe); + break; + case TLB_MAS: + g_free(env->tlb.tlbm); + break; + } + } + ppc_cpu_instance_finalize(tcg_ctx->uc->cpu); ppc_cpu_unrealize(tcg_ctx->uc->cpu); } @@ -292,7 +307,7 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value) break; case UC_PPC_REG_CR: val = *(uint32_t *)value; - for (i = 0; i < 8; i++) { + for (i = 7; i >= 0; i--) { env->crf[i] = val & 0b1111; val >>= 4; } diff --git a/qemu/target/tricore/helper.h b/qemu/target/tricore/helper.h index e1ee5fa0..e0712597 100644 --- a/qemu/target/tricore/helper.h +++ b/qemu/target/tricore/helper.h @@ -22,6 +22,7 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_tricore_exit,void, env) /* Arithmetic */ DEF_HELPER_3(add_ssov, i32, env, i32, i32) diff --git a/qemu/target/tricore/op_helper.c b/qemu/target/tricore/op_helper.c index 57ad816f..6bb7b3a0 100644 --- a/qemu/target/tricore/op_helper.c +++ b/qemu/target/tricore/op_helper.c @@ -2793,3 +2793,12 @@ uint32_t helper_psw_read(CPUTriCoreState *env) { return psw_read(env); } + +void helper_uc_tricore_exit(CPUTriCoreState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +} \ No newline at end of file diff --git a/qemu/target/tricore/translate.c b/qemu/target/tricore/translate.c index 112f2eb0..016306fb 100644 --- a/qemu/target/tricore/translate.c +++ b/qemu/target/tricore/translate.c @@ -33,6 +33,11 @@ #include "exec/translator.h" #include "exec/gen-icount.h" +/* + * Unicorn: Special disas state for exiting in the middle of tb. + */ +#define DISAS_UC_EXIT DISAS_TARGET_6 + static const char *regnames_a[] = { "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , "a6" , "a7" , "a8" , "a9" , "sp" , "a11" , @@ -9227,11 +9232,7 @@ static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, ctx->base.pc_next)) { - gen_helper_rfe(tcg_ctx, tcg_ctx->cpu_env); - tcg_gen_exit_tb(tcg_ctx, NULL, 0); - cpu->exception_index = EXCP_HLT; - cpu->halted = 1; - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_UC_EXIT; } else { insn_lo = cpu_lduw_code(env, ctx->base.pc_next); is_16bit = tricore_insn_is_16bit(insn_lo); @@ -9239,6 +9240,9 @@ static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) insn_size = is_16bit ? 2 : 4; // Unicorn: trace this instruction on request if (HOOK_EXISTS_BOUNDED(ctx->uc, UC_HOOK_CODE, ctx->base.pc_next)) { + // Sync PC in advance + gen_save_pc(ctx, ctx->base.pc_next); + gen_uc_tracecode(tcg_ctx, insn_size, UC_HOOK_CODE_IDX, ctx->uc, ctx->base.pc_next); // the callback might want to stop emulation immediately @@ -9282,6 +9286,10 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_goto_tb(ctx, 0, ctx->base.pc_next); break; + case DISAS_UC_EXIT: + gen_save_pc(ctx, ctx->base.pc_next); + gen_helper_uc_tricore_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env); + break; case DISAS_NORETURN: break; default: @@ -9371,4 +9379,4 @@ void tricore_tcg_init(struct uc_struct *uc) tcg_ctx->cpu_PSW_SAV = tcg_global_mem_new(uc->tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUTriCoreState, PSW_USB_SAV), "PSW_SAV"); -} \ No newline at end of file +} diff --git a/qemu/target/tricore/unicorn.c b/qemu/target/tricore/unicorn.c index 2ccb2c0d..88e937bb 100644 --- a/qemu/target/tricore/unicorn.c +++ b/qemu/target/tricore/unicorn.c @@ -263,6 +263,25 @@ static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model) return 0; } +static void tricore_release(void *ctx) +{ + int i; + TCGContext *tcg_ctx = (TCGContext *)ctx; + TriCoreCPU *cpu = (TriCoreCPU *)tcg_ctx->uc->cpu; + CPUTLBDesc *d = cpu->neg.tlb.d; + CPUTLBDescFast *f = cpu->neg.tlb.f; + CPUTLBDesc *desc; + CPUTLBDescFast *fast; + + release_common(ctx); + for (i = 0; i < NB_MMU_MODES; i++) { + desc = &(d[i]); + fast = &(f[i]); + g_free(desc->iotlb); + g_free(fast->table); + } +} + void tricore_uc_init(struct uc_struct *uc) { uc->reg_read = tricore_reg_read; @@ -271,6 +290,7 @@ void tricore_uc_init(struct uc_struct *uc) uc->set_pc = tricore_set_pc; uc->get_pc = tricore_get_pc; uc->cpus_init = tricore_cpus_init; + uc->release = tricore_release; uc->cpu_context_size = offsetof(CPUTriCoreState, end_reset_fields); uc_common_init(uc); -} \ No newline at end of file +} diff --git a/qemu/tricore.h b/qemu/tricore.h index 6603175f..3f41fc76 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -1286,4 +1286,5 @@ #define helper_pack helper_pack_tricore #define gen_intermediate_code gen_intermediate_code_tricore #define restore_state_to_opc restore_state_to_opc_tricore +#define helper_uc_tricore_exit helper_uc_tricore_exit_tricore #endif diff --git a/samples/sample_ctl.c b/samples/sample_ctl.c index bf55c02a..0b1b5898 100644 --- a/samples/sample_ctl.c +++ b/samples/sample_ctl.c @@ -243,7 +243,8 @@ static void test_uc_ctl_tb_cache() // Now we request cache for all TBs. for (int i = 0; i < TB_COUNT; i++) { - err = uc_ctl_request_cache(uc, ADDRESS + i * TCG_MAX_INSNS, &tb); + err = uc_ctl_request_cache(uc, (uint64_t)(ADDRESS + i * TCG_MAX_INSNS), + &tb); printf(">>> TB is cached at 0x%" PRIx64 " which has %" PRIu16 " instructions with %" PRIu16 " bytes.\n", tb.pc, tb.icount, tb.size); @@ -258,8 +259,8 @@ static void test_uc_ctl_tb_cache() // Now we clear cache for all TBs. for (int i = 0; i < TB_COUNT; i++) { - err = uc_ctl_remove_cache(uc, ADDRESS + i * TCG_MAX_INSNS, - ADDRESS + i * TCG_MAX_INSNS + 1); + err = uc_ctl_remove_cache(uc, (uint64_t)(ADDRESS + i * TCG_MAX_INSNS), + (uint64_t)(ADDRESS + i * TCG_MAX_INSNS + 1)); if (err) { printf("Failed on uc_ctl() with error returned: %u\n", err); return; diff --git a/symbols.sh b/symbols.sh index 2968b959..f2d0a114 100755 --- a/symbols.sh +++ b/symbols.sh @@ -6264,6 +6264,14 @@ ppc_dcr_register \ ppc_dcr_init \ ppc_cpu_pir \ ppc_irq_reset \ +store_booke_tsr \ +get_pteg_offset32 \ +ppc_booke_timers_init \ +ppc_hash32_handle_mmu_fault \ +gen_helper_store_booke_tsr \ +gen_helper_store_booke_tcr \ +store_booke_tcr \ +ppc_hash32_get_phys_page_debug \ " ppc64_SYMBOLS=${ppc_SYMBOLS} @@ -6284,6 +6292,7 @@ helper_fmsub \ helper_pack \ gen_intermediate_code \ restore_state_to_opc \ +helper_uc_tricore_exit \ " ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore" diff --git a/tests/regress/x86_vex.c b/tests/regress/x86_vex.c index a05f2cf6..1808de42 100644 --- a/tests/regress/x86_vex.c +++ b/tests/regress/x86_vex.c @@ -47,12 +47,37 @@ static void test_vmovdqu(void) OK(uc_close(uc)); } +/* https://github.com/unicorn-engine/unicorn/issues/1656 */ +static void test_vex_l(void) +{ + uc_engine *uc; + uc_err err; + + /* vmovdqu ymm1, [rcx] */ + char code[] = { '\xC5', '\xFE', '\x6F', '\x09' }; + + /* initialize memory and run emulation */ + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_mem_map(uc, 0, 2 * 1024 * 1024, UC_PROT_ALL)); + + OK(uc_mem_write(uc, 0, code, sizeof(code) / sizeof(code[0]))); + + err = uc_emu_start(uc, 0, sizeof(code) / sizeof(code[0]), 0, 0); + if(err != UC_ERR_INSN_INVALID) { + fprintf(stderr, "%s", uc_strerror(err)); + assert(false); + } + + OK(uc_close(uc)); +} + /* TODO: Add more vex prefixed instructions Suggestions: vxorpd, vxorps, vandpd, ... */ int main(int argc, char **argv, char **envp) { test_vmovdqu(); + test_vex_l(); return 0; } diff --git a/tests/unit/test_arm64.c b/tests/unit/test_arm64.c index 8afdd0ec..0de80937 100644 --- a/tests/unit/test_arm64.c +++ b/tests/unit/test_arm64.c @@ -1,10 +1,14 @@ +#include "acutest.h" +#include "unicorn/unicorn.h" #include "unicorn_test.h" +#include +#include const uint64_t code_start = 0x1000; const uint64_t code_len = 0x4000; static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode, - const char *code, uint64_t size, uc_cpu_arm cpu) + const char *code, uint64_t size, uc_cpu_arm64 cpu) { OK(uc_open(arch, mode, uc)); OK(uc_ctl_set_cpu_model(*uc, cpu)); @@ -291,6 +295,43 @@ static void test_arm64_correct_address_in_long_jump_hook(void) OK(uc_close(uc)); } +static void test_arm64_block_sync_pc_cb(uc_engine *uc, uint64_t addr, + uint32_t size, void *data) +{ + uint64_t val = code_start; + bool first = *(bool *)data; + if (first) { + OK(uc_reg_write(uc, UC_ARM64_REG_PC, (void *)&val)); + *(bool *)data = false; + } +} + +static void test_arm64_block_sync_pc(void) +{ + uc_engine *uc; + // add x0, x0, #1234;bl t;t:mov x1, #5678; + const char code[] = "\x00\x48\x13\x91\x01\x00\x00\x94\xc1\xc5\x82\xd2"; + uc_hook hk; + uint64_t x0; + bool data = true; + + uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1, + UC_CPU_ARM64_A72); + OK(uc_hook_add(uc, &hk, UC_HOOK_BLOCK, test_arm64_block_sync_pc_cb, + (void *)&data, code_start + 8, code_start + 12)); + + x0 = 0; + OK(uc_reg_write(uc, UC_ARM64_REG_X0, (void *)&x0)); + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_ARM64_REG_X0, (void *)&x0)); + + TEST_CHECK(x0 == (1234 * 2)); + + OK(uc_hook_del(uc, hk)); + OK(uc_close(uc)); +} + TEST_LIST = {{"test_arm64_until", test_arm64_until}, {"test_arm64_code_patching", test_arm64_code_patching}, {"test_arm64_code_patching_count", test_arm64_code_patching_count}, @@ -301,4 +342,5 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until}, test_arm64_correct_address_in_small_jump_hook}, {"test_arm64_correct_address_in_long_jump_hook", test_arm64_correct_address_in_long_jump_hook}, + {"test_arm64_block_sync_pc", test_arm64_block_sync_pc}, {NULL, NULL}}; diff --git a/tests/unit/test_ctl.c b/tests/unit/test_ctl.c index 3b56611d..b96d7cf5 100644 --- a/tests/unit/test_ctl.c +++ b/tests/unit/test_ctl.c @@ -175,6 +175,8 @@ static void test_uc_ctl_tb_cache(void) OK(uc_close(uc)); } +// Test requires UC_ARCH_ARM. +#ifdef UNICORN_HAS_ARM static void test_uc_ctl_change_page_size(void) { uc_engine *uc; @@ -191,7 +193,10 @@ static void test_uc_ctl_change_page_size(void) OK(uc_close(uc)); OK(uc_close(uc2)); } +#endif +// Test requires UC_ARCH_ARM. +#ifdef UNICORN_HAS_ARM // Copy from test_arm.c but with new API. static void test_uc_ctl_arm_cpu(void) { @@ -226,6 +231,7 @@ static void test_uc_ctl_arm_cpu(void) OK(uc_close(uc)); } +#endif static void test_uc_hook_cached_cb(uc_engine *uc, uint64_t addr, size_t size, void *user_data) @@ -289,7 +295,9 @@ TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode}, {"test_uc_ctl_time_out", test_uc_ctl_time_out}, {"test_uc_ctl_exits", test_uc_ctl_exits}, {"test_uc_ctl_tb_cache", test_uc_ctl_tb_cache}, +#ifdef UNICORN_HAS_ARM {"test_uc_ctl_change_page_size", test_uc_ctl_change_page_size}, {"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu}, +#endif {"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf}, - {NULL, NULL}}; \ No newline at end of file + {NULL, NULL}}; diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index fae4b21f..a1db14e1 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -142,6 +142,9 @@ static void test_mem_protect_map_ptr(void) TEST_CHECK(val == mem); OK(uc_close(uc)); + + free(data2); + free(data1); } static void test_map_at_the_end(void) diff --git a/tests/unit/test_ppc.c b/tests/unit/test_ppc.c index b7b34a08..4322a8fd 100644 --- a/tests/unit/test_ppc.c +++ b/tests/unit/test_ppc.c @@ -89,7 +89,24 @@ static void test_ppc32_sc(void) OK(uc_close(uc)); } +static void test_ppc32_cr(void) +{ + uc_engine *uc; + uint32_t r_cr = 0x12345678; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, NULL, 0); + + OK(uc_reg_write(uc, UC_PPC_REG_CR, &r_cr)); + r_cr = 0; + OK(uc_reg_read(uc, UC_PPC_REG_CR, &r_cr)); + + TEST_CHECK(r_cr == 0x12345678); + + OK(uc_close(uc)); +} + TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, {"test_ppc32_fadd", test_ppc32_fadd}, {"test_ppc32_sc", test_ppc32_sc}, + {"test_ppc32_cr", test_ppc32_cr}, {NULL, NULL}}; \ No newline at end of file diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 04d4c76f..a9291f92 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1106,6 +1106,127 @@ static void test_x86_correct_address_in_long_jump_hook(void) OK(uc_close(uc)); } +static void test_x86_invalid_vex_l(void) +{ + uc_engine *uc; + uc_err err; + + /* vmovdqu ymm1, [rcx] */ + char code[] = {'\xC5', '\xFE', '\x6F', '\x09'}; + + /* initialize memory and run emulation */ + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_mem_map(uc, 0, 2 * 1024 * 1024, UC_PROT_ALL)); + + OK(uc_mem_write(uc, 0, code, sizeof(code) / sizeof(code[0]))); + + uc_assert_err(UC_ERR_INSN_INVALID, + uc_emu_start(uc, 0, sizeof(code) / sizeof(code[0]), 0, 0)); + OK(uc_close(uc)); +} + +#ifndef TARGET_READ_INLINED +struct writelog_t { + uint32_t addr, size; +}; + +static void test_x86_unaligned_access_callback(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, + int64_t value, void *user_data) +{ + TEST_CHECK(size != 0); + struct writelog_t *write_log = (struct writelog_t *)user_data; + + for (int i = 0; i < 10; i++) { + if (write_log[i].size == 0) { + write_log[i].addr = (uint32_t)address; + write_log[i].size = (uint32_t)size; + return; + } + } + TEST_ASSERT(false); +} + +static void test_x86_unaligned_access(void) +{ + uc_engine *uc; + uc_hook hook; + // mov dword ptr [0x200001], eax; mov eax, dword ptr [0x200001] + char code[] = "\xa3\x01\x00\x20\x00\xa1\x01\x00\x20\x00"; + uint32_t r_eax = 0x41424344; + struct writelog_t write_log[10]; + struct writelog_t read_log[10]; + memset(write_log, 0, sizeof(write_log)); + memset(read_log, 0, sizeof(read_log)); + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1); + OK(uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_ALL)); + OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_WRITE, + test_x86_unaligned_access_callback, write_log, 1, 0)); + OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_READ, + test_x86_unaligned_access_callback, read_log, 1, 0)); + + OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_eax)); + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + TEST_CHECK(write_log[0].addr == 0x200001); + TEST_CHECK(write_log[0].size == 4); + TEST_CHECK(write_log[1].size == 0); + + TEST_CHECK(read_log[0].addr == 0x200001); + TEST_CHECK(read_log[0].size == 4); + TEST_CHECK(read_log[1].size == 0); + + char b; + OK(uc_mem_read(uc, 0x200001, &b, 1)); + TEST_CHECK(b == 0x44); + OK(uc_mem_read(uc, 0x200002, &b, 1)); + TEST_CHECK(b == 0x43); + OK(uc_mem_read(uc, 0x200003, &b, 1)); + TEST_CHECK(b == 0x42); + OK(uc_mem_read(uc, 0x200004, &b, 1)); + TEST_CHECK(b == 0x41); + + OK(uc_close(uc)); +} +#endif + +static bool test_x86_lazy_mapping_mem_callback(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, + int64_t value, void *user_data) +{ + OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); + OK(uc_mem_write(uc, 0x1000, "\x90\x90", 2)); // nop; nop + + // Handled! + return true; +} + +static void test_x86_lazy_mapping_block_callback(uc_engine *uc, + uint64_t address, + uint32_t size, void *user_data) +{ + int *block_count = (int *)user_data; + (*block_count)++; +} + +static void test_x86_lazy_mapping(void) +{ + uc_engine *uc; + uc_hook mem_hook, block_hook; + int block_count = 0; + + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_hook_add(uc, &mem_hook, UC_HOOK_MEM_FETCH_UNMAPPED, + test_x86_lazy_mapping_mem_callback, NULL, 1, 0)); + OK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK, + test_x86_lazy_mapping_block_callback, &block_count, 1, 0)); + + OK(uc_emu_start(uc, 0x1000, 0x1002, 0, 0)); + TEST_CHECK(block_count == 1); + OK(uc_close(uc)); +} + TEST_LIST = { {"test_x86_in", test_x86_in}, {"test_x86_out", test_x86_out}, @@ -1143,4 +1264,9 @@ TEST_LIST = { test_x86_correct_address_in_small_jump_hook}, {"test_x86_correct_address_in_long_jump_hook", test_x86_correct_address_in_long_jump_hook}, + {"test_x86_invalid_vex_l", test_x86_invalid_vex_l}, +#ifndef TARGET_READ_INLINED + {"test_x86_unaligned_access", test_x86_unaligned_access}, +#endif + {"test_x86_lazy_mapping", test_x86_lazy_mapping}, {NULL, NULL}}; diff --git a/uc.c b/uc.c index 6bff4e77..82471965 100644 --- a/uc.c +++ b/uc.c @@ -2240,7 +2240,7 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) } else { int model = va_arg(args, int); - if (model <= 0 || uc->init_done) { + if (model < 0 || uc->init_done) { err = UC_ERR_ARG; break; }