From 7f48b1dd4a7eba269f532a0f1cf03be896142e58 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 12 Apr 2025 21:38:14 +0800 Subject: [PATCH] No longer used hacked liveness_pass_1 This hack was introduced in issue#287 which later becomes endless maintainance pain. ===== Our previous check_exit_request use `brcond` in the middle of a TranslationBlock which breaks the assumptions and thus a hack to liveness_pass_1 is used for _all_ brcond instructions which causes issues for MIPS and many other scenarios. ===== This patch also resolves PC not sync-ed when no memory hooks are installed, finally. Now Unicorn will always have correct PC no matter what happens. --- include/uc_priv.h | 1 + qemu/aarch64.h | 1 + qemu/accel/tcg/cputlb.c | 8 ++++---- qemu/accel/tcg/tcg-runtime.c | 22 ++++++++++++++++++++++ qemu/accel/tcg/tcg-runtime.h | 2 ++ qemu/arm.h | 1 + qemu/include/exec/gen-icount.h | 24 ++++++------------------ qemu/include/tcg/tcg.h | 1 - qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/ppc.h | 1 + qemu/ppc64.h | 1 + qemu/riscv32.h | 1 + qemu/riscv64.h | 1 + qemu/s390x.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/tcg/tcg-op.c | 20 ++++++-------------- qemu/tcg/tcg.c | 26 +------------------------- qemu/tricore.h | 1 + qemu/x86_64.h | 1 + symbols.sh | 1 + tests/unit/test_arm64.c | 19 +++++++++++++++++++ tests/unit/test_mips.c | 2 +- uc.c | 1 + 28 files changed, 80 insertions(+), 63 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 484fc53e..9785e824 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -423,6 +423,7 @@ struct uc_struct { uint64_t nested; // the nested level of all exposed API bool thread_executable_entry; bool current_executable; + bool skip_sync_pc_on_exit; }; // Metadata stub for the variable-size cpu context used with uc_context_*() diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 6f131502..f7170a78 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _aarch64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_aarch64 #define unicorn_fill_tlb unicorn_fill_tlb_aarch64 #define reg_read reg_read_aarch64 #define reg_write reg_write_aarch64 diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index f7ffee48..e11d7c24 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1575,7 +1575,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, // because qemu might generate tcg code like: // qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1 // where we don't have a change to recover x0 value - cpu_loop_exit(uc->cpu); + cpu_loop_exit_restore(uc->cpu, retaddr); } return 0; } @@ -1586,7 +1586,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above - cpu_loop_exit(uc->cpu); + cpu_loop_exit_restore(uc->cpu, retaddr); } return 0; } @@ -1660,7 +1660,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above - cpu_loop_exit(uc->cpu); + cpu_loop_exit_restore(uc->cpu, retaddr); } return 0; } @@ -1694,7 +1694,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above - cpu_loop_exit(uc->cpu); + cpu_loop_exit_restore(uc->cpu, retaddr); } return 0; } diff --git a/qemu/accel/tcg/tcg-runtime.c b/qemu/accel/tcg/tcg-runtime.c index 1e8283ea..5b9ecb16 100644 --- a/qemu/accel/tcg/tcg-runtime.c +++ b/qemu/accel/tcg/tcg-runtime.c @@ -164,3 +164,25 @@ void HELPER(exit_atomic)(CPUArchState *env) { cpu_loop_exit_atomic(env_cpu(env), GETPC()); } + +void HELPER(check_exit_request)(void *p, uint32_t in_delay_slot) { + uc_engine *uc = p; + + if (cpu_loop_exit_requested(uc->cpu) && !in_delay_slot) { + // There are stil something we have to before exiting to be compatible with previous behaviors + + // from cpu_tb_exec + if (uc->nested_level == 1) { + // Only unlock (allow writing to JIT area) if we are the outmost uc_emu_start + tb_exec_unlock(uc); + } + uc->cpu->tcg_exit_req = 0; + + if (uc->skip_sync_pc_on_exit) { + cpu_loop_exit(uc->cpu); + } else { + uc->skip_sync_pc_on_exit = false; + cpu_loop_exit_restore(uc->cpu, GETPC()); + } + } +} \ No newline at end of file diff --git a/qemu/accel/tcg/tcg-runtime.h b/qemu/accel/tcg/tcg-runtime.h index ab7369e8..8ba10e18 100644 --- a/qemu/accel/tcg/tcg-runtime.h +++ b/qemu/accel/tcg/tcg-runtime.h @@ -259,3 +259,5 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_2(check_exit_request, void, ptr, i32) \ No newline at end of file diff --git a/qemu/arm.h b/qemu/arm.h index 27592db3..8337fe87 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _arm #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_arm #define unicorn_fill_tlb unicorn_fill_tlb_arm #define reg_read reg_read_arm #define reg_write reg_write_arm diff --git a/qemu/include/exec/gen-icount.h b/qemu/include/exec/gen-icount.h index 79f5726f..8b484cbc 100644 --- a/qemu/include/exec/gen-icount.h +++ b/qemu/include/exec/gen-icount.h @@ -32,28 +32,17 @@ static inline void gen_io_end(TCGContext *tcg_ctx) static inline void gen_tb_start(TCGContext *tcg_ctx, TranslationBlock *tb) { - TCGv_i32 count; - - tcg_ctx->exitreq_label = gen_new_label(tcg_ctx); - - count = tcg_temp_new_i32(tcg_ctx); - - tcg_gen_ld_i32(tcg_ctx, count, tcg_ctx->cpu_env, - offsetof(ArchCPU, neg.icount_decr.u32) - - offsetof(ArchCPU, env)); + TCGv_ptr puc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); + TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 0); // Unicorn: // We CANT'T use brcondi_i32 here or we will fail liveness analysis // because it marks the end of BB if (tcg_ctx->delay_slot_flag != NULL) { - // Initialize delay_slot_flag here - tcg_gen_movi_i32(tcg_ctx, tcg_ctx->delay_slot_flag, 0); - TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 0); - // dest = (c1 cond c2 ? v1 : v2) - tcg_gen_movcond_i32(tcg_ctx, TCG_COND_GT, count, tcg_ctx->delay_slot_flag, tmp, tcg_ctx->delay_slot_flag, count); - tcg_temp_free_i32(tcg_ctx, tmp); + tcg_gen_mov_i32(tcg_ctx, tmp, tcg_ctx->delay_slot_flag); } - tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_LT, count, 0, tcg_ctx->exitreq_label); - tcg_temp_free_i32(tcg_ctx, count); + gen_helper_check_exit_request(tcg_ctx, puc, tmp); + tcg_temp_free_i32(tcg_ctx, tmp); + tcg_temp_free_ptr(tcg_ctx, puc); } static inline void gen_tb_end(TCGContext *tcg_ctx, TranslationBlock *tb, int num_insns) @@ -68,7 +57,6 @@ static inline void gen_tb_end(TCGContext *tcg_ctx, TranslationBlock *tb, int num tcg_set_insn_param(tcg_ctx->icount_start_insn, 1, num_insns); } - gen_set_label(tcg_ctx, tcg_ctx->exitreq_label); tcg_gen_exit_tb(tcg_ctx, tb, TB_EXIT_REQUESTED); } diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index ade583e4..e3b02c1a 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -672,7 +672,6 @@ struct TCGContext { #endif TCGv_i32 delay_slot_flag; - TCGLabel *exitreq_label; TCGTempSet free_temps[TCG_TYPE_COUNT * 2]; TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ diff --git a/qemu/m68k.h b/qemu/m68k.h index 1b1703d1..c4ac5306 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _m68k #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_m68k #define unicorn_fill_tlb unicorn_fill_tlb_m68k #define reg_read reg_read_m68k #define reg_write reg_write_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 3a005710..dda1a458 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _mips #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_mips #define unicorn_fill_tlb unicorn_fill_tlb_mips #define reg_read reg_read_mips #define reg_write reg_write_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 367c6b7e..62a17d11 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _mips64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_mips64 #define unicorn_fill_tlb unicorn_fill_tlb_mips64 #define reg_read reg_read_mips64 #define reg_write reg_write_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 1c3f8ca2..d30b6765 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _mips64el #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_mips64el #define unicorn_fill_tlb unicorn_fill_tlb_mips64el #define reg_read reg_read_mips64el #define reg_write reg_write_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 511cfcfb..5d1fa4d9 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _mipsel #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_mipsel #define unicorn_fill_tlb unicorn_fill_tlb_mipsel #define reg_read reg_read_mipsel #define reg_write reg_write_mipsel diff --git a/qemu/ppc.h b/qemu/ppc.h index 7fd12291..ee63c633 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _ppc #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_ppc #define unicorn_fill_tlb unicorn_fill_tlb_ppc #define reg_read reg_read_ppc #define reg_write reg_write_ppc diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 9e4d79ed..45c0f577 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _ppc64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_ppc64 #define unicorn_fill_tlb unicorn_fill_tlb_ppc64 #define reg_read reg_read_ppc64 #define reg_write reg_write_ppc64 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 90889da5..f54b1754 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _riscv32 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_riscv32 #define unicorn_fill_tlb unicorn_fill_tlb_riscv32 #define reg_read reg_read_riscv32 #define reg_write reg_write_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 1bb11933..f51aea62 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _riscv64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_riscv64 #define unicorn_fill_tlb unicorn_fill_tlb_riscv64 #define reg_read reg_read_riscv64 #define reg_write reg_write_riscv64 diff --git a/qemu/s390x.h b/qemu/s390x.h index 1906872b..c3c47cc7 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _s390x #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_s390x #define unicorn_fill_tlb unicorn_fill_tlb_s390x #define reg_read reg_read_s390x #define reg_write reg_write_s390x diff --git a/qemu/sparc.h b/qemu/sparc.h index 32be40ab..7883f690 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _sparc #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_sparc #define unicorn_fill_tlb unicorn_fill_tlb_sparc #define reg_read reg_read_sparc #define reg_write reg_write_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index c9f6f2fc..e6ecc941 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _sparc64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_sparc64 #define unicorn_fill_tlb unicorn_fill_tlb_sparc64 #define reg_read reg_read_sparc64 #define reg_write reg_write_sparc64 diff --git a/qemu/tcg/tcg-op.c b/qemu/tcg/tcg-op.c index 8a5865df..d0223ea2 100644 --- a/qemu/tcg/tcg-op.c +++ b/qemu/tcg/tcg-op.c @@ -2852,8 +2852,6 @@ static void gen_ldst_i64(TCGContext *tcg_ctx, TCGOpcode opc, TCGv_i64 val, TCGv // if so, we jump to the block epilogue to quit immediately. void check_exit_request(TCGContext *tcg_ctx) { - TCGv_i32 count; - // Unicorn: // For ARM IT block, we couldn't exit in the middle of the // block and this is the our hack here. @@ -2861,23 +2859,17 @@ void check_exit_request(TCGContext *tcg_ctx) return; } - count = tcg_temp_new_i32(tcg_ctx); - - tcg_gen_ld_i32(tcg_ctx, count, tcg_ctx->cpu_env, - offsetof(ArchCPU, neg.icount_decr.u32) - - offsetof(ArchCPU, env)); + TCGv_ptr puc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); + TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 0); // Unicorn: // We CANT'T use brcondi_i32 here or we will fail liveness analysis // because it marks the end of BB if (tcg_ctx->delay_slot_flag != NULL) { - TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 0); - // dest = (c1 cond c2 ? v1 : v2) - tcg_gen_movcond_i32(tcg_ctx, TCG_COND_GT, count, tcg_ctx->delay_slot_flag, tmp, tcg_ctx->delay_slot_flag, count); - tcg_temp_free_i32(tcg_ctx, tmp); + tcg_gen_mov_i32(tcg_ctx, tmp, tcg_ctx->delay_slot_flag); } - - tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_LT, count, 0, tcg_ctx->exitreq_label); - tcg_temp_free_i32(tcg_ctx, count); + gen_helper_check_exit_request(tcg_ctx, puc, tmp); + tcg_temp_free_i32(tcg_ctx, tmp); + tcg_temp_free_ptr(tcg_ctx, puc); } static void tcg_gen_req_mo(TCGContext *tcg_ctx, TCGBar type) diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index 1c935303..bc62051f 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -2243,17 +2243,6 @@ static inline void la_reset_pref(TCGContext *tcg_ctx, TCGTemp *ts) = (ts->state == TS_DEAD ? 0 : tcg_ctx->tcg_target_available_regs[ts->type]); } -/* - Unicorn: for brcond, we should refresh liveness states for TCG globals -*/ -static void la_brcond_end(TCGContext *s, int ng) -{ - int i; - - for (i = 0; i < ng; i++) { - s->temps[i].state |= TS_MEM; - } -} /* liveness analysis: end of function: all temps are dead, and globals should be in memory. */ @@ -2581,20 +2570,7 @@ static void liveness_pass_1(TCGContext *s) if (def->flags & TCG_OPF_BB_EXIT) { la_func_end(s, nb_globals, nb_temps); } else if (def->flags & TCG_OPF_BB_END) { - // Unicorn: do not optimize dead temps on brcond, - // this causes problem because check_exit_request() inserts - // brcond instruction in the middle of the TB, - // which incorrectly flags end-of-block - if (opc != INDEX_op_brcond_i32) { - la_bb_end(s, nb_globals, nb_temps); - } else { - // Unicorn: we do not touch dead temps for brcond, - // but we should refresh TCG globals In-Memory states, - // otherwise, important CPU states(especially conditional flags) might be forgotten, - // result in wrongly generated host code that run into wrong branch. - // Refer to https://github.com/unicorn-engine/unicorn/issues/287 for further information - la_brcond_end(s, nb_globals); - } + la_bb_end(s, nb_globals, nb_temps); } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { la_global_sync(s, nb_globals); if (def->flags & TCG_OPF_CALL_CLOBBER) { diff --git a/qemu/tricore.h b/qemu/tricore.h index e3788685..83752d37 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _tricore #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_tricore #define unicorn_fill_tlb unicorn_fill_tlb_tricore #define reg_read reg_read_tricore #define reg_write reg_write_tricore diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 0118257e..7aa56416 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -4,6 +4,7 @@ #ifndef UNICORN_ARCH_POSTFIX #define UNICORN_ARCH_POSTFIX _x86_64 #endif +#define gen_helper_check_exit_request gen_helper_check_exit_request_x86_64 #define unicorn_fill_tlb unicorn_fill_tlb_x86_64 #define reg_read reg_read_x86_64 #define reg_write reg_write_x86_64 diff --git a/symbols.sh b/symbols.sh index 11866f93..b70aa6d1 100755 --- a/symbols.sh +++ b/symbols.sh @@ -4,6 +4,7 @@ CMD_PATH=$(realpath $0) SOURCE_DIR=$(dirname ${CMD_PATH}) COMMON_SYMBOLS=" +gen_helper_check_exit_request \ unicorn_fill_tlb \ reg_read \ reg_write \ diff --git a/tests/unit/test_arm64.c b/tests/unit/test_arm64.c index e6e91565..68934832 100644 --- a/tests/unit/test_arm64.c +++ b/tests/unit/test_arm64.c @@ -651,6 +651,24 @@ static void test_arm64_mem_hook_read_write(void) OK(uc_close(uc)); } +static void test_arm64_pc_guarantee(void) +{ + uc_engine *uc; + // ks.asm("mov x0, #1; mov x1, #2; ldr x0, [x1]") + const char code[] = "\x20\x00\x80\xd2\x41\x00\x80\xd2\x20\x00\x40\xf9"; + uint64_t rip; + + uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code), + UC_CPU_ARM64_A72); + + uc_assert_err(UC_ERR_READ_UNMAPPED, uc_emu_start(uc, code_start, + code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_ARM64_REG_PC, (void*)&rip)); + TEST_CHECK(rip == code_start + 8); + 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}, @@ -668,4 +686,5 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until}, {"test_arm64_pc_wrap", test_arm64_pc_wrap}, {"test_arm64_mem_prot_regress", test_arm64_mem_prot_regress}, {"test_arm64_mem_hook_read_write", test_arm64_mem_hook_read_write}, + {"test_arm64_pc_guarantee", test_arm64_pc_guarantee}, {NULL, NULL}}; diff --git a/tests/unit/test_mips.c b/tests/unit/test_mips.c index 11d43156..c53c19c1 100644 --- a/tests/unit/test_mips.c +++ b/tests/unit/test_mips.c @@ -206,7 +206,7 @@ static void test_mips_simple_coredump_2134(void) const char code[] = "\x25\xc8\x80\x03\x25\x78\xe0\x03\x09\xf8\x20\x03\x10\x00\x18\x24"; uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32, code, sizeof(code) - 1); - OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + uc_assert_err(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0), UC_ERR_FETCH_UNMAPPED); OK(uc_close(uc)); } diff --git a/uc.c b/uc.c index 033a26f0..2de9f51e 100644 --- a/uc.c +++ b/uc.c @@ -708,6 +708,7 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) if (setpc) { // force to quit execution and flush TB uc->quit_request = true; + uc->skip_sync_pc_on_exit = true; break_translation_loop(uc); }