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.
This commit is contained in:
@@ -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_*()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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}};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user