Skip to content

Commit 21dd437

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 a04e125 commit 21dd437

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
mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"]
134137
mshv3 = ["dep:mshv-bindings3", "dep:mshv-ioctls3"]

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::{
@@ -525,6 +532,19 @@ impl Debug for HypervLinuxDriver {
525532
}
526533
}
527534

535+
#[cfg(feature = "unwind_guest")]
536+
impl From<TraceRegister> for hv_register_name {
537+
fn from(r: TraceRegister) -> Self {
538+
match r {
539+
TraceRegister::RAX => hv_register_name_HV_X64_REGISTER_RAX,
540+
TraceRegister::RCX => hv_register_name_HV_X64_REGISTER_RCX,
541+
TraceRegister::RIP => hv_register_name_HV_X64_REGISTER_RIP,
542+
TraceRegister::RSP => hv_register_name_HV_X64_REGISTER_RSP,
543+
TraceRegister::RBP => hv_register_name_HV_X64_REGISTER_RBP,
544+
}
545+
}
546+
}
547+
528548
impl Hypervisor for HypervLinuxDriver {
529549
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
530550
fn initialise(
@@ -1071,6 +1091,17 @@ impl Hypervisor for HypervLinuxDriver {
10711091

10721092
Ok(())
10731093
}
1094+
1095+
#[cfg(feature = "unwind_guest")]
1096+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1097+
let mut assoc = [hv_register_assoc {
1098+
name: reg.into(),
1099+
..Default::default()
1100+
}];
1101+
self.vcpu_fd.get_reg(&mut assoc)?;
1102+
// safety: all registers that we currently support are 64-bit
1103+
unsafe { Ok(assoc[0].value.reg64) }
1104+
}
10741105
}
10751106

10761107
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
@@ -41,6 +41,8 @@ use {
4141
std::sync::Mutex,
4242
};
4343

44+
#[cfg(feature = "unwind_guest")]
45+
use super::TraceRegister;
4446
use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
4547
use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
4648
use super::surrogate_process::SurrogateProcess;
@@ -1034,6 +1036,18 @@ impl Hypervisor for HypervWindowsDriver {
10341036

10351037
Ok(())
10361038
}
1039+
1040+
#[cfg(feature = "unwind_guest")]
1041+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1042+
let regs = self.processor.get_regs()?;
1043+
match reg {
1044+
TraceRegister::RAX => Ok(regs.rax),
1045+
TraceRegister::RCX => Ok(regs.rcx),
1046+
TraceRegister::RIP => Ok(regs.rip),
1047+
TraceRegister::RSP => Ok(regs.rsp),
1048+
TraceRegister::RBP => Ok(regs.rbp),
1049+
}
1050+
}
10371051
}
10381052

10391053
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};
@@ -946,6 +948,18 @@ impl Hypervisor for KVMDriver {
946948

947949
Ok(())
948950
}
951+
952+
#[cfg(feature = "unwind_guest")]
953+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
954+
let regs = self.vcpu_fd.get_regs()?;
955+
Ok(match reg {
956+
TraceRegister::RAX => regs.rax,
957+
TraceRegister::RCX => regs.rcx,
958+
TraceRegister::RIP => regs.rip,
959+
TraceRegister::RSP => regs.rsp,
960+
TraceRegister::RBP => regs.rbp,
961+
})
962+
}
949963
}
950964

951965
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)