diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index bccb1b2411..027f125aae 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -61,7 +61,11 @@ static void *kvm_vcpu_thread_fn(void *arg) if (cpu_can_run(cpu)) { r = kvm_cpu_exec(cpu); if (r == EXCP_DEBUG) { - cpu_handle_guest_debug(cpu); +//// --- Begin LibAFL code --- + // cpu_handle_guest_debug(cpu); + cpu->stopped = true; + libafl_qemu_trigger_breakpoint(cpu); +//// --- End LibAFL code --- } } qemu_wait_io_event(cpu); diff --git a/gdbstub/system.c b/gdbstub/system.c index feee467fa9..4500d393bf 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -33,6 +33,7 @@ //// --- Begin LibAFL code --- #include "libafl/gdb.h" +#include "gdbstub/enums.h" //// --- End LibAFL code --- /* System emulation specific state */ @@ -655,6 +656,12 @@ bool gdb_supports_guest_debug(void) int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) { const AccelOpsClass *ops = cpus_get_accel(); + //// --- Begin LibAFL code --- + // HW breakpoints are reserved for LibAFL + if (type == GDB_BREAKPOINT_HW) { + return -ENOSYS; + } + //// --- End LibAFL code --- if (ops->insert_breakpoint) { return ops->insert_breakpoint(cs, type, addr, len); } diff --git a/include/libafl/system.h b/include/libafl/system.h index 454d45b9f4..9a6e9c6d4d 100644 --- a/include/libafl/system.h +++ b/include/libafl/system.h @@ -1,3 +1,11 @@ #pragma once +#include "hw/core/cpu.h" +#include "gdbstub/enums.h" +#include "sysemu/accel-ops.h" +#include "sysemu/cpus.h" + +int libafl_qemu_set_hw_breakpoint(vaddr addr); +int libafl_qemu_remove_hw_breakpoint(vaddr addr); + void libafl_qemu_init(int argc, char** argv); diff --git a/libafl/system.c b/libafl/system.c index f22c0973c6..5177d47f31 100644 --- a/libafl/system.c +++ b/libafl/system.c @@ -3,4 +3,42 @@ #include "libafl/system.h" +int libafl_qemu_toggle_hw_breakpoint(vaddr addr, bool set); + void libafl_qemu_init(int argc, char** argv) { qemu_init(argc, argv); } + +int libafl_qemu_set_hw_breakpoint(vaddr addr) +{ + return libafl_qemu_toggle_hw_breakpoint(addr, true); +} + +int libafl_qemu_remove_hw_breakpoint(vaddr addr) +{ + return libafl_qemu_toggle_hw_breakpoint(addr, false); +} + +int libafl_qemu_toggle_hw_breakpoint(vaddr addr, bool set) { + const int type = GDB_BREAKPOINT_HW; + const vaddr len = 1; + const AccelOpsClass *ops = cpus_get_accel(); + + CPUState *cs = first_cpu; + int ret = 0; + + if (!ops->insert_breakpoint) { + return -ENOSYS; + } + + // let's add/remove the breakpoint on the first CPU. + // Both TCG and KVM propagate it to all CPUs internally. + if (set) { + ret = ops->insert_breakpoint(cs, type, addr, len); + } else { + ret = ops->remove_breakpoint(cs, type, addr, len); + } + if (ret != 0) { + return ret; + } + + return 0; +}