Skip to content

Commit 82c95f2

Browse files
committed
gdb: update mshv hypervisor to use the arch specific logic to determine stop reason
Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent edd59e9 commit 82c95f2

File tree

2 files changed

+41
-38
lines changed

2 files changed

+41
-38
lines changed

src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use mshv_bindings::{
3232
};
3333
use mshv_ioctls::VcpuFd;
3434

35-
use super::arch::{DR6_BS_FLAG_MASK, DR6_HW_BP_FLAGS_MASK, MAX_NO_OF_HW_BP, SW_BP_SIZE};
35+
use super::arch::{vcpu_stop_reason, MAX_NO_OF_HW_BP, SW_BP_SIZE};
3636
use super::{GuestDebug, VcpuStopReason, X86_64Regs};
3737
use crate::{new_error, HyperlightError, Result};
3838

@@ -131,52 +131,38 @@ impl MshvDebug {
131131
pub(crate) fn get_stop_reason(
132132
&mut self,
133133
vcpu_fd: &VcpuFd,
134+
exception: u16,
134135
entrypoint: u64,
135136
) -> Result<VcpuStopReason> {
136-
// MSHV does not provide info on the vCPU exits but the debug
137-
// information can be retrieved from the DEBUG REGISTERS
138137
let regs = vcpu_fd
139138
.get_debug_regs()
140139
.map_err(|e| new_error!("Cannot retrieve debug registers from vCPU: {}", e))?;
141140

142141
// DR6 register contains debug state related information
143142
let debug_status = regs.dr6;
144143

145-
// If the BS flag in DR6 register is set, it means a single step
146-
// instruction triggered the exit
147-
// Check page 19-4 Vol. 3B of Intel 64 and IA-32
148-
// Architectures Software Developer's Manual
149-
if debug_status & DR6_BS_FLAG_MASK != 0 && self.single_step {
150-
return Ok(VcpuStopReason::DoneStep);
151-
}
144+
let rip = self.get_instruction_pointer(vcpu_fd)?;
145+
let rip = self.translate_gva(vcpu_fd, rip)?;
152146

153-
let ip = self.get_instruction_pointer(vcpu_fd)?;
154-
let gpa = self.translate_gva(vcpu_fd, ip)?;
147+
let reason = vcpu_stop_reason(
148+
self.single_step,
149+
rip,
150+
debug_status,
151+
entrypoint,
152+
exception as u32,
153+
&self.hw_breakpoints,
154+
&self.sw_breakpoints,
155+
);
155156

156-
// If any of the B0-B3 flags in DR6 register is set, it means a
157-
// hardware breakpoint triggered the exit
158-
// Check page 19-4 Vol. 3B of Intel 64 and IA-32
159-
// Architectures Software Developer's Manual
160-
if debug_status & DR6_HW_BP_FLAGS_MASK != 0 && self.hw_breakpoints.contains(&gpa) {
157+
if let VcpuStopReason::EntryPointBp = reason {
161158
// In case the hw breakpoint is the entry point, remove it to
162159
// avoid hanging here as gdb does not remove breakpoints it
163160
// has not set.
164161
// Gdb expects the target to be stopped when connected.
165-
if gpa == entrypoint {
166-
self.remove_hw_breakpoint(vcpu_fd, entrypoint)?;
167-
}
168-
return Ok(VcpuStopReason::HwBp);
169-
}
170-
171-
// mshv does not provide a way to specify which exception triggered the
172-
// vCPU exit as the mshv intercepts both #DB and #BP
173-
// We check against the SW breakpoints Hashmap to detect whether the
174-
// vCPU exited due to a SW breakpoint
175-
if self.sw_breakpoints.contains_key(&gpa) {
176-
return Ok(VcpuStopReason::SwBp);
162+
self.remove_hw_breakpoint(vcpu_fd, entrypoint)?;
177163
}
178164

179-
Ok(VcpuStopReason::Unknown)
165+
Ok(reason)
180166
}
181167
}
182168

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ use crate::{log_then_return, new_error, Result};
7171
mod debug {
7272
use std::sync::{Arc, Mutex};
7373

74+
use super::mshv_bindings::hv_x64_exception_intercept_message;
7475
use super::{HypervLinuxDriver, *};
7576
use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs};
7677
use crate::hypervisor::handlers::DbgMemAccessHandlerCaller;
@@ -89,13 +90,16 @@ mod debug {
8990
}
9091

9192
/// Get the reason the vCPU has stopped
92-
pub(crate) fn get_stop_reason(&mut self) -> Result<VcpuStopReason> {
93+
pub(crate) fn get_stop_reason(
94+
&mut self,
95+
ex_info: hv_x64_exception_intercept_message,
96+
) -> Result<VcpuStopReason> {
9397
let debug = self
9498
.debug
9599
.as_mut()
96100
.ok_or_else(|| new_error!("Debug is not enabled"))?;
97101

98-
debug.get_stop_reason(&self.vcpu_fd, self.entrypoint)
102+
debug.get_stop_reason(&self.vcpu_fd, ex_info.exception_vector, self.entrypoint)
99103
}
100104

101105
pub(crate) fn process_dbg_request(
@@ -626,14 +630,27 @@ impl Hypervisor for HypervLinuxDriver {
626630
}
627631
}
628632
// The only case an intercept exit is expected is when debugging is enabled
629-
// and the intercepts are installed
633+
// and the intercepts are installed.
634+
// Provide the extra information about the exception to accurately determine
635+
// the stop reason
630636
#[cfg(gdb)]
631-
EXCEPTION_INTERCEPT => match self.get_stop_reason() {
632-
Ok(reason) => HyperlightExit::Debug(reason),
633-
Err(e) => {
634-
log_then_return!("Error getting stop reason: {:?}", e);
637+
EXCEPTION_INTERCEPT => {
638+
// Extract exception info from the message so we can figure out
639+
// more information about the vCPU state
640+
let ex_info = match m.to_exception_info() {
641+
Ok(info) => info,
642+
Err(e) => {
643+
log_then_return!("Error converting to exception info: {:?}", e);
644+
}
645+
};
646+
647+
match self.get_stop_reason(ex_info) {
648+
Ok(reason) => HyperlightExit::Debug(reason),
649+
Err(e) => {
650+
log_then_return!("Error getting stop reason: {:?}", e);
651+
}
635652
}
636-
},
653+
}
637654
other => {
638655
crate::debug!("mshv Other Exit: Exit: {:#?} \n {:#?}", other, &self);
639656
log_then_return!("unknown Hyper-V run message type {:?}", other);

0 commit comments

Comments
 (0)