diff --git a/README.md b/README.md new file mode 100644 index 0000000000..c54f4ca3b1 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# QEMU LibAFL Bridge + +This is a patched QEMU that exposes an interface for LibAFL-based fuzzers. + +This raw interface is used in `libafl_qemu` that expose a more Rusty API. + +#### License + + +This project extends the QEMU emulator, and our contributions to previously existing files adopt those files' respective licenses; the files that we have added are made available under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. + + +
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index e5c0ccd1a2..959b121df0 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -626,6 +626,18 @@ static inline void cpu_handle_debug_exception(CPUState *cpu) static inline bool cpu_handle_exception(CPUState *cpu, int *ret) { + //// --- Begin LibAFL code --- + +#define EXCP_LIBAFL_BP 0xf4775747 + + if (cpu->exception_index == EXCP_LIBAFL_BP) { + *ret = cpu->exception_index; + cpu->exception_index = -1; + return true; + } + + //// --- End LibAFL code --- + if (cpu->exception_index < 0) { #ifndef CONFIG_USER_ONLY if (replay_has_exception() @@ -851,6 +863,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 +984,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/tcg-runtime.c b/accel/tcg/tcg-runtime.c index e4e030043f..762c410969 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -31,6 +31,19 @@ #include "exec/log.h" #include "tcg/tcg.h" +//// --- Begin LibAFL code --- + +#define EXCP_LIBAFL_BP 0xf4775747 + +void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env) +{ + CPUState* cpu = env_cpu(env); + cpu->exception_index = EXCP_LIBAFL_BP; + cpu_loop_exit(cpu); +} + +//// --- 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 37cbd722bf..20eda6f1ec 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -285,3 +285,9 @@ 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) + +//// --- Begin LibAFL code --- + +DEF_HELPER_FLAGS_1(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, void, env) + +//// --- End LibAFL code --- 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..2ad28db09f 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -18,6 +18,29 @@ #include "exec/plugin-gen.h" #include "sysemu/replay.h" +//// --- Begin LibAFL code --- + +#include "tcg/tcg-internal.h" + +struct libafl_breakpoint { + target_ulong addr; + struct libafl_breakpoint* next; +}; + +extern struct libafl_breakpoint* libafl_qemu_breakpoints; + +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 +102,29 @@ 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; + } + + struct libafl_breakpoint* bp = libafl_qemu_breakpoints; + while (bp) { + if (bp->addr == db->pc_next) { + gen_helper_libafl_qemu_handle_breakpoint(cpu_env); + } + bp = bp->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/configure b/configure index 6e308ed77f..6f1925bfa1 100755 --- a/configure +++ b/configure @@ -835,6 +835,8 @@ if test "$mingw32" = "yes" ; then fi werror="" +as_shared_lib="no" +as_static_lib="no" for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') @@ -1581,6 +1583,16 @@ for opt do ;; --disable-slirp-smbd) slirp_smbd=no ;; + --as-shared-lib) + as_shared_lib="yes" + QEMU_CFLAGS="$QEMU_CFLAGS -fPIC -DAS_LIB=1" + QEMU_CXXFLAGS="$QEMU_CXXFLAGS -fPIC -DAS_LIB=1" + ;; + --as-static-lib) + as_static_lib="yes" + QEMU_CFLAGS="$QEMU_CFLAGS -fPIC -DAS_LIB=1" + QEMU_CXXFLAGS="$QEMU_CXXFLAGS -fPIC -DAS_LIB=1" + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -4919,6 +4931,13 @@ if test "$secret_keyring" = "yes" ; then echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak fi +if test "$as_shared_lib" = "yes" ; then + echo "AS_SHARED_LIB=y" >> $config_host_mak +fi +if test "$as_static_lib" = "yes" ; then + echo "AS_STATIC_LIB=y" >> $config_host_mak +fi + echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak echo "PYTHON=$python" >> $config_host_mak diff --git a/cpu.c b/cpu.c index e1799a15bc..7dd96b7dbf 100644 --- a/cpu.c +++ b/cpu.c @@ -40,6 +40,187 @@ #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_breakpoint { + target_ulong addr; + struct libafl_breakpoint* next; +}; + +struct libafl_breakpoint* libafl_qemu_breakpoints = NULL; + +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_breakpoint(uint64_t addr); +int libafl_qemu_remove_breakpoint(uint64_t addr); +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_breakpoint(uint64_t addr) +{ + CPUState *cpu; + + target_ulong pc = (target_ulong) addr; + CPU_FOREACH(cpu) { + libafl_breakpoint_invalidate(cpu, pc); + } + + struct libafl_breakpoint* bp = malloc(sizeof(struct libafl_breakpoint)); + bp->addr = pc; + bp->next = libafl_qemu_breakpoints; + libafl_qemu_breakpoints = bp; + return 1; +} + +int libafl_qemu_remove_breakpoint(uint64_t addr) +{ + CPUState *cpu; + int r = 0; + + target_ulong pc = (target_ulong) addr; + struct libafl_breakpoint** bp = &libafl_qemu_breakpoints; + while (*bp) { + if ((*bp)->addr == pc) { + CPU_FOREACH(cpu) { + libafl_breakpoint_invalidate(cpu, pc); + } + + *bp = (*bp)->next; + r = 1; + } else { + bp = &(*bp)->next; + } + } + return r; +} + +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 +406,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 +435,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/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index ee72a1c20f..57c904bda2 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -88,6 +88,16 @@ void cpu_loop(CPUARMState *env) process_queued_cpu_work(cs); switch (trapnr) { + +//// --- Begin LibAFL code --- + +#define EXCP_LIBAFL_BP 0xf4775747 + + case EXCP_LIBAFL_BP: + return; + +//// --- End LibAFL code --- + case EXCP_SWI: ret = do_syscall(env, env->xregs[8], diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 69632d15be..20f0dc2f09 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -298,6 +298,16 @@ void cpu_loop(CPUARMState *env) process_queued_cpu_work(cs); switch(trapnr) { + +//// --- Begin LibAFL code --- + +#define EXCP_LIBAFL_BP 0xf4775747 + + case EXCP_LIBAFL_BP: + return; + +//// --- End LibAFL code --- + case EXCP_UDEF: case EXCP_NOCP: case EXCP_INVSTATE: diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index f813e87294..f1a64cf278 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -209,6 +209,16 @@ void cpu_loop(CPUX86State *env) process_queued_cpu_work(cs); switch(trapnr) { + +//// --- Begin LibAFL code --- + +#define EXCP_LIBAFL_BP 0xf4775747 + + case EXCP_LIBAFL_BP: + return; + +//// --- End LibAFL code --- + case 0x80: /* linux syscall from int $0x80 */ ret = do_syscall(env, diff --git a/linux-user/main.c b/linux-user/main.c index 37ed50d98e..a4b60a3955 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -582,6 +582,16 @@ static int parse_args(int argc, char **argv) r++; } + if (!strncmp(r, "libafl", 6)) { + if (optind >= argc) { + (void) fprintf(stderr, + "qemu: missing argument for option '%s'\n", r); + exit(EXIT_FAILURE); + } + optind++; + continue; + } + for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { if (!strcmp(r, arginfo->argv)) { if (arginfo->has_arg) { @@ -611,16 +621,51 @@ static int parse_args(int argc, char **argv) exit(EXIT_FAILURE); } - exec_path = argv[optind]; + exec_path = strdup(argv[optind]); return optind; } +//// --- Begin LibAFL code --- + +uint64_t libafl_load_addr(void); +int libafl_qemu_main(void); +int libafl_qemu_run(void); + +extern __thread CPUArchState *libafl_qemu_env; + +struct image_info libafl_image_info; +struct linux_binprm bprm; + +uint64_t libafl_load_addr(void) { + return libafl_image_info.load_addr; +} + +__attribute__((weak)) int libafl_qemu_main(void) +{ + libafl_qemu_run(); + return 0; +} + +int libafl_qemu_run(void) +{ + cpu_loop(libafl_qemu_env); + return 1; +} + +//// --- End LibAFL code --- + +#ifdef AS_LIB +int qemu_user_init(int argc, char **argv, char **envp); +int qemu_user_init(int argc, char **argv, char **envp) +#else int main(int argc, char **argv, char **envp) +#endif { struct target_pt_regs regs1, *regs = ®s1; - struct image_info info1, *info = &info1; - struct linux_binprm bprm; + //struct image_info info1, *info = &info1; + struct image_info *info = &libafl_image_info; + // struct linux_binprm bprm; TaskState *ts; CPUArchState *env; CPUState *cpu; @@ -882,7 +927,18 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(cpu, 0); } - cpu_loop(env); + // cpu_loop(env); + + //// --- Begin LibAFL code --- + + libafl_qemu_env = env; + +#ifndef AS_LIB + return libafl_qemu_main(); +#endif + + //// --- End LibAFL code --- + /* never exits */ return 0; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ccd3892b2d..f43c132f2d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -756,6 +756,23 @@ void target_set_brk(abi_ulong new_brk) brk_page = HOST_PAGE_ALIGN(target_brk); } +//// --- Begin LibAFL code --- + +uint64_t libafl_get_brk(void); +uint64_t libafl_set_brk(uint64_t new_brk); + +uint64_t libafl_get_brk(void) { + return (uint64_t)target_brk; +} + +uint64_t libafl_set_brk(uint64_t new_brk) { + uint64_t old_brk = (uint64_t)target_brk; + target_brk = (abi_ulong)new_brk; + return old_brk; +} + +//// --- End LibAFL code --- + //#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0) #define DEBUGF_BRK(message, args...) @@ -13115,6 +13132,67 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return ret; } +//// --- Begin LibAFL code --- + +struct libafl_mapinfo { + uint64_t start, end; + uint64_t offset; + const char* path; + int flags, is_priv; +}; +GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret); + +GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret) { + if (!map_info || !ret) + return NULL; + GSList *s = g_slist_next(map_info); + if (!s) + return NULL; + MapInfo *e = (MapInfo *) s->data; + + if (h2g_valid(e->start)) { + unsigned long min = e->start; + unsigned long max = e->end; + int flags = page_get_flags(h2g(min)); + + max = h2g_valid(max - 1) ? + max : (uintptr_t) g2h_untagged(GUEST_ADDR_MAX) + 1; + + if (page_check_range(h2g(min), max - min, flags) == -1) { + return libafl_maps_next(s, ret); + } + + int libafl_flags = 0; + if (flags & PAGE_READ) libafl_flags |= PROT_READ; + if (flags & PAGE_WRITE_ORG) libafl_flags |= PROT_WRITE; + if (flags & PAGE_EXEC) libafl_flags |= PROT_EXEC; + + ret->start = (uint64_t)min; + ret->end = (uint64_t)max; + ret->offset = (uint64_t)e->offset; + ret->path = e->path; + ret->flags = libafl_flags; + ret->is_priv = e->is_priv; + + return s; + } else { + return libafl_maps_next(s, ret); + } +} + +struct syshook_ret { + uint64_t retval; + bool skip_syscall; +}; +struct syshook_ret (*libafl_pre_syscall_hook)(int, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t); +uint64_t (*libafl_post_syscall_hook)(uint64_t, int, uint64_t, uint64_t, + uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t); + +//// --- End LibAFL code --- + abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, @@ -13144,9 +13222,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6); } + //// --- Begin LibAFL code --- + + if (libafl_pre_syscall_hook) { + struct syshook_ret hook_ret = libafl_pre_syscall_hook(num, + (uint64_t)arg1, + (uint64_t)arg2, + (uint64_t)arg3, + (uint64_t)arg4, + (uint64_t)arg5, + (uint64_t)arg6, + (uint64_t)arg7, + (uint64_t)arg8); + if (hook_ret.skip_syscall) { + ret = (abi_ulong)hook_ret.retval; + goto after_syscall; + } + } + + //// --- End LibAFL code --- + ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + //// --- Begin LibAFL code --- + + if (libafl_post_syscall_hook) { + ret = (abi_ulong)libafl_post_syscall_hook((uint64_t)ret, num, + (uint64_t)arg1, + (uint64_t)arg2, + (uint64_t)arg3, + (uint64_t)arg4, + (uint64_t)arg5, + (uint64_t)arg6, + (uint64_t)arg7, + (uint64_t)arg8); + } + +after_syscall: + //// --- End LibAFL code --- + if (unlikely(qemu_loglevel_mask(LOG_STRACE))) { print_syscall_ret(cpu_env, num, ret, arg1, arg2, arg3, arg4, arg5, arg6); diff --git a/meson.build b/meson.build index b3e7ec0e92..d9e4d42e71 100644 --- a/meson.build +++ b/meson.build @@ -1797,7 +1797,8 @@ if capstone_opt == 'internal' build_by_default: false, sources: capstone_files, c_args: capstone_cargs, - include_directories: 'capstone/include') + include_directories: 'capstone/include', + pic: 'AS_SHARED_LIB' in config_host) capstone = declare_dependency(link_with: libcapstone, include_directories: 'capstone/include/capstone') endif @@ -1877,7 +1878,8 @@ if have_system build_by_default: false, sources: slirp_files, c_args: slirp_cargs, - include_directories: slirp_inc) + include_directories: slirp_inc, + pic: 'AS_SHARED_LIB' in config_host) slirp = declare_dependency(link_with: libslirp, dependencies: slirp_deps, include_directories: slirp_inc) @@ -1934,7 +1936,8 @@ if have_system libfdt = static_library('fdt', build_by_default: false, sources: fdt_files, - include_directories: fdt_inc) + include_directories: fdt_inc, + pic: 'AS_SHARED_LIB' in config_host) fdt = declare_dependency(link_with: libfdt, include_directories: fdt_inc) endif @@ -2202,7 +2205,8 @@ util_ss.add_all(trace_ss) util_ss = util_ss.apply(config_all, strict: false) libqemuutil = static_library('qemuutil', sources: util_ss.sources() + stub_ss.sources() + genh, - dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) + dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman], + pic: 'AS_SHARED_LIB' in config_host) qemuutil = declare_dependency(link_with: libqemuutil, sources: genh + version_res) @@ -2267,7 +2271,8 @@ if get_option('b_lto') pagevary_flags += '-fno-sanitize=cfi-icall' endif pagevary = static_library('page-vary-common', sources: pagevary, - c_args: pagevary_flags) + c_args: pagevary_flags, + pic: 'AS_SHARED_LIB' in config_host) pagevary = declare_dependency(link_with: pagevary) endif common_ss.add(pagevary) @@ -2393,7 +2398,8 @@ if enable_modules input: modinfo_files, command: [modinfo_generate, '@INPUT@'], capture: true) - modinfo_lib = static_library('modinfo', modinfo_src) + modinfo_lib = static_library('modinfo', modinfo_src, + pic: 'AS_SHARED_LIB' in config_host) modinfo_dep = declare_dependency(link_whole: modinfo_lib) softmmu_ss.add(modinfo_dep) endif @@ -2412,7 +2418,8 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms', qom_ss = qom_ss.apply(config_host, strict: false) libqom = static_library('qom', qom_ss.sources() + genh, dependencies: [qom_ss.dependencies()], - name_suffix: 'fa') + name_suffix: 'fa', + pic: 'AS_SHARED_LIB' in config_host) qom = declare_dependency(link_whole: libqom) @@ -2420,7 +2427,8 @@ authz_ss = authz_ss.apply(config_host, strict: false) libauthz = static_library('authz', authz_ss.sources() + genh, dependencies: [authz_ss.dependencies()], name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) authz = declare_dependency(link_whole: libauthz, dependencies: qom) @@ -2429,7 +2437,8 @@ crypto_ss = crypto_ss.apply(config_host, strict: false) libcrypto = static_library('crypto', crypto_ss.sources() + genh, dependencies: [crypto_ss.dependencies()], name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) crypto = declare_dependency(link_whole: libcrypto, dependencies: [authz, qom]) @@ -2439,13 +2448,15 @@ libio = static_library('io', io_ss.sources() + genh, dependencies: [io_ss.dependencies()], link_with: libqemuutil, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) io = declare_dependency(link_whole: libio, dependencies: [crypto, qom]) libmigration = static_library('migration', sources: migration_files + genh, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) migration = declare_dependency(link_with: libmigration, dependencies: [zlib, qom, io]) softmmu_ss.add(migration) @@ -2455,7 +2466,8 @@ libblock = static_library('block', block_ss.sources() + genh, dependencies: block_ss.dependencies(), link_depends: block_syms, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) block = declare_dependency(link_whole: [libblock], link_args: '@block.syms', @@ -2465,7 +2477,8 @@ blockdev_ss = blockdev_ss.apply(config_host, strict: false) libblockdev = static_library('blockdev', blockdev_ss.sources() + genh, dependencies: blockdev_ss.dependencies(), name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) blockdev = declare_dependency(link_whole: [libblockdev], dependencies: [block]) @@ -2474,20 +2487,23 @@ qmp_ss = qmp_ss.apply(config_host, strict: false) libqmp = static_library('qmp', qmp_ss.sources() + genh, dependencies: qmp_ss.dependencies(), name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) qmp = declare_dependency(link_whole: [libqmp]) libchardev = static_library('chardev', chardev_ss.sources() + genh, name_suffix: 'fa', dependencies: [gnutls], - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) chardev = declare_dependency(link_whole: libchardev) libhwcore = static_library('hwcore', sources: hwcore_files + genh, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: 'AS_SHARED_LIB' in config_host) hwcore = declare_dependency(link_whole: libhwcore) common_ss.add(hwcore) @@ -2515,7 +2531,8 @@ common_all = static_library('common', sources: common_all.sources() + genh, implicit_include_directories: false, dependencies: common_all.dependencies(), - name_suffix: 'fa') + name_suffix: 'fa', + pic: 'AS_SHARED_LIB' in config_host) feature_to_c = find_program('scripts/feature_to_c.sh') @@ -2609,7 +2626,8 @@ foreach target : target_dirs include_directories: target_inc, c_args: c_args, build_by_default: false, - name_suffix: 'fa') + name_suffix: 'fa', + pic: 'AS_SHARED_LIB' in config_host) if target.endswith('-softmmu') execs = [{ @@ -2649,15 +2667,34 @@ foreach target : target_dirs exe_name += '-unsigned' endif - emulator = executable(exe_name, exe['sources'], - install: true, - c_args: c_args, - dependencies: arch_deps + deps + exe['dependencies'], - objects: lib.extract_all_objects(recursive: true), - link_language: link_language, - link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), - link_args: link_args, - gui_app: exe['gui']) + if 'AS_SHARED_LIB' not in config_host and 'AS_STATIC_LIB' not in config_host + emulator = executable(exe_name, exe['sources'], + install: true, + c_args: c_args, + dependencies: arch_deps + deps + exe['dependencies'], + objects: lib.extract_all_objects(recursive: true), + link_language: link_language, + link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), + link_args: link_args, + gui_app: exe['gui']) + else + if 'AS_SHARED_LIB' in config_host + emulator = shared_library(exe_name, exe['sources'], + install: true, + c_args: c_args, + dependencies: arch_deps + deps + exe['dependencies'], + objects: lib.extract_all_objects(recursive: true), + link_language: link_language, + link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), + link_args: link_args) + endif + if 'AS_STATIC_LIB' in config_host + emulator = static_library(exe_name, exe['sources'], + c_args: c_args, + dependencies: arch_deps + deps + exe['dependencies'], + objects: lib.extract_all_objects(recursive: true)) + endif + endif if targetos == 'darwin' icon = 'pc-bios/qemu.rsrc' diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 422e2ac0c9..d1fe577750 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -4186,6 +4186,12 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) tcg_gen_movi_i64(cpu_reg(s, rd), base + offset); } +//// --- Begin LibAFL code --- + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); + +//// --- End LibAFL code --- + /* * Add/subtract (immediate) * @@ -4217,6 +4223,16 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) imm <<= 12; } +//// --- Begin LibAFL code --- + + if (rd == 31 && sub_op) { // cmp xX, imm + TCGv_i64 tcg_imm = tcg_const_i64(imm); + libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_imm, is_64bit ? MO_64 : MO_32); + tcg_temp_free_i64(tcg_imm); + } + +//// --- End LibAFL code --- + tcg_result = tcg_temp_new_i64(); if (!setflags) { if (sub_op) { @@ -4879,6 +4895,13 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) tcg_rm = read_cpu_reg(s, rm, sf); ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3); +//// --- Begin LibAFL code --- + + if (rd == 31 && sub_op) // cmp xX, xY + libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_rm, sf ? MO_64 : MO_32); + +//// --- End LibAFL code --- + tcg_result = tcg_temp_new_i64(); if (!setflags) { @@ -4943,6 +4966,13 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn) shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6); +//// --- Begin LibAFL code --- + + if (rd == 31 && sub_op) // cmp xX, xY + libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_rm, sf ? MO_64 : MO_32); + +//// --- End LibAFL code --- + tcg_result = tcg_temp_new_i64(); if (!setflags) { @@ -5225,6 +5255,12 @@ static void disas_cc(DisasContext *s, uint32_t insn) } tcg_rn = cpu_reg(s, rn); +//// --- Begin LibAFL code --- + + libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_y, sf ? MO_64 : MO_32); + +//// --- End LibAFL code --- + /* Set the flags for the new comparison. */ tcg_tmp = tcg_temp_new_i64(); if (op) { diff --git a/target/arm/translate.c b/target/arm/translate.c index 80c282669f..8c91b4c924 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5424,6 +5424,12 @@ static bool store_reg_kind(DisasContext *s, int rd, g_assert_not_reached(); } +//// --- Begin LibAFL code --- + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); + +//// --- End LibAFL code --- + /* * Data Processing (register) * @@ -5440,6 +5446,24 @@ static bool op_s_rrr_shi(DisasContext *s, arg_s_rrr_shi *a, gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc); tmp1 = load_reg(s, a->rn); +//// --- Begin LibAFL code --- + + if (gen == gen_sub_CC || /*gen == gen_add_CC ||*/ gen == gen_rsb_CC) { +#ifdef TARGET_AARCH64 + TCGv tmp1_64 = tcg_temp_new(); + TCGv tmp2_64 = tcg_temp_new(); + tcg_gen_extu_i32_i64(tmp1_64, tmp1); + tcg_gen_extu_i32_i64(tmp2_64, tmp2); + libafl_gen_cmp(s->pc_curr, tmp1_64, tmp2_64, MO_32); + tcg_temp_free(tmp1_64); + tcg_temp_free(tmp2_64); +#else + libafl_gen_cmp(s->pc_curr, tmp1, tmp2, MO_32); +#endif + } + +//// --- End LibAFL code --- + gen(tmp1, tmp1, tmp2); tcg_temp_free_i32(tmp2); @@ -5532,6 +5556,24 @@ static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a, tmp2 = tcg_const_i32(imm); tmp1 = load_reg(s, a->rn); +//// --- Begin LibAFL code --- + + if (gen == gen_sub_CC || /*gen == gen_add_CC ||*/ gen == gen_rsb_CC) { +#ifdef TARGET_AARCH64 + TCGv tmp1_64 = tcg_temp_new(); + TCGv tmp2_64 = tcg_temp_new(); + tcg_gen_extu_i32_i64(tmp1_64, tmp1); + tcg_gen_extu_i32_i64(tmp2_64, tmp2); + libafl_gen_cmp(s->pc_curr, tmp1_64, tmp2_64, MO_32); + tcg_temp_free(tmp1_64); + tcg_temp_free(tmp2_64); +#else + libafl_gen_cmp(s->pc_curr, tmp1, tmp2, MO_32); +#endif + } + +//// --- End LibAFL code --- + gen(tmp1, tmp1, tmp2); tcg_temp_free_i32(tmp2); diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index aacb605eee..45d8f68487 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -32,6 +32,12 @@ #include "exec/log.h" +//// --- Begin LibAFL code --- + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); + +//// --- End LibAFL code --- + #define PREFIX_REPZ 0x01 #define PREFIX_REPNZ 0x02 #define PREFIX_LOCK 0x04 @@ -1445,6 +1451,13 @@ static void gen_op(DisasContext *s1, int op, MemOp ot, int d) tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1); } else { tcg_gen_mov_tl(s1->cc_srcT, s1->T0); + + //// --- Begin LibAFL code --- + + libafl_gen_cmp(s1->pc, s1->T0, s1->T1, ot); + + //// --- End LibAFL code --- + tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1); gen_op_st_rm_T0_A0(s1, ot, d); } @@ -1488,6 +1501,13 @@ static void gen_op(DisasContext *s1, int op, MemOp ot, int d) case OP_CMPL: tcg_gen_mov_tl(cpu_cc_src, s1->T1); tcg_gen_mov_tl(s1->cc_srcT, s1->T0); + + //// --- Begin LibAFL code --- + + libafl_gen_cmp(s1->pc, s1->T0, s1->T1, ot); + + //// --- End LibAFL code --- + tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1); set_cc_op(s1, CC_OP_SUBB + ot); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c754396575..5393e4ea22 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2860,6 +2860,13 @@ static inline void plugin_gen_mem_callbacks(TCGv vaddr, uint16_t info) #endif } +//// --- Begin LibAFL code --- + +void libafl_gen_read(TCGv addr, MemOp ot); +void libafl_gen_write(TCGv addr, MemOp ot); + +//// --- End LibAFL code --- + void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) { MemOp orig_memop; @@ -2879,6 +2886,13 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) } addr = plugin_prep_mem_callbacks(addr); + +//// --- Begin LibAFL code --- + + libafl_gen_read(addr, memop); + +//// --- End LibAFL code --- + gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx); plugin_gen_mem_callbacks(addr, info); @@ -2924,6 +2938,13 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) } addr = plugin_prep_mem_callbacks(addr); + +//// --- Begin LibAFL code --- + + libafl_gen_write(addr, memop); + +//// --- End LibAFL code --- + if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) { gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx); } else { @@ -2966,6 +2987,13 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) } addr = plugin_prep_mem_callbacks(addr); + +//// --- Begin LibAFL code --- + + libafl_gen_read(addr, memop); + +//// --- End LibAFL code --- + gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx); plugin_gen_mem_callbacks(addr, info); @@ -3024,6 +3052,13 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) } addr = plugin_prep_mem_callbacks(addr); + +//// --- Begin LibAFL code --- + + libafl_gen_write(addr, memop); + +//// --- End LibAFL code --- + gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx); plugin_gen_mem_callbacks(addr, info); 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;