From 7633d5fce5315caba5361867127e9375d1c8f29b Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Tue, 29 Apr 2025 14:26:42 +0200 Subject: [PATCH] reorganize stuff --- accel/tcg/cpu-exec.c | 23 +-- accel/tcg/internal-common.h | 1 + accel/tcg/tcg-runtime.c | 18 -- accel/tcg/tcg-runtime.h | 10 -- accel/tcg/translate-all.c | 208 +-------------------- hw/core/cpu-system.c | 19 +- include/exec/cpu-all.h | 4 - include/exec/helper-gen-common.h | 6 + include/exec/helper-proto-common.h | 6 + include/libafl/exit.h | 3 +- include/libafl/tcg-helper.h | 4 + include/libafl/tcg.h | 4 +- include/user/cpu_loop.h | 5 +- include/user/page-protection.h | 4 + libafl/cpu.c | 4 +- libafl/exit.c | 2 - libafl/meson.build | 2 + libafl/tcg-helper.c | 22 +++ libafl/tcg.c | 279 +++++++++++++++++++++++++++++ linux-user/i386/cpu_loop.c | 4 + linux-user/user-internals.h | 1 - 21 files changed, 367 insertions(+), 262 deletions(-) create mode 100644 include/libafl/tcg-helper.h create mode 100644 libafl/tcg-helper.c create mode 100644 libafl/tcg.c diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 95bf5f0199..6403eb1191 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -45,6 +45,15 @@ #include "internal-common.h" #include "internal-target.h" +//// --- Begin LibAFL code --- + +#include "libafl/exit.h" +#include "libafl/tcg.h" +#include "libafl/hooks/tcg/edge.h" + +//// --- End LibAFL code --- + + /* -icount align implementation. */ typedef struct SyncClocks { @@ -702,12 +711,6 @@ static inline void cpu_handle_debug_exception(CPUState *cpu) } } -//// --- Begin LibAFL code --- - -#include "libafl/exit.h" - -//// --- End LibAFL code --- - static inline bool cpu_handle_exception(CPUState *cpu, int *ret) { //// --- Begin LibAFL code --- @@ -958,14 +961,6 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, #endif } -//// --- Begin LibAFL code --- - -TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, - target_ulong dst_block, int exit_n, target_ulong cs_base, - uint32_t flags, int cflags); - -//// --- End LibAFL code --- - /* main execution loop */ static int __attribute__((noinline)) diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 9b6ab3a8cc..c3fa9ab0e0 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -54,6 +54,7 @@ void tb_reset_jump(TranslationBlock *tb, int n); TranslationBlock *tb_link_page(TranslationBlock *tb); void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t host_pc); +int encode_search(TranslationBlock *tb, uint8_t *block); /** * tlb_init - initialize a CPU's TLB diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 5f029d9686..fa7ed9739c 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -31,24 +31,6 @@ #include "exec/helper-info.c.inc" #undef HELPER_H -//// --- Begin LibAFL code --- - -#include "libafl/exit.h" - -void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env, uint64_t pc) -{ - CPUState* cpu = env_cpu(env); - libafl_exit_request_breakpoint(cpu, (target_ulong) pc); -} - -void HELPER(libafl_qemu_handle_custom_insn)(CPUArchState *env, uint64_t pc, uint32_t kind) -{ - CPUState* cpu = env_cpu(env); - libafl_exit_request_custom_insn(cpu, (target_ulong) pc, (enum libafl_custom_insn_kind) kind); -} - -//// --- End LibAFL code --- - /* 32-bit helpers */ int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2) diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 3f154ccf76..c23b5e66c4 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -323,13 +323,3 @@ DEF_HELPER_FLAGS_4(gvec_leus32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) DEF_HELPER_FLAGS_4(gvec_leus64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) - -//// --- Begin LibAFL code --- - -DEF_HELPER_FLAGS_2(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, - void, env, i64) - -DEF_HELPER_FLAGS_3(libafl_qemu_handle_custom_insn, TCG_CALL_NO_RWG, - void, env, i64, i32) - -//// --- End LibAFL code --- diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index ec73612f3c..6274798869 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -132,8 +132,10 @@ static int64_t decode_sleb128(const uint8_t **pp) line. The seed for the first line is { tb->pc, 0..., tb->tc.ptr }. That is, the first column is seeded with the guest pc, the last column with the host pc, and the middle columns with zeros. */ - -static int encode_search(TranslationBlock *tb, uint8_t *block) +/* +static +*/ +int encode_search(TranslationBlock *tb, uint8_t *block) { uint8_t *highwater = tcg_ctx->code_gen_highwater; uint64_t *insn_data = tcg_ctx->gen_insn_data; @@ -299,208 +301,6 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, return tcg_gen_code(tcg_ctx, tb, pc); } - -/* Called with mmap_lock held for user mode emulation. */ -TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, - target_ulong dst_block, int exit_n, - target_ulong cs_base, uint32_t flags, - int cflags) -{ - CPUArchState *env = cpu_env(cpu); - TranslationBlock *tb; - tb_page_addr_t phys_pc; - tcg_insn_unit *gen_code_buf; - int gen_code_size, search_size, max_insns; - int64_t ti; - void *host_pc; - - // edge hooks generation callbacks - // early check if it should be skipped or not - bool no_exec_hook = libafl_qemu_hook_edge_gen(src_block, dst_block); - if (no_exec_hook) { - // no exec hooks to run for edges, not point in generating a TB - return NULL; - } - - target_ulong pc = src_block ^ reverse_bits((target_ulong)exit_n); - - assert_memory_lock(); - qemu_thread_jit_write(); - - // TODO: this (get_page_addr_code_hostp) is a bottleneck in systemmode, investigate why - phys_pc = get_page_addr_code_hostp(env, src_block, &host_pc); - phys_pc ^= reverse_bits((tb_page_addr_t)exit_n); - - // if (phys_pc == -1) { - // /* Generate a one-shot TB with 1 insn in it */ - // cflags = (cflags & ~CF_COUNT_MASK) | 1; - // } - - /* Generate a one-shot TB with max 16 insn in it */ - cflags = (cflags & ~CF_COUNT_MASK) | LIBAFL_MAX_INSNS; - QEMU_BUILD_BUG_ON(LIBAFL_MAX_INSNS > TCG_MAX_INSNS); - - max_insns = cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = TCG_MAX_INSNS; - } - QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); - - buffer_overflow: - assert_no_pages_locked(); - tb = tcg_tb_alloc(tcg_ctx); - if (unlikely(!tb)) { - /* flush must be done */ - tb_flush(cpu); - mmap_unlock(); - /* Make the execution loop process the flush as soon as possible. */ - cpu->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(cpu); - } - - gen_code_buf = tcg_ctx->code_gen_ptr; - tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf); - - if (!(cflags & CF_PCREL)) { - tb->pc = pc; - } - - tb->cs_base = cs_base; - tb->flags = flags; - tb->cflags = cflags | CF_IS_EDGE; - tb_set_page_addr0(tb, phys_pc); - tb_set_page_addr1(tb, -1); - // if (phys_pc != -1) { - // tb_lock_page0(phys_pc); - // } - - tcg_ctx->gen_tb = tb; - tcg_ctx->addr_type = TARGET_LONG_BITS == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; -#ifdef CONFIG_SOFTMMU - tcg_ctx->page_bits = TARGET_PAGE_BITS; - tcg_ctx->page_mask = TARGET_PAGE_MASK; - tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; -#endif - tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; -#ifdef TCG_GUEST_DEFAULT_MO - tcg_ctx->guest_mo = TCG_GUEST_DEFAULT_MO; -#else - tcg_ctx->guest_mo = TCG_MO_ALL; -#endif - - restart_translate: - trace_translate_block(tb, pc, tb->tc.ptr); - - gen_code_size = libafl_setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti); - if (unlikely(gen_code_size < 0)) { - switch (gen_code_size) { - case -1: - /* - * Overflow of code_gen_buffer, or the current slice of it. - * - * TODO: We don't need to re-do gen_intermediate_code, nor - * should we re-do the tcg optimization currently hidden - * inside tcg_gen_code. All that should be required is to - * flush the TBs, allocate a new TB, re-initialize it per - * above, and re-do the actual code generation. - */ - qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, - "Restarting code generation for " - "code_gen_buffer overflow\n"); - tb_unlock_pages(tb); - tcg_ctx->gen_tb = NULL; - goto buffer_overflow; - - case -2: - assert(false && "This should never happen for edge code. There must be a bug."); - /* - * The code generated for the TranslationBlock is too large. - * The maximum size allowed by the unwind info is 64k. - * There may be stricter constraints from relocations - * in the tcg backend. - * - * Try again with half as many insns as we attempted this time. - * If a single insn overflows, there's a bug somewhere... - */ - assert(max_insns > 1); - max_insns /= 2; - qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, - "Restarting code generation with " - "smaller translation block (max %d insns)\n", - max_insns); - - /* - * The half-sized TB may not cross pages. - * TODO: Fix all targets that cross pages except with - * the first insn, at which point this can't be reached. - */ - // phys_p2 = tb_page_addr1(tb); - // if (unlikely(phys_p2 != -1)) { - // tb_unlock_page1(phys_pc, phys_p2); - // tb_set_page_addr1(tb, -1); - // } - goto restart_translate; - - case -3: - /* - * We had a page lock ordering problem. In order to avoid - * deadlock we had to drop the lock on page0, which means - * that everything we translated so far is compromised. - * Restart with locks held on both pages. - */ - qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, - "Restarting code generation with re-locked pages"); - goto restart_translate; - - default: - g_assert_not_reached(); - } - } - tcg_ctx->gen_tb = NULL; - - search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size); - if (unlikely(search_size < 0)) { - tb_unlock_pages(tb); - goto buffer_overflow; - } - tb->tc.size = gen_code_size; - - /* - * For CF_PCREL, attribute all executions of the generated code - * to its first mapping. - */ - perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf)); - - qatomic_set(&tcg_ctx->code_gen_ptr, (void *) - ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size, - CODE_GEN_ALIGN)); - - /* init jump list */ - qemu_spin_init(&tb->jmp_lock); - tb->jmp_list_head = (uintptr_t)NULL; - tb->jmp_list_next[0] = (uintptr_t)NULL; - tb->jmp_list_next[1] = (uintptr_t)NULL; - tb->jmp_dest[0] = (uintptr_t)NULL; - tb->jmp_dest[1] = (uintptr_t)NULL; - - /* init original jump addresses which have been set during tcg_gen_code() */ - if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { - tb_reset_jump(tb, 0); - } - if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { - tb_reset_jump(tb, 1); - } - - assert_no_pages_locked(); - -#ifndef CONFIG_USER_ONLY - tb->page_addr[0] = tb->page_addr[1] = -1; -#endif - return tb; -} - -//// --- End LibAFL code --- - /* Called with mmap_lock held for user mode emulation. */ TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, uint64_t cs_base, diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index aed5076ec7..b0333dc2c5 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -31,6 +31,14 @@ #include "migration/vmstate.h" #include "system/tcg.h" +//// --- Begin LibAFL code --- + +#ifndef CONFIG_USER_ONLY +#include "libafl/syx-snapshot/device-save.h" +#endif + +//// --- End LibAFL code --- + bool cpu_has_work(CPUState *cpu) { return cpu->cc->sysemu_ops->has_work(cpu); @@ -214,7 +222,16 @@ static int cpu_common_post_load(void *opaque, int version_id) * memory we've translated code from. So we must flush all TBs, * which will now be stale. */ - tb_flush(cpu); + //tb_flush(cpu); + //// --- Begin LibAFL code --- + + // flushing the TBs every restore makes it really slow + // TODO handle writes to X code with specific calls to tb_invalidate_phys_addr + if (!libafl_devices_is_restoring()) { + tb_flush(cpu); + } + + //// --- End LibAFL code --- } return 0; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index a1430528ec..5de58da40e 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -100,10 +100,6 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val #include "exec/cpu-defs.h" #include "exec/target_page.h" -//// --- Begin LibAFL code --- -IntervalTreeRoot* pageflags_get_root(void); -//// --- End LibAFL code --- - CPUArchState *cpu_copy(CPUArchState *env); #include "cpu.h" diff --git a/include/exec/helper-gen-common.h b/include/exec/helper-gen-common.h index 834590dc4e..a6fa47c20b 100644 --- a/include/exec/helper-gen-common.h +++ b/include/exec/helper-gen-common.h @@ -11,4 +11,10 @@ #include "exec/helper-gen.h.inc" #undef HELPER_H +//// --- Begin LibAFL code --- +#define HELPER_H "libafl/tcg-helper.h" +#include "exec/helper-gen.h.inc" +#undef HELPER_H +//// --- End LibAFL code --- + #endif /* HELPER_GEN_COMMON_H */ diff --git a/include/exec/helper-proto-common.h b/include/exec/helper-proto-common.h index 16782ef46c..959771ac29 100644 --- a/include/exec/helper-proto-common.h +++ b/include/exec/helper-proto-common.h @@ -13,4 +13,10 @@ #include "exec/helper-proto.h.inc" #undef HELPER_H +//// --- Begin LibAFL code --- +#define HELPER_H "libafl/tcg-helper.h" +#include "exec/helper-proto.h.inc" +#undef HELPER_H +//// --- End LibAFL code --- + #endif /* HELPER_PROTO_COMMON_H */ diff --git a/include/libafl/exit.h b/include/libafl/exit.h index b5716f1d41..5af1be547b 100644 --- a/include/libafl/exit.h +++ b/include/libafl/exit.h @@ -1,7 +1,8 @@ #pragma once #include "qemu/osdep.h" -#include "exec/cpu-defs.h" +#include "exec/cpu_ldst.h" +#include "hw/core/cpu.h" #define EXCP_LIBAFL_EXIT 0xf4775747 diff --git a/include/libafl/tcg-helper.h b/include/libafl/tcg-helper.h new file mode 100644 index 0000000000..050356a460 --- /dev/null +++ b/include/libafl/tcg-helper.h @@ -0,0 +1,4 @@ +DEF_HELPER_FLAGS_2(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, + void, env, i64) +DEF_HELPER_FLAGS_3(libafl_qemu_handle_custom_insn, TCG_CALL_NO_RWG, + void, env, i64, i32) diff --git a/include/libafl/tcg.h b/include/libafl/tcg.h index 2320fb2f93..372419c1a7 100644 --- a/include/libafl/tcg.h +++ b/include/libafl/tcg.h @@ -1,10 +1,8 @@ #pragma once #include "qemu/osdep.h" -#include "qapi/error.h" - #include "tcg/tcg.h" -#include "tcg/helper-info.h" void tcg_gen_callN(void* func, TCGHelperInfo* info, TCGTemp* ret, TCGTemp** args); + diff --git a/include/user/cpu_loop.h b/include/user/cpu_loop.h index 589c66543f..1ef11f720c 100644 --- a/include/user/cpu_loop.h +++ b/include/user/cpu_loop.h @@ -77,7 +77,10 @@ G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, MMUAccessType access_type, uintptr_t ra); -G_NORETURN void cpu_loop(CPUArchState *env); +//// --- Begin LibAFL code --- +/* G_NORETURN */ +//// --- End LibAFL code --- +void cpu_loop(CPUArchState *env); void target_exception_dump(CPUArchState *env, const char *fmt, int code); #define EXCP_DUMP(env, fmt, code) \ diff --git a/include/user/page-protection.h b/include/user/page-protection.h index 51daa18648..6f7902fc80 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -96,4 +96,8 @@ int walk_memory_regions(void *, walk_memory_regions_fn); void page_dump(FILE *f); +//// --- Begin LibAFL code --- +IntervalTreeRoot* pageflags_get_root(void); +//// --- End LibAFL code --- + #endif diff --git a/libafl/cpu.c b/libafl/cpu.c index 36e748e70b..409fcb3aab 100644 --- a/libafl/cpu.c +++ b/libafl/cpu.c @@ -2,18 +2,16 @@ #ifdef CONFIG_USER_ONLY #include "qemu.h" -#include "user-internals.h" +#include "user/cpu_loop.h" #endif #include "exec/gdbstub.h" -#include "exec/cpu-defs.h" #include "exec/tb-flush.h" #include "exec/exec-all.h" #include "hw/core/sysemu-cpu-ops.h" #include "libafl/cpu.h" -#include "libafl/exit.h" #include "libafl/hook.h" int gdb_write_register(CPUState* cpu, uint8_t* mem_buf, int reg); diff --git a/libafl/exit.c b/libafl/exit.c index 92190eef4b..2a6efeaf6d 100644 --- a/libafl/exit.c +++ b/libafl/exit.c @@ -2,8 +2,6 @@ #include "tcg/tcg.h" #include "tcg/tcg-op.h" -#include "tcg/tcg-temp-internal.h" -#include "sysemu/runstate.h" #include "cpu.h" #include "libafl/cpu.h" diff --git a/libafl/meson.build b/libafl/meson.build index b6d1dc52e0..8eb288257f 100644 --- a/libafl/meson.build +++ b/libafl/meson.build @@ -5,6 +5,8 @@ specific_ss.add(files( 'jit.c', 'utils.c', 'gdb.c', + 'tcg.c', + 'tcg-helper.c', # TCG-related hooks 'hooks/tcg/backdoor.c', diff --git a/libafl/tcg-helper.c b/libafl/tcg-helper.c new file mode 100644 index 0000000000..48e522403b --- /dev/null +++ b/libafl/tcg-helper.c @@ -0,0 +1,22 @@ +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "exec/cpu-common.h" +#include "exec/helper-proto-common.h" + +#include "libafl/exit.h" + +#define HELPER_H "libafl/tcg-helper.h" +#include "exec/helper-info.c.inc" +#undef HELPER_H + +void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env, uint64_t pc) +{ + CPUState* cpu = env_cpu(env); + libafl_exit_request_breakpoint(cpu, (target_ulong) pc); +} + +void HELPER(libafl_qemu_handle_custom_insn)(CPUArchState *env, uint64_t pc, uint32_t kind) +{ + CPUState* cpu = env_cpu(env); + libafl_exit_request_custom_insn(cpu, (target_ulong) pc, (enum libafl_custom_insn_kind) kind); +} diff --git a/libafl/tcg.c b/libafl/tcg.c new file mode 100644 index 0000000000..a8ac8aaa25 --- /dev/null +++ b/libafl/tcg.c @@ -0,0 +1,279 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" + +#include "exec/cpu-common.h" + +#include "accel/tcg/internal-common.h" +#include "accel/tcg/internal-target.h" +#include "accel/tcg/trace.h" + +#include "tcg/insn-start-words.h" +#include "tcg/perf.h" + +#include "libafl/tcg.h" +#include "libafl/hooks/tcg/edge.h" + +static target_ulong reverse_bits(target_ulong num) +{ + unsigned int count = sizeof(num) * 8 - 1; + target_ulong reverse_num = num; + + num >>= 1; + while(num) + { + reverse_num <<= 1; + reverse_num |= num & 1; + num >>= 1; + count--; + } + reverse_num <<= count; + return reverse_num; +} + +/* + * Isolate the portion of code gen which can setjmp/longjmp. + * Return the size of the generated code, or negative on error. + */ +static int libafl_setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, + vaddr pc, void *host_pc, + int *max_insns, int64_t *ti) +{ + int ret = sigsetjmp(tcg_ctx->jmp_trans, 0); + if (unlikely(ret != 0)) { + return ret; + } + + tcg_func_start(tcg_ctx); + + tcg_ctx->cpu = env_cpu(env); + + // -- start gen_intermediate_code + const int num_insns = 1; // do "as-if" we were translating a single target instruction + +#ifndef TARGET_INSN_START_EXTRA_WORDS + tcg_gen_insn_start(pc); +#elif TARGET_INSN_START_EXTRA_WORDS == 1 + tcg_gen_insn_start(pc, 0); +#elif TARGET_INSN_START_EXTRA_WORDS == 2 + tcg_gen_insn_start(pc, 0, 0); +#else +#error Unhandled TARGET_INSN_START_EXTRA_WORDS value +#endif + + // run edge hooks + libafl_qemu_hook_edge_run(); + + tcg_gen_goto_tb(0); + tcg_gen_exit_tb(tb, 0); + + // This is obviously wrong, but it is required that the number / size of target instruction translated + // is at least 1. For now, we make it so that no problem occurs later on. + tb->icount = num_insns; // number of target instructions translated in the TB. + tb->size = num_insns; // size (in target bytes) of target instructions translated in the TB. + // -- end gen_intermediate_code + + assert(tb->size != 0); + tcg_ctx->cpu = NULL; + *max_insns = tb->icount; + + return tcg_gen_code(tcg_ctx, tb, pc); +} + +/* Called with mmap_lock held for user mode emulation. */ +TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, + target_ulong dst_block, int exit_n, + target_ulong cs_base, uint32_t flags, + int cflags) +{ + CPUArchState *env = cpu_env(cpu); + TranslationBlock *tb; + tb_page_addr_t phys_pc; + tcg_insn_unit *gen_code_buf; + int gen_code_size, search_size, max_insns; + int64_t ti; + void *host_pc; + + // edge hooks generation callbacks + // early check if it should be skipped or not + bool no_exec_hook = libafl_qemu_hook_edge_gen(src_block, dst_block); + if (no_exec_hook) { + // no exec hooks to run for edges, not point in generating a TB + return NULL; + } + + target_ulong pc = src_block ^ reverse_bits((target_ulong)exit_n); + + assert_memory_lock(); + qemu_thread_jit_write(); + + // TODO: this (get_page_addr_code_hostp) is a bottleneck in systemmode, investigate why + phys_pc = get_page_addr_code_hostp(env, src_block, &host_pc); + phys_pc ^= reverse_bits((tb_page_addr_t)exit_n); + + // if (phys_pc == -1) { + // /* Generate a one-shot TB with 1 insn in it */ + // cflags = (cflags & ~CF_COUNT_MASK) | 1; + // } + + /* Generate a one-shot TB with max 16 insn in it */ + cflags = (cflags & ~CF_COUNT_MASK) | LIBAFL_MAX_INSNS; + QEMU_BUILD_BUG_ON(LIBAFL_MAX_INSNS > TCG_MAX_INSNS); + + max_insns = cflags & CF_COUNT_MASK; + if (max_insns == 0) { + max_insns = TCG_MAX_INSNS; + } + QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); + + buffer_overflow: + assert_no_pages_locked(); + tb = tcg_tb_alloc(tcg_ctx); + if (unlikely(!tb)) { + /* flush must be done */ + tb_flush(cpu); + mmap_unlock(); + /* Make the execution loop process the flush as soon as possible. */ + cpu->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(cpu); + } + + gen_code_buf = tcg_ctx->code_gen_ptr; + tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf); + + if (!(cflags & CF_PCREL)) { + tb->pc = pc; + } + + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags | CF_IS_EDGE; + tb_set_page_addr0(tb, phys_pc); + tb_set_page_addr1(tb, -1); + // if (phys_pc != -1) { + // tb_lock_page0(phys_pc); + // } + + tcg_ctx->gen_tb = tb; + tcg_ctx->addr_type = TARGET_LONG_BITS == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; +#ifdef CONFIG_SOFTMMU + tcg_ctx->page_bits = TARGET_PAGE_BITS; + tcg_ctx->page_mask = TARGET_PAGE_MASK; + tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; +#endif + tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; +#ifdef TCG_GUEST_DEFAULT_MO + tcg_ctx->guest_mo = TCG_GUEST_DEFAULT_MO; +#else + tcg_ctx->guest_mo = TCG_MO_ALL; +#endif + + restart_translate: + trace_translate_block(tb, pc, tb->tc.ptr); + + gen_code_size = libafl_setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti); + if (unlikely(gen_code_size < 0)) { + switch (gen_code_size) { + case -1: + /* + * Overflow of code_gen_buffer, or the current slice of it. + * + * TODO: We don't need to re-do gen_intermediate_code, nor + * should we re-do the tcg optimization currently hidden + * inside tcg_gen_code. All that should be required is to + * flush the TBs, allocate a new TB, re-initialize it per + * above, and re-do the actual code generation. + */ + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation for " + "code_gen_buffer overflow\n"); + tb_unlock_pages(tb); + tcg_ctx->gen_tb = NULL; + goto buffer_overflow; + + case -2: + assert(false && "This should never happen for edge code. There must be a bug."); + /* + * The code generated for the TranslationBlock is too large. + * The maximum size allowed by the unwind info is 64k. + * There may be stricter constraints from relocations + * in the tcg backend. + * + * Try again with half as many insns as we attempted this time. + * If a single insn overflows, there's a bug somewhere... + */ + assert(max_insns > 1); + max_insns /= 2; + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation with " + "smaller translation block (max %d insns)\n", + max_insns); + + /* + * The half-sized TB may not cross pages. + * TODO: Fix all targets that cross pages except with + * the first insn, at which point this can't be reached. + */ + // phys_p2 = tb_page_addr1(tb); + // if (unlikely(phys_p2 != -1)) { + // tb_unlock_page1(phys_pc, phys_p2); + // tb_set_page_addr1(tb, -1); + // } + goto restart_translate; + + case -3: + /* + * We had a page lock ordering problem. In order to avoid + * deadlock we had to drop the lock on page0, which means + * that everything we translated so far is compromised. + * Restart with locks held on both pages. + */ + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation with re-locked pages"); + goto restart_translate; + + default: + g_assert_not_reached(); + } + } + tcg_ctx->gen_tb = NULL; + + search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size); + if (unlikely(search_size < 0)) { + tb_unlock_pages(tb); + goto buffer_overflow; + } + tb->tc.size = gen_code_size; + + /* + * For CF_PCREL, attribute all executions of the generated code + * to its first mapping. + */ + perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf)); + + qatomic_set(&tcg_ctx->code_gen_ptr, (void *) + ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size, + CODE_GEN_ALIGN)); + + /* init jump list */ + qemu_spin_init(&tb->jmp_lock); + tb->jmp_list_head = (uintptr_t)NULL; + tb->jmp_list_next[0] = (uintptr_t)NULL; + tb->jmp_list_next[1] = (uintptr_t)NULL; + tb->jmp_dest[0] = (uintptr_t)NULL; + tb->jmp_dest[1] = (uintptr_t)NULL; + + /* init original jump addresses which have been set during tcg_gen_code() */ + if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { + tb_reset_jump(tb, 0); + } + if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { + tb_reset_jump(tb, 1); + } + + assert_no_pages_locked(); + +#ifndef CONFIG_USER_ONLY + tb->page_addr[0] = tb->page_addr[1] = -1; +#endif + return tb; +} diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 0008780d19..afca47ab34 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -25,6 +25,10 @@ #include "signal-common.h" #include "user-mmap.h" +//// --- Begin LibAFL code --- +#include "libafl/exit.h" +//// --- End LibAFL code --- + /***********************************************************/ /* CPUX86 core interface */ diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 02a6edb0c4..4aa253b566 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -64,7 +64,6 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8); extern __thread CPUState *thread_cpu; -/* G_NORETURN */ void cpu_loop(CPUArchState *env); abi_long get_errno(abi_long ret); const char *target_strerror(int err); int get_osversion(void);