From 78903838510802ec4209b932ee8044e24b79702e Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Mon, 11 Jul 2022 14:54:58 -0700 Subject: [PATCH 1/6] Do not run tbs that request an exit --- qemu/accel/tcg/cpu-exec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index 471ddc9484..688cc98c32 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -595,6 +595,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 */ From a2a5db9334f7034644d9a7240a69c3015e2e7791 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Mon, 11 Jul 2022 14:57:11 -0700 Subject: [PATCH 2/6] Do not only lift blocks with only 1 insn just because there is no phys page --- qemu/accel/tcg/translate-all.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 232a91780f..91dd5ce769 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; From 4a8af17971af5ab3d62a139243ccb328c2359074 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Wed, 13 Jul 2022 15:58:09 -0700 Subject: [PATCH 3/6] Do not call write callback twice for same address in same write --- qemu/accel/tcg/cputlb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 62233bc092..8de7f48d36 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 @@ -2136,6 +2136,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 +2179,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 +2192,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; } From 33c488b3d27f4c5056ed6a9c1ec5f8b82f55f3d6 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Thu, 14 Jul 2022 08:10:41 -0700 Subject: [PATCH 4/6] Add test case for unaligned write callbacks --- tests/unit/test_x86.c | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 04d4c76f7d..d6cb2132a3 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1106,6 +1106,60 @@ static void test_x86_correct_address_in_long_jump_hook(void) OK(uc_close(uc)); } +struct writelog_t { + uint32_t addr, size; +}; + +static void test_x86_unaligned_write_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_write(void) +{ + uc_engine *uc; + uc_hook hook; + char code[] = "\xa3\x01\x00\x20\x00"; // mov dword ptr [0x200001], eax + uint32_t r_eax = 0x41424344; + struct writelog_t write_log[10]; + memset(write_log, 0, sizeof(write_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_write_callback, + write_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); + + 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)); +} + TEST_LIST = { {"test_x86_in", test_x86_in}, {"test_x86_out", test_x86_out}, @@ -1143,4 +1197,5 @@ 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_unaligned_write", test_x86_unaligned_write}, {NULL, NULL}}; From d9d91df3208fdbf4354c11b1a9b65c0e609b3858 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Tue, 2 Aug 2022 13:22:59 -0700 Subject: [PATCH 5/6] Add testcase for blocks being lifted on jump into unmapped mem --- tests/unit/test_x86.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index d6cb2132a3..81e413c682 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1160,6 +1160,36 @@ static void test_x86_unaligned_write(void) OK(uc_close(uc)); } +static void 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)); +} + +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; + char code[] = "\x90\x90"; // nop; nop + 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, &mem_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}, @@ -1198,4 +1228,5 @@ TEST_LIST = { {"test_x86_correct_address_in_long_jump_hook", test_x86_correct_address_in_long_jump_hook}, {"test_x86_unaligned_write", test_x86_unaligned_write}, + {"test_x86_lazy_mapping", test_x86_lazy_mapping}, {NULL, NULL}}; From b459b42a27d01c6d0cb89ece0a93581c3d4acefa Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Tue, 2 Aug 2022 13:48:21 -0700 Subject: [PATCH 6/6] Make unaligned reads not trigger recursive callbacks - add test - linting for previous commit --- qemu/accel/tcg/cputlb.c | 4 ++++ tests/unit/test_x86.c | 24 ++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 8de7f48d36..255e4c4131 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -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)) { diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 81e413c682..dad1205015 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1110,7 +1110,7 @@ struct writelog_t { uint32_t addr, size; }; -static void test_x86_unaligned_write_callback(uc_engine *uc, uc_mem_type type, +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); @@ -1126,19 +1126,24 @@ static void test_x86_unaligned_write_callback(uc_engine *uc, uc_mem_type type, TEST_ASSERT(false); } -static void test_x86_unaligned_write(void) +static void test_x86_unaligned_access(void) { uc_engine *uc; uc_hook hook; - char code[] = "\xa3\x01\x00\x20\x00"; // mov dword ptr [0x200001], eax + // 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_write_callback, + 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)); @@ -1147,6 +1152,10 @@ static void test_x86_unaligned_write(void) 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); @@ -1164,7 +1173,7 @@ static void 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)); + OK(uc_mem_write(uc, 0x1000, "\x90\x90", 2)); // nop; nop } static void test_x86_lazy_mapping_block_callback(uc_engine *uc, @@ -1178,12 +1187,11 @@ static void test_x86_lazy_mapping(void) { uc_engine *uc; uc_hook mem_hook, block_hook; - char code[] = "\x90\x90"; // nop; nop 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, &mem_hook, UC_HOOK_BLOCK, test_x86_lazy_mapping_block_callback, &block_count, 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); @@ -1227,6 +1235,6 @@ 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_unaligned_write", test_x86_unaligned_write}, + {"test_x86_unaligned_access", test_x86_unaligned_access}, {"test_x86_lazy_mapping", test_x86_lazy_mapping}, {NULL, NULL}};