Skip to content

Commit 94a699a

Browse files
committed
Handle incoming TraceRecords in the host and send traces from key places in the guest
Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
1 parent bfb17d5 commit 94a699a

File tree

11 files changed

+118
-6
lines changed

11 files changed

+118
-6
lines changed

src/hyperlight_guest/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ Provides only the essential building blocks for interacting with the host enviro
1515
anyhow = { version = "1.0.98", default-features = false }
1616
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
1717
hyperlight-common = { workspace = true }
18+
hyperlight-guest-tracing = { workspace = true, optional = true }
19+
hyperlight-guest-tracing-macro = { workspace = true}
20+
21+
[features]
22+
default = []
23+
trace_guest = ["dep:hyperlight-guest-tracing"]

src/hyperlight_guest/src/exit.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ use hyperlight_common::outb::OutBAction;
2121

2222
/// Halt the execution of the guest and returns control to the host.
2323
#[inline(never)]
24+
#[hyperlight_guest_tracing_macro::trace_function]
2425
pub fn halt() {
2526
unsafe { asm!("hlt", options(nostack)) }
2627
}
2728

2829
/// Exits the VM with an Abort OUT action and code 0.
2930
#[unsafe(no_mangle)]
31+
#[hyperlight_guest_tracing_macro::trace_function]
3032
pub extern "C" fn abort() -> ! {
3133
abort_with_code(&[0, 0xFF])
3234
}
3335

