Skip to content

Commit 896fbea

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 41483d5 commit 896fbea

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-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::{
@@ -522,6 +529,19 @@ impl Debug for HypervLinuxDriver {
522529
}
523530
}
524531

532+
#[cfg(feature = "unwind_guest")]
533+
impl From<TraceRegister> for hv_register_name {
534+
fn from(r: TraceRegister) -> Self {
535+
match r {
536+
TraceRegister::RAX => hv_register_name_HV_X64_REGISTER_RAX,
537+
TraceRegister::RCX => hv_register_name_HV_X64_REGISTER_RCX,
538+
TraceRegister::RIP => hv_register_name_HV_X64_REGISTER_RIP,
539+
TraceRegister::RSP => hv_register_name_HV_X64_REGISTER_RSP,
540+
TraceRegister::RBP => hv_register_name_HV_X64_REGISTER_RBP,
541+
}
542+
}
543+
}
544+
525545
impl Hypervisor for HypervLinuxDriver {
526546
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
527547
fn initialise(
@@ -1037,6 +1057,17 @@ impl Hypervisor for HypervLinuxDriver {
10371057

10381058
Ok(())
10391059
}
1060+
1061+
#[cfg(feature = "unwind_guest")]
1062+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1063+
let mut assoc = [hv_register_assoc {
1064+
name: reg.into(),
1065+
..Default::default()
1066+
}];
1067+
self.vcpu_fd.get_reg(&mut assoc)?;
1068+
// safety: all registers that we currently support are 64-bit
1069+
unsafe { Ok(assoc[0].value.reg64) }
1070+
}
10401071
}
10411072

10421073
impl Drop for HypervLinuxDriver {

src/hyperlight_host/src/hypervisor/hyperv_windows.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
2222

2323
use log::LevelFilter;
2424
use tracing::{Span, instrument};
25+
#[cfg(feature = "trace_guest")]
26+
use windows::Win32::System::Hypervisor::WHV_REGISTER_NAME;
2527
use windows::Win32::System::Hypervisor::{
2628
WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_REGISTER_VALUE, WHV_RUN_VP_EXIT_CONTEXT,
2729
WHV_RUN_VP_EXIT_REASON, WHV_X64_SEGMENT_REGISTER, WHV_X64_SEGMENT_REGISTER_0,
@@ -41,6 +43,8 @@ use {
4143
std::sync::Mutex,
4244
};
4345

46+
#[cfg(feature = "unwind_guest")]
47+
use super::TraceRegister;
4448
use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
4549
use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
4650
use super::surrogate_process::SurrogateProcess;
@@ -571,6 +575,19 @@ impl Debug for HypervWindowsDriver {
571575
}
572576
}
573577

578+
#[cfg(feature = "trace_guest")]
579+
impl From<TraceRegister> for WHV_REGISTER_NAME {
580+
fn from(r: TraceRegister) -> Self {
581+
match r {
582+
TraceRegister::RAX => windows::Win32::System::Hypervisor::WHvX64RegisterRax,
583+
TraceRegister::RCX => windows::Win32::System::Hypervisor::WHvX64RegisterRcx,
584+
TraceRegister::RIP => windows::Win32::System::Hypervisor::WHvX64RegisterRip,
585+
TraceRegister::RSP => windows::Win32::System::Hypervisor::WHvX64RegisterRsp,
586+
TraceRegister::RBP => windows::Win32::System::Hypervisor::WHvX64RegisterRbp,
587+
}
588+
}
589+
}
590+
574591
impl Hypervisor for HypervWindowsDriver {
575592
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
576593
fn initialise(
@@ -1022,6 +1039,23 @@ impl Hypervisor for HypervWindowsDriver {
10221039

10231040
Ok(())
10241041
}
1042+
1043+
#[cfg(feature = "unwind_guest")]
1044+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1045+
let register_names = [WHV_REGISTER_NAME::from(reg)];
1046+
let mut register_values: [WHV_REGISTER_VALUE; 1] = Default::default();
1047+
unsafe {
1048+
WHvGetVirtualProcessorRegisters(
1049+
self.get_partition_hdl(),
1050+
0,
1051+
register_names.as_ptr(),
1052+
register_names.len() as u32,
1053+
register_values.as_mut_ptr(),
1054+
)?;
1055+
// safety: all registers that we currently support are 64-bit
1056+
Ok(register_values[0].Reg64)
1057+
}
1058+
}
10251059
}
10261060

10271061
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};
@@ -934,6 +936,18 @@ impl Hypervisor for KVMDriver {
934936

935937
Ok(())
936938
}
939+
940+
#[cfg(feature = "unwind_guest")]
941+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
942+
let regs = self.vcpu_fd.get_regs()?;
943+
Ok(match reg {
944+
TraceRegister::RAX => regs.rax,
945+
TraceRegister::RCX => regs.rcx,
946+
TraceRegister::RIP => regs.rip,
947+
TraceRegister::RSP => regs.rsp,
948+
TraceRegister::RBP => regs.rbp,
949+
})
950+
}
937951
}
938952

939953
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
@@ -242,6 +257,10 @@ pub(crate) trait Hypervisor: Debug + Sync + Send {
242257
) -> Result<()> {
243258
unimplemented!()
244259
}
260+
261+
/// Read a register for trace/unwind purposes
262+
#[cfg(feature = "unwind_guest")]
263+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64>;
245264
}
246265

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

0 commit comments

Comments
 (0)