diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index e5c0ccd1a2..68211f9948 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -851,6 +851,14 @@ 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, target_ulong cs_base, + uint32_t flags, int cflags); + +//// --- End LibAFL code --- + /* main execution loop */ int cpu_exec(CPUState *cpu) @@ -964,7 +972,27 @@ int cpu_exec(CPUState *cpu) #endif /* See if we can patch the calling TB. */ if (last_tb) { - tb_add_jump(last_tb, tb_exit, tb); + // tb_add_jump(last_tb, tb_exit, tb); + + //// --- Begin LibAFL code --- + + if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) { + mmap_lock(); + TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc, + cs_base, flags, cflags); + mmap_unlock(); + + if (edge) { + tb_add_jump(last_tb, tb_exit, edge); + tb_add_jump(edge, 0, tb); + } else { + tb_add_jump(last_tb, tb_exit, tb); + } + } else { + tb_add_jump(last_tb, tb_exit, tb); + } + + //// --- End LibAFL code --- } cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index bbfcfb698c..3b5994b56a 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -61,6 +61,375 @@ #include "tb-context.h" #include "internal.h" +//// --- Begin LibAFL code --- + +#include "tcg/tcg-op.h" +#include "tcg/tcg-internal.h" +#include "exec/helper-head.h" + +void libafl_helper_table_add(TCGHelperInfo* info); +TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, + target_ulong dst_block, target_ulong cs_base, + uint32_t flags, int cflags); +void libafl_gen_read(TCGv addr, MemOp ot); +void libafl_gen_read_N(TCGv addr, uint32_t size); +void libafl_gen_write(TCGv addr, MemOp ot); +void libafl_gen_write_N(TCGv addr, uint32_t size); +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); + +void (*libafl_exec_edge_hook)(uint64_t id); +uint64_t (*libafl_gen_edge_hook)(uint64_t src, uint64_t dst); + +static TCGHelperInfo libafl_exec_edge_hook_info = { + .func = NULL, .name = "libafl_exec_edge_hook", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) +}; +static int exec_edge_hook_added = 0; + +void (*libafl_exec_block_hook)(uint64_t id); +uint64_t (*libafl_gen_block_hook)(uint64_t pc); + +static TCGHelperInfo libafl_exec_block_hook_info = { + .func = NULL, .name = "libafl_exec_block_hook", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) +}; +static int exec_block_hook_added = 0; + +void (*libafl_exec_read_hook1)(uint64_t id, uint64_t addr); +void (*libafl_exec_read_hook2)(uint64_t id, uint64_t addr); +void (*libafl_exec_read_hook4)(uint64_t id, uint64_t addr); +void (*libafl_exec_read_hook8)(uint64_t id, uint64_t addr); +void (*libafl_exec_read_hookN)(uint64_t id, uint64_t addr, uint32_t size); +uint64_t (*libafl_gen_read_hook)(uint32_t size); + +static TCGHelperInfo libafl_exec_read_hook1_info = { + .func = NULL, .name = "libafl_exec_read_hook1", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_read_hook2_info = { + .func = NULL, .name = "libafl_exec_read_hook2", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_read_hook4_info = { + .func = NULL, .name = "libafl_exec_read_hook4", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_read_hook8_info = { + .func = NULL, .name = "libafl_exec_read_hook8", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_read_hookN_info = { + .func = NULL, .name = "libafl_exec_read_hookN", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2) +}; +static int exec_read_hook_added = 0; + +void libafl_gen_read(TCGv addr, MemOp ot) +{ + uint32_t size = 0; + void* func = NULL; + switch (ot & MO_SIZE) { + case MO_64: + size = 8; + func = libafl_exec_read_hook8; + break; + case MO_32: + size = 4; + func = libafl_exec_read_hook4; + break; + case MO_16: + size = 2; + func = libafl_exec_read_hook2; + break; + case MO_8: + size = 1; + func = libafl_exec_read_hook1; + break; + default: + return; + } + + uint32_t libafl_id = 0; + if (libafl_gen_read_hook) + libafl_id = libafl_gen_read_hook(size); + if (func && libafl_id != (uint32_t)-1) { + if (!exec_read_hook_added) { + exec_read_hook_added = 1; + libafl_exec_read_hook1_info.func = libafl_exec_read_hook1; + libafl_helper_table_add(&libafl_exec_read_hook1_info); + libafl_exec_read_hook2_info.func = libafl_exec_read_hook2; + libafl_helper_table_add(&libafl_exec_read_hook2_info); + libafl_exec_read_hook4_info.func = libafl_exec_read_hook4; + libafl_helper_table_add(&libafl_exec_read_hook4_info); + libafl_exec_read_hook8_info.func = libafl_exec_read_hook8; + libafl_helper_table_add(&libafl_exec_read_hook8_info); + libafl_exec_read_hookN_info.func = libafl_exec_read_hookN; + libafl_helper_table_add(&libafl_exec_read_hookN_info); + } + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(addr) }; +#else + tcgv_i64_temp(addr) }; +#endif + tcg_gen_callN(func, NULL, 2, tmp1); + tcg_temp_free_i64(tmp0); + } +} + +void libafl_gen_read_N(TCGv addr, uint32_t size) +{ + uint32_t libafl_id = 0; + if (libafl_gen_read_hook) + libafl_id = libafl_gen_read_hook(size); + if (libafl_id != (uint32_t)-1) { + if (!exec_read_hook_added) { + exec_read_hook_added = 1; + libafl_exec_read_hook1_info.func = libafl_exec_read_hook1; + libafl_helper_table_add(&libafl_exec_read_hook1_info); + libafl_exec_read_hook2_info.func = libafl_exec_read_hook2; + libafl_helper_table_add(&libafl_exec_read_hook2_info); + libafl_exec_read_hook4_info.func = libafl_exec_read_hook4; + libafl_helper_table_add(&libafl_exec_read_hook4_info); + libafl_exec_read_hook8_info.func = libafl_exec_read_hook8; + libafl_helper_table_add(&libafl_exec_read_hook8_info); + libafl_exec_read_hookN_info.func = libafl_exec_read_hookN; + libafl_helper_table_add(&libafl_exec_read_hookN_info); + } + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGv_i32 tmp1 = tcg_const_i32(size); + TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(addr), +#else + tcgv_i64_temp(addr), +#endif + tcgv_i32_temp(tmp1) + }; + tcg_gen_callN(libafl_exec_read_hookN, NULL, 3, tmp2); + tcg_temp_free_i32(tmp1); + tcg_temp_free_i64(tmp0); + } +} + +void (*libafl_exec_write_hook1)(uint64_t id, uint64_t addr); +void (*libafl_exec_write_hook2)(uint64_t id, uint64_t addr); +void (*libafl_exec_write_hook4)(uint64_t id, uint64_t addr); +void (*libafl_exec_write_hook8)(uint64_t id, uint64_t addr); +void (*libafl_exec_write_hookN)(uint64_t id, uint64_t addr, uint32_t size); +uint64_t (*libafl_gen_write_hook)(uint32_t size); + +static TCGHelperInfo libafl_exec_write_hook1_info = { + .func = NULL, .name = "libafl_exec_write_hook1", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_write_hook2_info = { + .func = NULL, .name = "libafl_exec_write_hook2", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_write_hook4_info = { + .func = NULL, .name = "libafl_exec_write_hook4", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_write_hook8_info = { + .func = NULL, .name = "libafl_exec_write_hook8", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) +}; +static TCGHelperInfo libafl_exec_write_hookN_info = { + .func = NULL, .name = "libafl_exec_write_hookN", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2) +}; +static int exec_write_hook_added = 0; + +void libafl_gen_write(TCGv addr, MemOp ot) +{ + uint32_t size = 0; + void* func = NULL; + switch (ot & MO_SIZE) { + case MO_64: + size = 8; + func = libafl_exec_write_hook8; + break; + case MO_32: + size = 4; + func = libafl_exec_write_hook4; + break; + case MO_16: + size = 2; + func = libafl_exec_write_hook2; + break; + case MO_8: + size = 1; + func = libafl_exec_write_hook1; + break; + default: + return; + } + + uint32_t libafl_id = 0; + if (libafl_gen_write_hook) + libafl_id = libafl_gen_write_hook(size); + if (func && libafl_id != (uint32_t)-1) { + if (!exec_write_hook_added) { + exec_write_hook_added = 1; + libafl_exec_write_hook1_info.func = libafl_exec_write_hook1; + libafl_helper_table_add(&libafl_exec_write_hook1_info); + libafl_exec_write_hook2_info.func = libafl_exec_write_hook2; + libafl_helper_table_add(&libafl_exec_write_hook2_info); + libafl_exec_write_hook4_info.func = libafl_exec_write_hook4; + libafl_helper_table_add(&libafl_exec_write_hook4_info); + libafl_exec_write_hook8_info.func = libafl_exec_write_hook8; + libafl_helper_table_add(&libafl_exec_write_hook8_info); + libafl_exec_write_hookN_info.func = libafl_exec_write_hookN; + libafl_helper_table_add(&libafl_exec_write_hookN_info); + } + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(addr) }; +#else + tcgv_i64_temp(addr) }; +#endif + tcg_gen_callN(func, NULL, 2, tmp1); + tcg_temp_free_i64(tmp0); + } +} + +void libafl_gen_write_N(TCGv addr, uint32_t size) +{ + uint32_t libafl_id = 0; + if (libafl_gen_write_hook) + libafl_id = libafl_gen_write_hook(size); + if (libafl_id != (uint32_t)-1) { + if (!exec_write_hook_added) { + exec_write_hook_added = 1; + libafl_exec_write_hook1_info.func = libafl_exec_write_hook1; + libafl_helper_table_add(&libafl_exec_write_hook1_info); + libafl_exec_write_hook2_info.func = libafl_exec_write_hook2; + libafl_helper_table_add(&libafl_exec_write_hook2_info); + libafl_exec_write_hook4_info.func = libafl_exec_write_hook4; + libafl_helper_table_add(&libafl_exec_write_hook4_info); + libafl_exec_write_hook8_info.func = libafl_exec_write_hook8; + libafl_helper_table_add(&libafl_exec_write_hook8_info); + libafl_exec_write_hookN_info.func = libafl_exec_write_hookN; + libafl_helper_table_add(&libafl_exec_write_hookN_info); + } + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGv_i32 tmp1 = tcg_const_i32(size); + TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(addr), +#else + tcgv_i64_temp(addr), +#endif + tcgv_i32_temp(tmp1) + }; + tcg_gen_callN(libafl_exec_write_hookN, NULL, 3, tmp2); + tcg_temp_free_i32(tmp1); + tcg_temp_free_i64(tmp0); + } +} + + +void (*libafl_exec_cmp_hook1)(uint64_t id, uint8_t v0, uint8_t v1); +void (*libafl_exec_cmp_hook2)(uint64_t id, uint16_t v0, uint16_t v1); +void (*libafl_exec_cmp_hook4)(uint64_t id, uint32_t v0, uint32_t v1); +void (*libafl_exec_cmp_hook8)(uint64_t id, uint64_t v0, uint64_t v1); +uint64_t (*libafl_gen_cmp_hook)(uint64_t pc, uint32_t size); + +static TCGHelperInfo libafl_exec_cmp_hook1_info = { + .func = NULL, .name = "libafl_exec_cmp_hook1", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i32, 1) + | dh_typemask(tl, 2) | dh_typemask(tl, 3) +}; +static TCGHelperInfo libafl_exec_cmp_hook2_info = { + .func = NULL, .name = "libafl_exec_cmp_hook2", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i32, 1) + | dh_typemask(tl, 2) | dh_typemask(tl, 3) +}; +static TCGHelperInfo libafl_exec_cmp_hook4_info = { + .func = NULL, .name = "libafl_exec_cmp_hook4", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i32, 1) + | dh_typemask(tl, 2) | dh_typemask(tl, 3) +}; +static TCGHelperInfo libafl_exec_cmp_hook8_info = { + .func = NULL, .name = "libafl_exec_cmp_hook8", \ + .flags = dh_callflag(void), \ + .typemask = dh_typemask(void, 0) | dh_typemask(i32, 1) + | dh_typemask(tl, 2) | dh_typemask(tl, 3) +}; +static int exec_cmp_hook_added = 0; + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot) +{ + uint32_t size = 0; + void* func = NULL; + switch (ot & MO_SIZE) { + case MO_64: + size = 8; + func = libafl_exec_cmp_hook8; + break; + case MO_32: + size = 4; + func = libafl_exec_cmp_hook4; + break; + case MO_16: + size = 2; + func = libafl_exec_cmp_hook2; + break; + case MO_8: + size = 1; + func = libafl_exec_cmp_hook1; + break; + default: + return; + } + + uint32_t libafl_id = 0; + if (libafl_gen_cmp_hook) + libafl_id = libafl_gen_cmp_hook((uint64_t)pc, size); + if (func && libafl_id != (uint32_t)-1) { + if (!exec_cmp_hook_added) { + exec_cmp_hook_added = 1; + libafl_exec_cmp_hook1_info.func = libafl_exec_cmp_hook1; + libafl_helper_table_add(&libafl_exec_cmp_hook1_info); + libafl_exec_cmp_hook2_info.func = libafl_exec_cmp_hook2; + libafl_helper_table_add(&libafl_exec_cmp_hook2_info); + libafl_exec_cmp_hook4_info.func = libafl_exec_cmp_hook4; + libafl_helper_table_add(&libafl_exec_cmp_hook4_info); + libafl_exec_cmp_hook8_info.func = libafl_exec_cmp_hook8; + libafl_helper_table_add(&libafl_exec_cmp_hook8_info); + } + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGTemp *tmp1[3] = { tcgv_i64_temp(tmp0), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(op0), tcgv_i32_temp(op1) }; +#else + tcgv_i64_temp(op0), tcgv_i64_temp(op1) }; +#endif + tcg_gen_callN(func, NULL, 3, tmp1); + tcg_temp_free_i64(tmp0); + } +} + +//// --- End LibAFL code --- + /* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_FLUSH */ /* make various TB consistency checks */ @@ -1400,6 +1769,122 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, return tb; } +//// --- Begin LibAFL code --- + +/* Called with mmap_lock held for user mode emulation. */ +TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, + target_ulong dst_block, target_ulong cs_base, + uint32_t flags, int cflags) +{ + CPUArchState *env = cpu->env_ptr; + TranslationBlock *tb; + tcg_insn_unit *gen_code_buf; + int gen_code_size, search_size; + + assert_memory_lock(); + + uint32_t libafl_id = 0; + if (libafl_gen_edge_hook) + libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block); + if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1) + return NULL; + + if (!exec_edge_hook_added) { + exec_edge_hook_added = 1; + libafl_exec_edge_hook_info.func = libafl_exec_edge_hook; + libafl_helper_table_add(&libafl_exec_edge_hook_info); + } + + buffer_overflow1: + 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); + } + + libafl_exec_edge_hook(libafl_id); + + gen_code_buf = tcg_ctx->code_gen_ptr; + tb->tc.ptr = gen_code_buf; + tb->pc = 0; + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags; + tb->trace_vcpu_dstate = *cpu->trace_dstate; + tcg_ctx->tb_cflags = 0; + + tcg_func_start(tcg_ctx); + + tcg_ctx->cpu = env_cpu(env); + + TCGv_i64 tmp0 = tcg_const_i64(libafl_id); + TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) }; + tcg_gen_callN(libafl_exec_edge_hook, NULL, 1, tmp1); + tcg_temp_free_i64(tmp0); + + tcg_gen_goto_tb(0); + tcg_gen_exit_tb(tb, 0); + + tcg_ctx->cpu = NULL; + + trace_translate_block(tb, tb->pc, tb->tc.ptr); + + /* generate machine code */ + tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; + tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID; + tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; + if (TCG_TARGET_HAS_direct_jump) { + tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; + tcg_ctx->tb_jmp_target_addr = NULL; + } else { + tcg_ctx->tb_jmp_insn_offset = NULL; + tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg; + } + + /* ??? Overflow could be handled better here. In particular, 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. */ + gen_code_size = tcg_gen_code(tcg_ctx, tb); + if (unlikely(gen_code_size < 0)) { + goto buffer_overflow1; + } + search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size); + if (unlikely(search_size < 0)) { + goto buffer_overflow1; + } + tb->tc.size = gen_code_size; + + 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_RESET_OFFSET_INVALID) { + tb_reset_jump(tb, 0); + } + if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) { + tb_reset_jump(tb, 1); + } + + return tb; +} + +//// --- End LibAFL code --- + /* Called with mmap_lock held for user mode emulation. */ TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, target_ulong cs_base, @@ -1467,6 +1952,26 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_func_start(tcg_ctx); tcg_ctx->cpu = env_cpu(env); + + //// --- Begin LibAFL code --- + + uint32_t libafl_id = 0; + if (libafl_gen_block_hook) + libafl_id = libafl_gen_block_hook((uint64_t)pc); + if (libafl_exec_block_hook && libafl_id != (uint32_t)-1) { + if (!exec_block_hook_added) { + exec_block_hook_added = 1; + libafl_exec_block_hook_info.func = libafl_exec_block_hook; + libafl_helper_table_add(&libafl_exec_block_hook_info); + } + TCGv_i64 tmp0 = tcg_const_i64((uint64_t)pc); + TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) }; + tcg_gen_callN(libafl_exec_block_hook, NULL, 1, tmp1); + tcg_temp_free_i64(tmp0); + } + + //// --- End LibAFL code --- + gen_intermediate_code(cpu, tb, max_insns); assert(tb->size != 0); tcg_ctx->cpu = NULL; diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index c53a7f8e44..250e0b9542 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -18,6 +18,22 @@ #include "exec/plugin-gen.h" #include "sysemu/replay.h" +//// --- Begin LibAFL code --- + +#include "tcg/tcg-internal.h" + +struct libafl_hook { + target_ulong addr; + void (*callback)(uint64_t); + uint64_t value; + TCGHelperInfo helper_info; + struct libafl_hook* next; +}; + +extern struct libafl_hook* libafl_qemu_hooks; + +//// --- End LibAFL code --- + /* Pairs with tcg_clear_temp_count. To be called by #TranslatorOps.{translate_insn,tb_stop} if (1) the target is sufficiently clean to support reporting, @@ -79,6 +95,21 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, plugin_gen_insn_start(cpu, db); } + //// --- Begin LibAFL code --- + + struct libafl_hook* hk = libafl_qemu_hooks; + while (hk) { + if (hk->addr == db->pc_next) { + TCGv_i64 tmp0 = tcg_const_i64(hk->value); + TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) }; + tcg_gen_callN(hk->callback, NULL, 1, tmp1); + tcg_temp_free_i64(tmp0); + } + hk = hk->next; + } + + //// --- End LibAFL code --- + /* Disassemble one instruction. The translate_insn hook should update db->pc_next and db->is_jmp to indicate what should be done next -- either exiting this loop or locate the start of diff --git a/cpu.c b/cpu.c index 07bd1c1cfa..68436d1fc0 100644 --- a/cpu.c +++ b/cpu.c @@ -40,6 +40,140 @@ #include "hw/core/accel-cpu.h" #include "trace/trace-root.h" +//// --- Begin LibAFL code --- + +#include "tcg/tcg-op.h" +#include "tcg/tcg-internal.h" +#include "exec/helper-head.h" + +struct libafl_hook { + target_ulong addr; + void (*callback)(uint64_t); + uint64_t value; + TCGHelperInfo helper_info; + struct libafl_hook* next; +}; + +struct libafl_hook* libafl_qemu_hooks = NULL; + +__thread CPUArchState *libafl_qemu_env; + +void libafl_helper_table_add(TCGHelperInfo* info); + +static GByteArray *libafl_qemu_mem_buf = NULL; + +int libafl_qemu_write_reg(int reg, uint8_t* val); +int libafl_qemu_read_reg(int reg, uint8_t* val); +int libafl_qemu_num_regs(void); +int libafl_qemu_set_hook(uint64_t addr, void (*callback)(uint64_t), uint64_t value); +int libafl_qemu_remove_hook(uint64_t addr); + +int libafl_qemu_write_reg(int reg, uint8_t* val) +{ + CPUState *cpu = current_cpu; + if (!cpu) { + cpu = env_cpu(libafl_qemu_env); + if (!cpu) { + return 0; + } + } + + CPUClass *cc = CPU_GET_CLASS(cpu); + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_write_register(cpu, val, reg); + } + return 0; +} + +int libafl_qemu_read_reg(int reg, uint8_t* val) +{ + CPUState *cpu = current_cpu; + if (!cpu) { + cpu = env_cpu(libafl_qemu_env); + if (!cpu) { + return 0; + } + } + + if (libafl_qemu_mem_buf == NULL) { + libafl_qemu_mem_buf = g_byte_array_sized_new(64); + } + + CPUClass *cc = CPU_GET_CLASS(cpu); + if (reg < cc->gdb_num_core_regs) { + g_byte_array_set_size(libafl_qemu_mem_buf, 0); + int len = cc->gdb_read_register(cpu, libafl_qemu_mem_buf, reg); + if (len > 0) { + memcpy(val, libafl_qemu_mem_buf->data, len); + } + return len; + } + return 0; +} + +int libafl_qemu_num_regs(void) +{ + CPUState *cpu = current_cpu; + if (!cpu) { + cpu = env_cpu(libafl_qemu_env); + if (!cpu) { + return 0; + } + } + + CPUClass *cc = CPU_GET_CLASS(cpu); + return cc->gdb_num_core_regs; +} + +void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc); + +int libafl_qemu_set_hook(uint64_t addr, void (*callback)(uint64_t), uint64_t value) +{ + CPUState *cpu; + + target_ulong pc = (target_ulong) addr; + CPU_FOREACH(cpu) { + libafl_breakpoint_invalidate(cpu, pc); + } + + struct libafl_hook* hk = malloc(sizeof(struct libafl_hook)); + hk->addr = pc; + hk->callback = callback; + hk->value = value; + hk->helper_info.func = callback; + hk->helper_info.name = "libafl_hook"; + hk->helper_info.flags = dh_callflag(void); + hk->helper_info.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1); + hk->next = libafl_qemu_hooks; + libafl_qemu_hooks = hk; + libafl_helper_table_add(&hk->helper_info); + return 1; +} + +int libafl_qemu_remove_hook(uint64_t addr) +{ + CPUState *cpu; + int r = 0; + + target_ulong pc = (target_ulong) addr; + struct libafl_hook** hk = &libafl_qemu_hooks; + while (*hk) { + if ((*hk)->addr == pc) { + CPU_FOREACH(cpu) { + libafl_breakpoint_invalidate(cpu, pc); + } + + *hk = (*hk)->next; + r = 1; + } else { + hk = &(*hk)->next; + } + } + return r; +} + +//// --- End LibAFL code --- + uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -225,6 +359,15 @@ void tb_invalidate_phys_addr(target_ulong addr) tb_invalidate_phys_page_range(addr, addr + 1); mmap_unlock(); } + +//// --- Begin LibAFL code --- + +void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc) +{ + tb_invalidate_phys_addr(pc); +} + +//// --- End LibAFL code --- #else void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) { @@ -245,6 +388,15 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) ram_addr = memory_region_get_ram_addr(mr) + addr; tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); } + +//// --- Begin LibAFL code --- + +void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc) +{ + tb_flush(cpu); +} + +//// --- End LibAFL code --- #endif /* Add a breakpoint. */ diff --git a/tcg/tcg.c b/tcg/tcg.c index ca5bcc4635..2c6f9b6de8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -566,6 +566,16 @@ static void process_op_defs(TCGContext *s); static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, TCGReg reg, const char *name); +//// --- Begin LibAFL code --- + +void libafl_helper_table_add(TCGHelperInfo* info); +void libafl_helper_table_add(TCGHelperInfo* info) { + g_hash_table_insert(helper_table, (gpointer)info->func, + (gpointer)info); +} + +//// --- End LibAFL code --- + static void tcg_context_init(unsigned max_cpus) { TCGContext *s = &tcg_init_ctx;