3436
/// Exits the VM with an Abort OUT action and a specific code.
37+
#[hyperlight_guest_tracing_macro::trace_function]
3538
pub fn abort_with_code(code: &[u8]) -> ! {
3639
outb(OutBAction::Abort as u16, code);
3740
outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code)
@@ -42,6 +45,7 @@ pub fn abort_with_code(code: &[u8]) -> ! {
4245
///
4346
/// # Safety
4447
/// This function is unsafe because it dereferences a raw pointer.
48+
#[hyperlight_guest_tracing_macro::trace_function]
4549
pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! {
4650
unsafe {
4751
// Step 1: Send abort code (typically 1 byte, but `code` allows flexibility)
@@ -63,6 +67,7 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha
6367

6468
/// OUT bytes to the host through multiple exits.
6569
pub(crate) fn outb(port: u16, data: &[u8]) {
70+
hyperlight_guest_tracing_macro::flush!();
6671
unsafe {
6772
let mut i = 0;
6873
while i < data.len() {

src/hyperlight_guest/src/guest_handle/host_comm.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use crate::exit::out32;
3535

3636
impl GuestHandle {
3737
/// Get user memory region as bytes.
38+
#[hyperlight_guest_tracing_macro::trace_function]
3839
pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result<Vec<u8>> {
3940
let peb_ptr = self.peb().unwrap();
4041
let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 };
@@ -83,6 +84,7 @@ impl GuestHandle {
8384
///
8485
/// Note: The function return value must be obtained by calling
8586
/// `get_host_return_value`.
87+
#[hyperlight_guest_tracing_macro::trace_function]
8688
pub fn call_host_function_without_returning_result(
8789
&self,
8890
function_name: &str,
@@ -114,6 +116,7 @@ impl GuestHandle {
114116
/// sends it to the host, and then retrieves the return value.
115117
///
116118
/// The return value is deserialized into the specified type `T`.
119+
#[hyperlight_guest_tracing_macro::trace_function]
117120
pub fn call_host_function<T: TryFrom<ReturnValue>>(
118121
&self,
119122
function_name: &str,
@@ -155,6 +158,7 @@ impl GuestHandle {
155158
}
156159

157160
/// Log a message with the specified log level, source, caller, source file, and line number.
161+
#[hyperlight_guest_tracing_macro::trace_function]
158162
pub fn log_message(
159163
&self,
160164
log_level: LogLevel,

src/hyperlight_guest/src/guest_handle/io.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::error::{HyperlightGuestError, Result};
2727

2828
impl GuestHandle {
2929
/// Pops the top element from the shared input data buffer and returns it as a T
30+
#[hyperlight_guest_tracing_macro::trace_function]
3031
pub fn try_pop_shared_input_data_into<T>(&self) -> Result<T>
3132
where
3233
T: for<'a> TryFrom<&'a [u8]>,
@@ -88,6 +89,7 @@ impl GuestHandle {
8889
}
8990

9091
/// Pushes the given data onto the shared output data buffer.
92+
#[hyperlight_guest_tracing_macro::trace_function]
9193
pub fn push_shared_output_data(&self, data: Vec<u8>) -> Result<()> {
9294
let peb_ptr = self.peb().unwrap();
9395
let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize };

src/hyperlight_guest_bin/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ and third-party code used by our C-API needed to build a native hyperlight-guest
1717
default = ["libc", "printf"]
1818
libc = [] # compile musl libc
1919
printf = [] # compile printf
20+
trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing-macro", "dep:hyperlight-guest-tracing", "hyperlight-guest/trace_guest"]
2021
mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"]
2122

2223
[dependencies]
2324
hyperlight-guest = { workspace = true, default-features = false }
2425
hyperlight-common = { workspace = true, default-features = false }
26+
hyperlight-guest-tracing = { workspace = true, optional = true }
27+
hyperlight-guest-tracing-macro = { workspace = true, optional = true }
2528
buddy_system_allocator = "0.11.0"
2629
log = { version = "0.4", default-features = false }
2730
spin = "0.10.0"

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS};
2727

2828
type GuestFunc = fn(&FunctionCall) -> Result<Vec<u8>>;
2929

30+
#[hyperlight_guest_tracing_macro::trace_function]
3031
pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>> {
3132
// Validate this is a Guest Function Call
3233
if function_call.function_call_type() != FunctionCallType::Guest {
@@ -99,6 +100,7 @@ fn internal_dispatch_function() -> Result<()> {
99100
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()
100101
// which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return
101102
// when running in the hypervisor.
103+
#[hyperlight_guest_tracing_macro::trace_function]
102104
pub(crate) extern "C" fn dispatch_function() {
103105
let _ = internal_dispatch_function();
104106
halt();

src/hyperlight_guest_bin/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use hyperlight_common::mem::HyperlightPEB;
3232
use hyperlight_common::outb::OutBAction;
3333
use hyperlight_guest::exit::{abort_with_code_and_message, halt};
3434
use hyperlight_guest::guest_handle::handle::GuestHandle;
35+
use hyperlight_guest_tracing_macro::{trace, trace_function};
3536
use log::LevelFilter;
3637
use spin::Once;
3738

@@ -154,6 +155,7 @@ unsafe extern "C" {
154155
static INIT: Once = Once::new();
155156

156157
#[unsafe(no_mangle)]
158+
#[trace_function]
157159
pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) {
158160
if peb_address == 0 {
159161
panic!("PEB address is null");
@@ -203,6 +205,7 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve
203205

204206
(*peb_ptr).guest_function_dispatch_ptr = dispatch_function as usize as u64;
205207

208+
trace!("hyperlight_main");
206209
hyperlight_main();
207210
}
208211
});

src/hyperlight_host/src/sandbox/outb.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,41 @@ fn handle_outb_impl(
295295
}
296296
#[cfg(feature = "trace_guest")]
297297
OutBAction::TraceRecord => {
298+
let Ok(len) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else {
299+
return Ok(());
300+
};
301+
let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else {
302+
return Ok(());
303+
};
304+
let mut buffer = vec![0u8; len as usize * std::mem::size_of::<TraceRecord>()];
305+
let buffer = &mut buffer[..];
306+
307+
// Read the trace records from the guest memory
308+
// TODO: maybe this can be done without copying?
309+
mem_mgr
310+
.as_ref()
311+
.shared_mem
312+
.copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS)
313+
// .read::<u64>((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize)
314+
.map_err(|e| {
315+
new_error!(
316+
"Failed to copy trace records from guest memory to host: {:?}",
317+
e
318+
)
319+
})?;
320+
321+
let traces = unsafe {
322+
std::slice::from_raw_parts(buffer.as_ptr() as *const TraceRecord, len as usize)
323+
};
324+
325+
for record in traces {
326+
record_trace_frame(&_trace_info, 4u64, |f| {
327+
let _ = f.write_all(&record.cycles.to_ne_bytes());
328+
let _ = f.write_all(&record.msg_len.to_ne_bytes());
329+
let _ = f.write_all(&record.msg[..record.msg_len]);
330+
})?
331+
}
332+
298333
Ok(())
299334
}
300335
}

src/tests/rust_guests/callbackguest/Cargo.lock

Lines changed: 14 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tests/rust_guests/simpleguest/Cargo.lock

Lines changed: 23 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)