On Fri, Jul 31, 2026 at 09:46:38PM +0300, Doru Blânzeanu wrote: > This series brings guest debugging to the MSHV accelerator by > implementing software breakpoints and single-stepping, so that gdb can > attach to an MSHV guest through QEMU's gdbstub. > > It follows the KVM gdbstub implementation closely, and borrows the WHPX > approach where the MSHV interface differs from KVM: > > - it installs a partition-wide intercept for the #DB exception > (HVCALL_INSTALL_INTERCEPT). #BP (INT3) is deliberately left to the > guest's own IDT and is never intercepted, as WHPX does. > > - only software breakpoints are supported. A breakpoint is an INT1 > (opcode 0xf1) patched into guest memory, which raises a #DB when > executed. Hardware breakpoints and watchpoints are not supported. > > - it never touches the guest debug registers (DR0-DR7), so guest state > is not clobbered. The only guest register used is RFLAGS.TF, toggled > around the vCPU run for single-stepping and kept out of env->eflags > so it cannot be read back and re-armed. > > - it re-injects the #DB back into the guest (via > HV_REGISTER_PENDING_EVENT0) when the faulting RIP does not match a > debugger breakpoint, so a guest-owned #DB is delivered through the > guest's own IDT. > > When a vCPU is created we register the accel ops that gdb drives once it > is attached: > > - mshv_update_guest_debug > - mshv_insert_gdbstub_breakpoint > - mshv_remove_gdbstub_breakpoint > - mshv_remove_all_gdbstub_breakpoints > > For each insert request from gdb the ops save the original byte at the > target address and patch in 0xf1; on a remove request the saved byte is > restored, after which gdb single-steps over the original instruction and > re-inserts the breakpoint. When the vCPU executes the 0xf1 byte a #DB > vmexits to QEMU. mshv_handle_debug() then checks whether the RIP where > the vCPU stopped matches a breakpoint installed by gdb, or whether > single-stepping is active, and if so reports the stop to gdb. If the RIP > does not match any debugger breakpoint the #DB is assumed to be > guest-owned and is re-injected so the guest can handle it. > > Known limitations: > > - Once installed, the #DB intercept stays for the lifetime > of the VM and every #DB - including those the guest raises itself - > vmexits to QEMU. > > - Because attribution relies on matching the faulting RIP against the > debugger's breakpoint list, a guest that legitimately executes INT1 or > raises its own #DB at an address that also holds a debugger breakpoint > cannot be disambiguated; such overlaps are not expected in practice. > > The series is organised as: > > 1. include/hw/hyperv: add ABI for exception intercepts and pending > events > 2. accel/mshv: add gdbstub software breakpoint support > 3. target/i386/mshv: support single-stepping > 4. accel/mshv: break the vCPU run loop on exit_request > This commit fixes a race condition encountered during testing with guests > that run infinite loops with some debugging opcodes. > > I have tested this patch series by using both a guest that doesn't use > debugging > and one that triggers the #DB and #BP exceptions (#DB is re-injected and #BP > is > not intercepted at all). > > Changes since v1: > - refactored the HVMSG_X64_EXCEPTION_INTERCEPT vmexit handle to be contained > in > a standalone function handle_exception_interrupt > - add new commit that checks the mshv vcpu run loop for exit requests before > re-entering MSHV_RUN_VP. This ensures a busy vCPU doesn't ignore gdb > commands. > > Doru Blânzeanu (4): > include/hw/hyperv: add ABI for exception intercepts and pending events > accel/mshv: add gdbstub software breakpoint support > target/i386/mshv: support single-stepping > accel/mshv: break the vCPU run loop on exit_request > > accel/mshv/mshv-all.c | 175 ++++++++++++++++++++++++++++++++- > include/hw/hyperv/hvgdk_mini.h | 56 +++++++++++ > include/system/mshv_int.h | 14 +++ > target/i386/mshv/mshv-cpu.c | 154 +++++++++++++++++++++++++++++ > 4 files changed, 398 insertions(+), 1 deletion(-) > > -- > 2.53.0
included in mkulke-pull-20261006, skipped 4/4
