diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index f62f12e717..da99f517c7 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -487,6 +487,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() diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 49f5de37e8..98b77822cf 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -32,6 +32,19 @@ #include "tcg/tcg.h" #include "exec/tb-lookup.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 91a5b7e85f..74bcc6d3f1 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -331,3 +331,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/translator.c b/accel/tcg/translator.c index 2dfc27102f..fd3e7389b7 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -19,6 +19,17 @@ #include "exec/plugin-gen.h" #include "sysemu/replay.h" +//// --- Begin LibAFL code --- + +struct libafl_breakpoint { + target_ulong addr; + struct libafl_breakpoint* next; +}; + +extern struct libafl_breakpoint* libafl_qemu_breakpoints; + +//// --- 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, @@ -91,6 +102,18 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, } } + //// --- Begin LibAFL code --- + + 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/cpu.c b/cpu.c index bfbe5a66f9..73728ce905 100644 --- a/cpu.c +++ b/cpu.c @@ -37,6 +37,110 @@ #include "exec/translate-all.h" #include "exec/log.h" +//// --- Begin LibAFL code --- + +struct libafl_breakpoint { + target_ulong addr; + struct libafl_breakpoint* next; +}; + +struct libafl_breakpoint* libafl_qemu_breakpoints = NULL; + +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_write_reg(int reg, uint8_t* val) +{ + CPUState *cpu = current_cpu; + 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) { + 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) { + return 0; + } + + CPUClass *cc = CPU_GET_CLASS(cpu); + if (reg < cc->gdb_num_core_regs) { + 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) { + return 0; + } + + CPUClass *cc = CPU_GET_CLASS(cpu); + return cc->gdb_num_core_regs; +} + +static void 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) { + 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; + + target_ulong pc = (target_ulong) addr; + struct libafl_breakpoint** bp = &libafl_qemu_breakpoints; + while (*bp) { + if ((*bp)->addr == pc) { + CPU_FOREACH(cpu) { + breakpoint_invalidate(cpu, pc); + } + + *bp = (*bp)->next; + return 1; + } + bp = &(*bp)->next; + } + return 0; +} + +//// --- End LibAFL code --- + uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; 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 989d03cd89..65ee9bb012 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -240,6 +240,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 f956afccab..ca256b017b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -621,6 +621,27 @@ static int parse_args(int argc, char **argv) return optind; } +//// --- Begin LibAFL code --- + +int libafl_qemu_main(void); +int libafl_qemu_run(void); + +static CPUArchState *libafl_qemu_env; + +__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 --- + int main(int argc, char **argv, char **envp) { struct target_pt_regs regs1, *regs = ®s1; @@ -886,7 +907,16 @@ 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; + + return libafl_qemu_main(); + + //// --- End LibAFL code --- + /* never exits */ - return 0; + // return 0; }