Skip to content

Commit a7b3e39

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 bb51a9b commit a7b3e39

File tree

5 files changed

+82
-1
lines changed

5 files changed

+82
-1
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::{
@@ -523,6 +530,19 @@ impl Debug for HypervLinuxDriver {
523530
}
524531
}
525532

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

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

10391070
impl Drop for HypervLinuxDriver {

src/hyperlight_host/src/hypervisor/hyperv_windows.rs

Lines changed: 15 additions & 1 deletion
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;
@@ -61,7 +63,7 @@ use crate::mem::ptr::{GuestPtr, RawPtr};
6163
use crate::sandbox::TraceInfo;
6264
#[cfg(crashdump)]
6365
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
64-
use crate::{Result, debug, log_then_return, new_error};
66+
use crate::{Result, debug, new_error};
6567

6668
#[cfg(gdb)]
6769
mod debug {
@@ -1019,6 +1021,18 @@ impl Hypervisor for HypervWindowsDriver {
10191021

10201022
Ok(())
10211023
}
1024+
1025+
#[cfg(feature = "unwind_guest")]
1026+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
1027+
let regs = self.processor.get_regs()?;
1028+
match reg {
1029+
TraceRegister::RAX => Ok(regs.rax),
1030+
TraceRegister::RCX => Ok(regs.rcx),
1031+
TraceRegister::RIP => Ok(regs.rip),
1032+
TraceRegister::RSP => Ok(regs.rsp),
1033+
TraceRegister::RBP => Ok(regs.rbp),
1034+
}
1035+
}
10221036
}
10231037

10241038
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};
@@ -931,6 +933,18 @@ impl Hypervisor for KVMDriver {
931933

932934
Ok(())
933935
}
936+
937+
#[cfg(feature = "unwind_guest")]
938+
fn read_trace_reg(&self, reg: TraceRegister) -> Result<u64> {
939+
let regs = self.vcpu_fd.get_regs()?;
940+
Ok(match reg {
941+
TraceRegister::RAX => regs.rax,
942+
TraceRegister::RCX => regs.rcx,
943+
TraceRegister::RIP => regs.rip,
944+
TraceRegister::RSP => regs.rsp,
945+
TraceRegister::RBP => regs.rbp,
946+
})
947+
}
934948
}
935949

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