diff --git a/src/hyperlight_host/src/hypervisor/gdb/target.rs b/src/hyperlight_host/src/hypervisor/gdb/target.rs index f85c679e4..a4c8d3e66 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/target.rs @@ -7,6 +7,7 @@ use gdbstub::stub::{BaseStopReason, SingleThreadStopReason}; use gdbstub::target::ext::base::singlethread::{ SingleThreadBase, SingleThreadResume, SingleThreadResumeOps, + SingleThreadSingleStep, SingleThreadSingleStepOps, }; use gdbstub::target::ext::base::BaseOps; use gdbstub::target::ext::breakpoints::{ @@ -101,6 +102,8 @@ pub struct HyperlightKvmSandboxTarget { /// vCPU paused state paused: bool, + /// vCPU stepping state + single_step: bool, /// Array of addresses for HW breakpoints hw_breakpoints: Vec<u64>, @@ -125,6 +128,7 @@ impl HyperlightKvmSandboxTarget { entrypoint, paused: false, + single_step: false, hw_breakpoints: vec![], @@ -146,6 +150,13 @@ impl HyperlightKvmSandboxTarget { /// Get the reason the vCPU has stopped pub fn get_stop_reason(&self) -> Result<Option<BaseStopReason<(), u64>>, GdbTargetError> { + if self.single_step { + return Ok(Some(SingleThreadStopReason::SignalWithThread { + tid: (), + signal: Signal::SIGTRAP, + })); + } + let ip = self.get_instruction_pointer()?; if self.hw_breakpoints.contains(&ip) { @@ -159,6 +170,15 @@ impl HyperlightKvmSandboxTarget { Ok(None) } + fn set_single_step(&mut self, enable: bool) -> Result<(), GdbTargetError> { + self.single_step = enable; + + self.debug + .set_breakpoints(&self.vcpu_fd.lock().unwrap(), &self.hw_breakpoints, enable)?; + + Ok(()) + } + /// This method provides a way to set a breakpoint at the entrypoint /// it does not keep this breakpoint set after the vcpu already stopped at the address pub fn set_entrypoint_bp(&mut self) -> Result<bool, GdbTargetError> { @@ -472,6 +492,20 @@ impl HwBreakpoint for HyperlightKvmSandboxTarget { impl SingleThreadResume for HyperlightKvmSandboxTarget { fn resume(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> { log::debug!("Resume"); + self.set_single_step(false)?; + self.resume_vcpu() + } + fn support_single_step(&mut self) -> Option<SingleThreadSingleStepOps<Self>> { + Some(self) + } +} + +impl SingleThreadSingleStep for HyperlightKvmSandboxTarget { + fn step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> { + assert!(signal.is_none()); + + log::debug!("Step"); + self.set_single_step(true)?; self.resume_vcpu() } } \ No newline at end of file