From a6fb2a68702191cbc1c08754397ca1a3f4170f80 Mon Sep 17 00:00:00 2001 From: lazymio Date: Tue, 13 Feb 2024 11:13:01 +0800 Subject: [PATCH] Save jit state before/after callback --- qemu/accel/tcg/cpu-exec.c | 7 +++--- qemu/accel/tcg/cputlb.c | 32 ++++++++++++++++++--------- qemu/accel/tcg/translate-all.c | 3 +++ qemu/include/tcg/tcg-apple-jit.h | 35 +++++++++++++++++++++++++++++ qemu/softmmu/ioport.c | 38 +++++++++++++++++++++----------- qemu/softmmu/unicorn_vtlb.c | 3 ++- qemu/target/arm/op_helper.c | 5 ++++- qemu/target/i386/misc_helper.c | 7 ++++-- qemu/target/i386/seg_helper.c | 14 ++++++++---- uc.c | 12 +++++----- 10 files changed, 115 insertions(+), 41 deletions(-) diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index f6a1c307..ed7be038 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -274,7 +274,7 @@ static inline TranslationBlock *tb_find(CPUState *cpu, } if (HOOK_BOUND_CHECK(hook, (uint64_t)tb->pc)) { - ((uc_hook_edge_gen_t)hook->callback)(uc, &cur_tb, &prev_tb, hook->user_data); + JIT_CALLBACK_GUARD(((uc_hook_edge_gen_t)hook->callback)(uc, &cur_tb, &prev_tb, hook->user_data)); } } } @@ -334,6 +334,7 @@ static inline void cpu_handle_debug_exception(CPUState *cpu) static inline bool cpu_handle_exception(CPUState *cpu, int *ret) { bool catched = false; + bool executable = false; struct uc_struct *uc = cpu->uc; struct hook *hook; @@ -347,7 +348,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) if (hook->to_delete) { continue; } - catched = ((uc_cb_hookinsn_invalid_t)hook->callback)(uc, hook->user_data); + JIT_CALLBACK_GUARD_VAR(catched, ((uc_cb_hookinsn_invalid_t)hook->callback)(uc, hook->user_data)); if (catched) { break; } @@ -401,7 +402,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) if (hook->to_delete) { continue; } - ((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data); + JIT_CALLBACK_GUARD(((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data)); catched = true; } // Unicorn: If un-catched interrupt, stop executions. diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 871ccca2..41ae6b07 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1475,7 +1475,9 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, paddr, size, 0, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, paddr, size, 0, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation @@ -1490,7 +1492,9 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, paddr, size, 0, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, paddr, size, 0, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation @@ -1551,7 +1555,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, paddr, size, 0, hook->user_data); + JIT_CALLBACK_GUARD(((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, paddr, size, 0, hook->user_data)); // the last callback may already asked to stop emulation if (uc->stop_request) @@ -1566,7 +1570,9 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, paddr, size, 0, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, paddr, size, 0, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation @@ -1610,7 +1616,9 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, paddr, size, 0, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, paddr, size, 0, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation @@ -1718,8 +1726,7 @@ _out: continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ_AFTER, paddr, size, res, hook->user_data); - + JIT_CALLBACK_GUARD(((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ_AFTER, paddr, size, res, hook->user_data)); // the last callback may already asked to stop emulation if (uc->stop_request) break; @@ -2062,8 +2069,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - ((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, paddr, size, val, hook->user_data); - + JIT_CALLBACK_GUARD(((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, paddr, size, val, hook->user_data)); // the last callback may already asked to stop emulation if (uc->stop_request) break; @@ -2078,7 +2084,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, paddr, size, val, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, paddr, size, val, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation @@ -2125,7 +2133,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, paddr, size, val, hook->user_data))) + JIT_CALLBACK_GUARD_VAR(handled, + ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, paddr, size, val, hook->user_data)); + if (handled) break; // the last callback may already asked to stop emulation diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 4320d494..f527628c 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -2183,6 +2183,9 @@ static void tb_exec_change(struct uc_struct *uc, bool executable) if (uc->current_executable != executable) { jit_write_protect(executable); uc->current_executable = executable; + assert( + executable == thread_executable() + ); } } #else /* not needed on non-Darwin platforms */ diff --git a/qemu/include/tcg/tcg-apple-jit.h b/qemu/include/tcg/tcg-apple-jit.h index d86ae67a..b8ea1b6a 100644 --- a/qemu/include/tcg/tcg-apple-jit.h +++ b/qemu/include/tcg/tcg-apple-jit.h @@ -63,6 +63,28 @@ __attribute__((unused)) static bool thread_executable() return thread_mask() == 1; } +#define JIT_CALLBACK_GUARD(x) \ +{ \ + bool executable = uc->current_executable; \ + assert (executable == thread_executable()); \ + x; \ + if (executable != thread_executable()) { \ + jit_write_protect(executable); \ + } \ +} \ + + +#define JIT_CALLBACK_GUARD_VAR(var, x) \ +{ \ + bool executable = uc->current_executable; \ + assert (executable == thread_executable()); \ + var = x; \ + if (executable != thread_executable()) { \ + jit_write_protect(executable); \ + } \ +} \ + + #else /* defined(__aarch64__) && defined(CONFIG_DARWIN) */ static inline void jit_write_protect(int enabled) @@ -70,6 +92,19 @@ static inline void jit_write_protect(int enabled) return; } +#define JIT_CALLBACK_GUARD(x) \ +{ \ + (void*)uc; \ + x; \ +} \ + + +#define JIT_CALLBACK_GUARD_VAR(var, x) \ +{ \ + (void*)uc; \ + var = x; \ +} \ + #endif #endif /* define TCG_APPLE_JIT_H */ \ No newline at end of file diff --git a/qemu/softmmu/ioport.c b/qemu/softmmu/ioport.c index 64e1a2e5..d8721b53 100644 --- a/qemu/softmmu/ioport.c +++ b/qemu/softmmu/ioport.c @@ -29,7 +29,7 @@ #include "cpu.h" #include "exec/memory.h" #include "uc_priv.h" - +#include "tcg/tcg-apple-jit.h" void cpu_outb(struct uc_struct *uc, uint32_t addr, uint8_t val) { @@ -43,8 +43,9 @@ void cpu_outb(struct uc_struct *uc, uint32_t addr, uint8_t val) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_OUT) - ((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data); + if (hook->insn == UC_X86_INS_OUT) { + JIT_CALLBACK_GUARD(((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data)); + } } } @@ -63,8 +64,9 @@ void cpu_outw(struct uc_struct *uc, uint32_t addr, uint16_t val) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_OUT) - ((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data); + if (hook->insn == UC_X86_INS_OUT) { + JIT_CALLBACK_GUARD(((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data)); + } } } @@ -83,8 +85,9 @@ void cpu_outl(struct uc_struct *uc, uint32_t addr, uint32_t val) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_OUT) - ((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data); + if (hook->insn == UC_X86_INS_OUT) { + JIT_CALLBACK_GUARD(((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data)); + } } } @@ -102,8 +105,11 @@ uint8_t cpu_inb(struct uc_struct *uc, uint32_t addr) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_IN) - return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data); + if (hook->insn == UC_X86_INS_IN) { + uint8_t ret; + JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data)); + return ret; + } } return 0; @@ -124,8 +130,11 @@ uint16_t cpu_inw(struct uc_struct *uc, uint32_t addr) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_IN) - return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data); + if (hook->insn == UC_X86_INS_IN) { + uint16_t ret; + JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data)); + return ret; + } } return 0; @@ -148,8 +157,11 @@ uint32_t cpu_inl(struct uc_struct *uc, uint32_t addr) HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; - if (hook->insn == UC_X86_INS_IN) - return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data); + if (hook->insn == UC_X86_INS_IN) { + uint32_t ret; + JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data)); + return ret; + } } return 0; diff --git a/qemu/softmmu/unicorn_vtlb.c b/qemu/softmmu/unicorn_vtlb.c index a9634737..8b4e9e0b 100644 --- a/qemu/softmmu/unicorn_vtlb.c +++ b/qemu/softmmu/unicorn_vtlb.c @@ -63,7 +63,8 @@ bool unicorn_fill_tlb(CPUState *cs, vaddr address, int size, continue; } handled = true; - if ((ret = ((uc_cb_tlbevent_t)hook->callback)(uc, address & TARGET_PAGE_MASK, rw_to_mem_type(rw), &e, hook->user_data))) { + JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_tlbevent_t)hook->callback)(uc, address & TARGET_PAGE_MASK, rw_to_mem_type(rw), &e, hook->user_data)); + if (ret) { break; } } diff --git a/qemu/target/arm/op_helper.c b/qemu/target/arm/op_helper.c index 69eac122..813133ae 100644 --- a/qemu/target/arm/op_helper.c +++ b/qemu/target/arm/op_helper.c @@ -939,6 +939,7 @@ uint32_t HELPER(uc_hooksys64)(CPUARMState *env, uint32_t insn, void *hk) struct hook *hook = (struct hook*)hk; uc_arm64_cp_reg cp_reg; uint32_t rt; + uc_engine *uc = env->uc; if (hook->to_delete) { return 0; @@ -965,5 +966,7 @@ uint32_t HELPER(uc_hooksys64)(CPUARMState *env, uint32_t insn, void *hk) cp_reg.val = 0; } - return ((uc_cb_insn_sys_t)(hook->callback))(env->uc, uc_rt, &cp_reg, hook->user_data); + uint32_t ret; + JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_insn_sys_t)(hook->callback))(env->uc, uc_rt, &cp_reg, hook->user_data)); + return ret; } \ No newline at end of file diff --git a/qemu/target/i386/misc_helper.c b/qemu/target/i386/misc_helper.c index f04f0237..25933212 100644 --- a/qemu/target/i386/misc_helper.c +++ b/qemu/target/i386/misc_helper.c @@ -25,6 +25,7 @@ #include "exec/ioport.h" #include "uc_priv.h" +#include "tcg/tcg-apple-jit.h" void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) { @@ -105,6 +106,7 @@ void helper_into(CPUX86State *env, int next_eip_addend) void helper_cpuid(CPUX86State *env) { uint32_t eax, ebx, ecx, edx; + uc_engine *uc = env->uc; struct hook *hook; int skip_cpuid = 0; @@ -120,8 +122,9 @@ void helper_cpuid(CPUX86State *env) // Multiple cpuid callbacks returning different values is undefined. // true -> skip the cpuid instruction - if (hook->insn == UC_X86_INS_CPUID) - skip_cpuid = ((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data); + if (hook->insn == UC_X86_INS_CPUID) { + JIT_CALLBACK_GUARD_VAR(skip_cpuid, ((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data)); + } // the last callback may already asked to stop emulation if (env->uc->stop_request) diff --git a/qemu/target/i386/seg_helper.c b/qemu/target/i386/seg_helper.c index 27efae9a..82726652 100644 --- a/qemu/target/i386/seg_helper.c +++ b/qemu/target/i386/seg_helper.c @@ -973,14 +973,17 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) { // Unicorn: call registered syscall hooks struct hook *hook; + uc_engine *uc = env->uc; + HOOK_FOREACH_VAR_DECLARE; HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; if (!HOOK_BOUND_CHECK(hook, env->eip)) continue; - if (hook->insn == UC_X86_INS_SYSCALL) - ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); + if (hook->insn == UC_X86_INS_SYSCALL) { + JIT_CALLBACK_GUARD(((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data)); + } // the last callback may already asked to stop emulation if (env->uc->stop_request) @@ -2348,14 +2351,17 @@ void helper_sysenter(CPUX86State *env, int next_eip_addend) { // Unicorn: call registered SYSENTER hooks struct hook *hook; + uc_engine *uc = env->uc; + HOOK_FOREACH_VAR_DECLARE; HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { if (hook->to_delete) continue; if (!HOOK_BOUND_CHECK(hook, env->eip)) continue; - if (hook->insn == UC_X86_INS_SYSENTER) - ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); + if (hook->insn == UC_X86_INS_SYSENTER) { + JIT_CALLBACK_GUARD(((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data)); + } // the last callback may already asked to stop emulation if (env->uc->stop_request) diff --git a/uc.c b/uc.c index e27d601d..4604f004 100644 --- a/uc.c +++ b/uc.c @@ -1957,8 +1957,8 @@ void helper_uc_traceopcode(struct hook *hook, uint64_t arg1, uint64_t arg2, // hold in most cases for uc_tracecode. // // TODO: Shall we have a flag to allow users to control whether updating PC? - ((uc_hook_tcg_op_2)hook->callback)(uc, address, arg1, arg2, size, - hook->user_data); + JIT_CALLBACK_GUARD(((uc_hook_tcg_op_2)hook->callback)( + uc, address, arg1, arg2, size, hook->user_data)); if (unlikely(uc->stop_request)) { return; @@ -2002,16 +2002,16 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, if (size == 0) { if (index == UC_HOOK_CODE_IDX && uc->count_hook) { // this is the instruction counter (first hook in the list) - ((uc_cb_hookcode_t)hook->callback)(uc, address, size, - hook->user_data); + JIT_CALLBACK_GUARD(((uc_cb_hookcode_t)hook->callback)( + uc, address, size, hook->user_data)); } return; } if (HOOK_BOUND_CHECK(hook, (uint64_t)address)) { - ((uc_cb_hookcode_t)hook->callback)(uc, address, size, - hook->user_data); + JIT_CALLBACK_GUARD(((uc_cb_hookcode_t)hook->callback)( + uc, address, size, hook->user_data)); } // the last callback may already asked to stop emulation