Skip to content

Commit 77c6ce7

Browse files
syntacticallydblnz
authored andcommitted
[hyperlight_host/trace] Add HV interface for reading trace registers
This adds a new interface which tracing code can use to request the values of registers from the hypervisor supervising a sandbox. Signed-off-by: Lucy Menon <[email protected]>
1 parent 21cf19b commit 77c6ce7

File tree

5 files changed

+81
-0
lines changed

5 files changed

+81
-0
lines changed

src/hyperlight_host/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ print_debug = []
129129
# Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged.
130130
crashdump = ["dep:chrono"]
131131
trace_guest = []
132+
# This feature enables unwinding the guest stack from the host, in
133+
# order to produce stack traces for debugging or profiling.
134+
unwind_guest = [ "trace_guest" ]
132135
kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"]
133136
# This feature is deprecated in favor of mshv3
134137
mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"]

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,18 @@ use mshv_bindings::{
4848
hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES,
4949
hv_partition_synthetic_processor_features,
5050
};
51+
#[cfg(feature = "unwind_guest")]
52+
use mshv_bindings::{
53+
hv_register_name, hv_register_name_HV_X64_REGISTER_RAX, hv_register_name_HV_X64_REGISTER_RBP,
54+
hv_register_name_HV_X64_REGISTER_RCX, hv_register_name_HV_X64_REGISTER_RSP,
55+
};
5156
use mshv_ioctls::{Mshv, MshvError, VcpuFd, VmFd};
5257
use tracing::{Span, instrument};
5358
#[cfg(crashdump)]
5459
use {super::crashdump, std::path::Path};
5560

61+
#[cfg(feature = "unwind_guest")]
62+
use super::TraceRegister;
5663
use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
5764
#[cfg(gdb)]
5865
use super::gdb::{
@@ -547,6 +554,19 @@ impl Debug for HypervLinuxDriver {
547554
}
548555
}
549556

557+
#[cfg(feature = "unwind_guest")]
558+
impl From<TraceRegister> for hv_register_name {
559+
fn from(r: TraceRegister) -> Self {
560+
match r {
561+
TraceRegister::RAX => hv_register_name_HV_X64_REGISTER_RAX,
562+
TraceRegister::RCX => hv_register_name_HV_X64_REGISTER_RCX,
563+
TraceRegister::RIP => hv_register_name_HV_X64_REGISTER_RIP,
564+
TraceRegister::RSP => hv_register_name_HV_X64_REGISTER_RSP,
565+
TraceRegister::RBP => hv_register_name_HV_X64_REGISTER_RBP,
566+
}
567+
}
568+
}
569+
550570
impl Hypervisor for HypervLinuxDriver {
551571
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
552572
fn initialise(
@@ -1093,6 +1113,17 @@ impl Hypervisor for HypervLinuxDriver {
10931113

10941114
Ok(())
10951115
}
1116+
1117+
#[cfg(feature = "unwind_guest")]
1118+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1119+
let mut assoc = [hv_register_assoc {
1120+
name: reg.into(),
1121+
..Default::default()
1122+
}];
1123+
self.vcpu_fd.get_reg(&mut assoc)?;
1124+
// safety: all registers that we currently support are 64-bit
1125+
unsafe { Ok(assoc[0].value.reg64) }
1126+
}
10961127
}
10971128

10981129
impl Drop for HypervLinuxDriver {

src/hyperlight_host/src/hypervisor/hyperv_windows.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ use {
4444
std::sync::Mutex,
4545
};
4646

47+
#[cfg(feature = "unwind_guest")]
48+
use super::TraceRegister;
4749
use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
4850
use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
4951
use super::surrogate_process::SurrogateProcess;
@@ -1043,6 +1045,18 @@ impl Hypervisor for HypervWindowsDriver {
10431045

10441046
Ok(())
10451047
}
1048+
1049+
#[cfg(feature = "unwind_guest")]
1050+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1051+
let regs = self.processor.get_regs()?;
1052+
match reg {
1053+
TraceRegister::RAX => Ok(regs.rax),
1054+
TraceRegister::RCX => Ok(regs.rcx),
1055+
TraceRegister::RIP => Ok(regs.rip),
1056+
TraceRegister::RSP => Ok(regs.rsp),
1057+
TraceRegister::RBP => Ok(regs.rbp),
1058+
}
1059+
}
10461060
}
10471061

10481062
impl Drop for HypervWindowsDriver {

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ use tracing::{Span, instrument};
2929
#[cfg(crashdump)]
3030
use {super::crashdump, std::path::Path};
3131

32+
#[cfg(feature = "unwind_guest")]
33+
use super::TraceRegister;
3234
use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
3335
#[cfg(gdb)]
3436
use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason};
@@ -962,6 +964,18 @@ impl Hypervisor for KVMDriver {
962964

963965
Ok(())
964966
}
967+
968+
#[cfg(feature = "unwind_guest")]
969+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
970+
let regs = self.vcpu_fd.get_regs()?;
971+
Ok(match reg {
972+
TraceRegister::RAX => regs.rax,
973+
TraceRegister::RCX => regs.rcx,
974+
TraceRegister::RIP => regs.rip,
975+
TraceRegister::RSP => regs.rsp,
976+
TraceRegister::RBP => regs.rbp,
977+
})
978+
}
965979
}
966980

967981
impl Drop for KVMDriver {

src/hyperlight_host/src/hypervisor/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,21 @@ pub enum HyperlightExit {
116116
Retry(),
117117
}
118118

119+
/// Registers which may be useful for tracing/stack unwinding
120+
#[cfg(feature = "trace_guest")]
121+
pub enum TraceRegister {
122+
/// RAX
123+
RAX,
124+
/// RCX
125+
RCX,
126+
/// RIP
127+
RIP,
128+
/// RSP
129+
RSP,
130+
/// RBP
131+
RBP,
132+
}
133+
119134
/// A common set of hypervisor functionality
120135
pub(crate) trait Hypervisor: Debug + Sync + Send {
121136
/// Initialise the internally stored vCPU with the given PEB address and
@@ -251,6 +266,10 @@ pub(crate) trait Hypervisor: Debug + Sync + Send {
251266
) -> Result<()> {
252267
unimplemented!()
253268
}
269+
270+
/// Read a register for trace/unwind purposes
271+
#[cfg(feature = "unwind_guest")]
272+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64>;
254273
}
255274

256275
/// A virtual CPU that can be run until an exit occurs

0 commit comments

Comments
 (0)