diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 5788bedc6..90155bb3d 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -15,8 +15,8 @@ Provides only the essential building blocks for interacting with the host enviro anyhow = { version = "1.0.98", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } -hyperlight-guest-tracing = { workspace = true } +hyperlight-guest-tracing = { workspace = true, default-features = false } [features] default = [] -trace_guest = [] +trace_guest = ["hyperlight-guest-tracing/trace"] diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 83ac2a454..79fad4450 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -17,13 +17,13 @@ and third-party code used by our C-API needed to build a native hyperlight-guest default = ["libc", "printf"] libc = [] # compile musl libc printf = [ "libc" ] # compile printf -trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest"] +trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } hyperlight-common = { workspace = true, default-features = false } -hyperlight-guest-tracing = { workspace = true } +hyperlight-guest-tracing = { workspace = true, default-features = false } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml index 873f9e37d..4e9bf9758 100644 --- a/src/hyperlight_guest_tracing/Cargo.toml +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -10,9 +10,13 @@ readme.workspace = true description = """Provides the tracing functionality for the hyperlight guest.""" [dependencies] -hyperlight-common = { workspace = true, default-features = false, features = ["trace_guest"] } +hyperlight-common = { workspace = true, default-features = false } hyperlight-guest-tracing-macro = { workspace = true } spin = "0.10.0" [lints] workspace = true + +[features] +default = [] +trace = [ "hyperlight-guest-tracing-macro/trace", "hyperlight-common/trace_guest" ] diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index bcf4ee4dd..92902e3da 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -15,30 +15,99 @@ limitations under the License. */ #![no_std] -// === Dependencies === -extern crate alloc; - -use core::mem::MaybeUninit; - -use hyperlight_common::outb::OutBAction; -use spin::Mutex; - -/// Type alias for the function that sends trace records to the host. -type SendToHostFn = fn(u64, &[TraceRecord]); - -/// Global trace buffer for storing trace records. -static TRACE_BUFFER: Mutex> = Mutex::new(TraceBuffer::new(send_to_host)); - -/// Maximum number of entries in the trace buffer. -/// From local testing, 32 entries seems to be a good balance between performance and memory usage. -const MAX_NO_OF_ENTRIES: usize = 32; - -/// Maximum length of a trace message in bytes. -pub const MAX_TRACE_MSG_LEN: usize = 64; - /// Re-export the tracing macros /// This allows users to use the macros without needing to import them explicitly. +/// +/// # Tracing Macros Usage +/// +/// ## The `trace_function` macro can be used to trace function calls. +/// +/// ```rust +/// #[hyperlight_guest_tracing_macro::trace_function] +/// fn my_function() { +/// // // Function body +/// } +/// ``` +/// +/// ## The `trace!` macro can be used to create trace records with a message. +/// +/// ```rust +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("message"); +/// trace!("message", { /* block of code */ }); +/// ``` +/// +/// ## Basic usage: trace with message only +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("hello"); +/// ``` +/// +/// ## Trace with a block, returning a value +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let x = trace!("block", { 42 }); +/// assert_eq!(x, 42); +/// ``` +/// +/// ## Trace with a block using local variables +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let y = 10; +/// let z = trace!("sum", { y + 5 }); +/// assert_eq!(z, 15); +/// ``` +/// +/// ## Trace with a block that returns a reference +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let s = String::from("abc"); +/// let r: &str = trace!("ref", { &s }); +/// assert_eq!(r, "abc"); +/// ``` +/// +/// ## Control flow: `return` inside the block returns from the function +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// fn foo() -> i32 { +/// let _ = trace!("fail", { +/// // This return only exits the closure, not the function `foo`. +/// return 42; +/// }); +/// assert!(false, "This should not be reached"); +/// } +/// ``` +/// +/// ## Control flow: `break` inside the block exits the outer loop +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let mut x = 0; +/// for i in 1..3 { +/// x = i; +/// let _ = trace!("msg", { +/// // This break should exit the loop. +/// break; +/// }); +/// } +/// assert_eq!(x, 1, "Loop should break after the first iteration"); +/// ``` +/// +/// ## Flush the trace buffer +/// ```rust +/// hyperlight_guest_tracing_macro::flush!(); +/// ``` pub use hyperlight_guest_tracing_macro::*; +#[cfg(feature = "trace")] +pub use trace::{create_trace_record, flush_trace_buffer}; + +/// Maximum length of a trace message in bytes. +pub const MAX_TRACE_MSG_LEN: usize = 64; #[derive(Debug, Copy, Clone)] /// Represents a trace record of a guest with a number of cycles and a message. @@ -51,82 +120,6 @@ pub struct TraceRecord { pub msg: [u8; MAX_TRACE_MSG_LEN], } -impl From<&str> for TraceRecord { - fn from(mut msg: &str) -> Self { - if msg.len() > MAX_TRACE_MSG_LEN { - // If the message is too long, truncate it to fit the maximum length - msg = &msg[..MAX_TRACE_MSG_LEN]; - } - - let cycles = invariant_tsc::read_tsc(); - - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), - } - } -} - -/// A buffer for storing trace records. -struct TraceBuffer { - /// The entries in the trace buffer. - entries: [TraceRecord; MAX_NO_OF_ENTRIES], - /// The index where the next entry will be written. - write_index: usize, - /// Function to send the trace records to the host. - send_to_host: F, -} - -impl TraceBuffer { - /// Creates a new `TraceBuffer` with uninitialized entries. - const fn new(f: F) -> Self { - Self { - entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, - write_index: 0, - send_to_host: f, - } - } - - /// Push a new trace record into the buffer. - /// If the buffer is full, it sends the records to the host. - fn push(&mut self, entry: TraceRecord) { - let mut write_index = self.write_index; - - self.entries[write_index] = entry; - write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; - - self.write_index = write_index; - - if write_index == 0 { - // If buffer is full send to host - (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); - } - } - - /// Flush the trace buffer, sending any remaining records to the host. - fn flush(&mut self) { - if self.write_index > 0 { - (self.send_to_host)(self.write_index as u64, &self.entries); - self.write_index = 0; // Reset write index after flushing - } - } -} - -/// Send the trace records to the host. -fn send_to_host(len: u64, records: &[TraceRecord]) { - unsafe { - core::arch::asm!("out dx, al", - in("dx") OutBAction::TraceRecord as u16, - in("rax") len, - in("rcx") records.as_ptr() as u64); - } -} - /// Module for checking invariant TSC support and reading the timestamp counter pub mod invariant_tsc { use core::arch::x86_64::{__cpuid, _rdtsc}; @@ -161,121 +154,223 @@ pub mod invariant_tsc { } } -/// Create a trace record from the message and push it to the trace buffer. -/// -/// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. -/// This is useful for ensuring that the trace buffer does not overflow. -pub fn create_trace_record(msg: &str) { - let entry = TraceRecord::from(msg); - let mut buffer = TRACE_BUFFER.lock(); +#[cfg(feature = "trace")] +mod trace { + // === Dependencies === + extern crate alloc; - buffer.push(entry); -} + use core::mem::MaybeUninit; -/// Flush the trace buffer to send any remaining trace records to the host. -pub fn flush_trace_buffer() { - let mut buffer = TRACE_BUFFER.lock(); - buffer.flush(); -} + use hyperlight_common::outb::OutBAction; + use spin::Mutex; + + use super::{MAX_TRACE_MSG_LEN, TraceRecord, invariant_tsc}; + + /// Type alias for the function that sends trace records to the host. + type SendToHostFn = fn(u64, &[TraceRecord]); -#[cfg(test)] -mod tests { - use alloc::format; + /// Global trace buffer for storing trace records. + static TRACE_BUFFER: Mutex> = + Mutex::new(TraceBuffer::new(send_to_host)); - use super::*; + /// Maximum number of entries in the trace buffer. + /// From local testing, 32 entries seems to be a good balance between performance and memory usage. + const MAX_NO_OF_ENTRIES: usize = 32; - /// This is a mock function for testing purposes. - /// In a real scenario, this would send the trace records to the host. - fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} + impl From<&str> for TraceRecord { + fn from(mut msg: &str) -> Self { + if msg.len() > MAX_TRACE_MSG_LEN { + // If the message is too long, truncate it to fit the maximum length + msg = &msg[..MAX_TRACE_MSG_LEN]; + } - fn create_test_entry(msg: &str) -> TraceRecord { - let cycles = invariant_tsc::read_tsc(); + let cycles = invariant_tsc::read_tsc(); - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } } } - #[test] - fn test_push_trace_record() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + /// A buffer for storing trace records. + struct TraceBuffer { + /// The entries in the trace buffer. + entries: [TraceRecord; MAX_NO_OF_ENTRIES], + /// The index where the next entry will be written. + write_index: usize, + /// Function to send the trace records to the host. + send_to_host: F, + } - let msg = "Test message"; - let entry = create_test_entry(msg); + impl TraceBuffer { + /// Creates a new `TraceBuffer` with uninitialized entries. + const fn new(f: F) -> Self { + Self { + entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, + write_index: 0, + send_to_host: f, + } + } - buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set + /// Push a new trace record into the buffer. + /// If the buffer is full, it sends the records to the host. + fn push(&mut self, entry: TraceRecord) { + let mut write_index = self.write_index; + + self.entries[write_index] = entry; + write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; + + self.write_index = write_index; + + if write_index == 0 { + // If buffer is full send to host + (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); + } + } + + /// Flush the trace buffer, sending any remaining records to the host. + fn flush(&mut self) { + if self.write_index > 0 { + (self.send_to_host)(self.write_index as u64, &self.entries); + self.write_index = 0; // Reset write index after flushing + } + } } - #[test] - fn test_flush_trace_buffer() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + /// Send the trace records to the host. + fn send_to_host(len: u64, records: &[TraceRecord]) { + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceRecord as u16, + in("rax") len, + in("rcx") records.as_ptr() as u64); + } + } - let msg = "Test message"; - let entry = create_test_entry(msg); + /// Create a trace record from the message and push it to the trace buffer. + /// + /// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. + /// This is useful for ensuring that the trace buffer does not overflow. + #[inline(always)] + pub fn create_trace_record(msg: &str) { + let entry = TraceRecord::from(msg); + let mut buffer = TRACE_BUFFER.lock(); buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); + } - // Flush the buffer + /// Flush the trace buffer to send any remaining trace records to the host. + #[inline(always)] + pub fn flush_trace_buffer() { + let mut buffer = TRACE_BUFFER.lock(); buffer.flush(); - - // After flushing, the entryes should still be intact, we don't clear them - assert_eq!(buffer.write_index, 0); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); } - #[test] - fn test_auto_flush_on_full() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + #[cfg(test)] + mod tests { + use alloc::format; + + use super::*; + + /// This is a mock function for testing purposes. + /// In a real scenario, this would send the trace records to the host. + fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} + + fn create_test_entry(msg: &str) -> TraceRecord { + let cycles = invariant_tsc::read_tsc(); + + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } + } + + #[test] + fn test_push_trace_record() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + let msg = "Test message"; + let entry = create_test_entry(msg); - // Fill the buffer to trigger auto-flush - for i in 0..MAX_NO_OF_ENTRIES { - let msg = format!("Message {}", i); - let entry = create_test_entry(&msg); buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set } - // After filling, the write index should be 0 (buffer is full) - assert_eq!(buffer.write_index, 0); + #[test] + fn test_flush_trace_buffer() { + let mut buffer = TraceBuffer::new(mock_send_to_host); - // The first entry should still be intact - assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); - } + let msg = "Test message"; + let entry = create_test_entry(msg); - /// Test TraceRecord creation with a valid message - #[test] - fn test_trace_record_creation_valid() { - let msg = "Valid message"; - let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); - assert_eq!(entry.msg_len, msg.len()); - assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); - assert!(entry.cycles > 0); // Ensure cycles is set - } + buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + + // Flush the buffer + buffer.flush(); + + // After flushing, the entryes should still be intact, we don't clear them + assert_eq!(buffer.write_index, 0); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + } + + #[test] + fn test_auto_flush_on_full() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + // Fill the buffer to trigger auto-flush + for i in 0..MAX_NO_OF_ENTRIES { + let msg = format!("Message {}", i); + let entry = create_test_entry(&msg); + buffer.push(entry); + } - /// Test TraceRecord creation with a message that exceeds the maximum length - #[test] - fn test_trace_record_creation_too_long() { - let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); - let result = TraceRecord::from(long_msg.as_str()); - assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); - assert_eq!( - &result.msg[..MAX_TRACE_MSG_LEN], - &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], - ); + // After filling, the write index should be 0 (buffer is full) + assert_eq!(buffer.write_index, 0); + + // The first entry should still be intact + assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); + } + + /// Test TraceRecord creation with a valid message + #[test] + fn test_trace_record_creation_valid() { + let msg = "Valid message"; + let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); + assert_eq!(entry.msg_len, msg.len()); + assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); + assert!(entry.cycles > 0); // Ensure cycles is set + } + + /// Test TraceRecord creation with a message that exceeds the maximum length + #[test] + fn test_trace_record_creation_too_long() { + let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); + let result = TraceRecord::from(long_msg.as_str()); + assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); + assert_eq!( + &result.msg[..MAX_TRACE_MSG_LEN], + &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], + ); + } } } diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 6e749ac20..9fc1df9d5 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -16,6 +16,7 @@ syn = { version = "2.0.104", features = ["full"] } [features] default = [] +trace = [] [lib] proc-macro = true diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs index 24b790864..22a5cdf0e 100644 --- a/src/hyperlight_guest_tracing_macro/src/lib.rs +++ b/src/hyperlight_guest_tracing_macro/src/lib.rs @@ -19,16 +19,7 @@ use quote::quote; use syn::{ItemFn, parse_macro_input}; /// A procedural macro attribute for tracing function calls. -/// Usage: -/// ```rust -/// #[hyperlight_guest_tracing_macro::trace_function] -/// fn my_function() { -/// // // Function body -/// } -/// ``` -/// -/// This macro will create a trace record when the function is called, if the `trace_guest` -/// feature is enabled. +/// This macro will create a trace record when the function is called /// /// The trace record will contain the function name as a string. /// Note: This macro is intended to be used with the `hyperlight_guest_tracing` crate. @@ -46,46 +37,64 @@ pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { // Compose entry/exit messages let entry_msg = format!("> {}", fn_name_str); - let exit_msg = format!("< {}", fn_name_str); + let _exit_msg = format!("< {}", fn_name_str); let expanded = match fn_output { syn::ReturnType::Default => { // No return value (unit) + #[cfg(feature = "trace")] quote! { #(#fn_attrs)* #fn_vis #fn_sig { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); // Call the original function body #fn_block - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); + } + } + #[cfg(not(feature = "trace"))] + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #fn_block } } } syn::ReturnType::Type(_, _) => { // Has a return value + #[cfg(feature = "trace")] quote! { #(#fn_attrs)* #fn_vis #fn_sig { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = (|| #fn_block )(); - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); __trace_result } } + #[cfg(not(feature = "trace"))] + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #fn_block + } + } } }; @@ -104,6 +113,11 @@ impl syn::parse::Parse for TraceMacroInput { if !matches!(message, syn::Lit::Str(_)) { return Err(input.error("first argument to trace! must be a string literal")); } + if let syn::Lit::Str(ref lit_str) = message { + if lit_str.value().is_empty() { + return Err(input.error("trace message must not be empty")); + } + } let statement = if input.peek(syn::Token![,]) { let _: syn::Token![,] = input.parse()?; @@ -117,78 +131,8 @@ impl syn::parse::Parse for TraceMacroInput { /// This macro creates a trace record with a message, or traces a block with entry/exit records. /// -/// Usage: -/// ```rust -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("message"); -/// trace!("message", { /* block of code */ }); -/// ``` -/// /// When called with an expression or statement as the second argument, it is wrapped in a block, /// entry and exit trace records are created at the start and end of block, and the result of the block is returned. -/// -/// # Examples -/// -/// ## Basic usage: trace with message only -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("hello"); -/// ``` -/// -/// ## Trace with a block, returning a value -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let x = trace!("block", { 42 }); -/// assert_eq!(x, 42); -/// ``` -/// -/// ## Trace with a block using local variables -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let y = 10; -/// let z = trace!("sum", { y + 5 }); -/// assert_eq!(z, 15); -/// ``` -/// -/// ## Trace with a block that returns a reference -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let s = String::from("abc"); -/// let r: &str = trace!("ref", { &s }); -/// assert_eq!(r, "abc"); -/// ``` -/// -/// ## Control flow: `return` inside the block returns from the function -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// fn foo() -> i32 { -/// let _ = trace!("fail", { -/// // This return only exits the closure, not the function `foo`. -/// return 42; -/// }); -/// assert!(false, "This should not be reached"); -/// } -/// ``` -/// -/// ## Control flow: `break` inside the block exits the outer loop -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let mut x = 0; -/// for i in 1..3 { -/// x = i; -/// let _ = trace!("msg", { -/// // This break should exit the loop. -/// break; -/// }); -/// } -/// assert_eq!(x, 1, "Loop should break after the first iteration"); -/// ``` #[proc_macro] pub fn trace(input: TokenStream) -> TokenStream { let parsed = syn::parse_macro_input!(input as TraceMacroInput); @@ -198,53 +142,68 @@ pub fn trace(input: TokenStream) -> TokenStream { }; if let Some(statement) = parsed.statement { let entry_msg = format!("+ {}", trace_message); - let exit_msg = format!("- {}", trace_message); + let _exit_msg = format!("- {}", trace_message); + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = #statement; - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); __trace_result } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! { + { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #statement + } + }; + TokenStream::from(expanded) } else { + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] const _: () = assert!( #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#trace_message); } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! { + { + const _: () = assert!( + #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + } + }; + TokenStream::from(expanded) } } /// This macro flushes the trace buffer, sending any remaining trace records to the host. -/// -/// Usage: -/// ```rust -/// hyperlight_guest_tracing_macro::flush!(); -/// ``` #[proc_macro] pub fn flush(_input: TokenStream) -> TokenStream { + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::flush_trace_buffer(); } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! {}; TokenStream::from(expanded) } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index eeba95e97..8af383193 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -132,7 +132,7 @@ executable_heap = [] print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] -trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing"] +trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"] # This feature enables unwinding the guest stack from the host, in # order to produce stack traces for debugging or profiling. unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 24c80469e..e1de2399e 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -36,6 +36,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", + "hyperlight-guest-tracing", ] [[package]] diff --git a/src/tests/rust_guests/callbackguest/Cargo.toml b/src/tests/rust_guests/callbackguest/Cargo.toml index 2d63452e4..b1040eb5d 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.toml +++ b/src/tests/rust_guests/callbackguest/Cargo.toml @@ -7,9 +7,10 @@ edition = "2021" hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } +hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/callbackguest/src/main.rs b/src/tests/rust_guests/callbackguest/src/main.rs index 0b79d578e..d217ccd88 100644 --- a/src/tests/rust_guests/callbackguest/src/main.rs +++ b/src/tests/rust_guests/callbackguest/src/main.rs @@ -37,6 +37,7 @@ use hyperlight_guest_bin::guest_function::register::register_function; use hyperlight_guest_bin::guest_logger::log_message; use hyperlight_guest_bin::host_comm::{call_host_function, print_output_with_host_print}; +#[hyperlight_guest_tracing::trace_function] fn send_message_to_host_method( method_name: &str, guest_message: &str, @@ -52,6 +53,7 @@ fn send_message_to_host_method( Ok(get_flatbuffer_result(res)) } +#[hyperlight_guest_tracing::trace_function] fn guest_function(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod", "Hello from GuestFunction, ", message) @@ -63,6 +65,7 @@ fn guest_function(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function1(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction1, ", message) @@ -74,6 +77,7 @@ fn guest_function1(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function2(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction2, ", message) @@ -85,6 +89,7 @@ fn guest_function2(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function3(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction3, ", message) @@ -96,6 +101,7 @@ fn guest_function3(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function4(_: &FunctionCall) -> Result> { call_host_function::<()>( "HostMethod4", @@ -108,6 +114,7 @@ fn guest_function4(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn guest_log_message(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(message), @@ -141,6 +148,7 @@ fn guest_log_message(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_error_method(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("ErrorMethod", "Error From Host: ", message) @@ -152,11 +160,13 @@ fn call_error_method(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_host_spin(_: &FunctionCall) -> Result> { call_host_function::<()>("Spin", None, ReturnType::Void)?; Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn host_call_loop(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { loop { @@ -171,6 +181,7 @@ fn host_call_loop(function_call: &FunctionCall) -> Result> { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { let print_output_def = GuestFunctionDefinition::new( "PrintOutput".to_string(), @@ -258,6 +269,7 @@ pub extern "C" fn hyperlight_main() { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { Err(HyperlightGuestError::new( ErrorCode::GuestFunctionNotFound, diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 07672d6f1..db313889c 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -231,6 +231,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", + "hyperlight-guest-tracing", "log", ] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 515b618d5..8748bdc0b 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -7,11 +7,12 @@ edition = "2021" hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } +hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } log = {version = "0.4", default-features = false } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] unwind_guest = ["hyperlight-common/unwind_guest"] mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 405087e25..5b5fe4dcf 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -56,6 +56,7 @@ extern crate hyperlight_guest; static mut BIGARRAY: [i32; 1024 * 1024] = [0; 1024 * 1024]; +#[hyperlight_guest_tracing::trace_function] fn set_static(_: &FunctionCall) -> Result> { unsafe { #[allow(static_mut_refs)] @@ -67,6 +68,7 @@ fn set_static(_: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo_double(function_call: &FunctionCall) -> Result> { if let ParameterValue::Double(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -78,6 +80,7 @@ fn echo_double(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo_float(function_call: &FunctionCall) -> Result> { if let ParameterValue::Float(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -89,6 +92,7 @@ fn echo_float(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_output(message: &str) -> Result> { let res = call_host_function::( "HostPrint", @@ -99,6 +103,7 @@ fn print_output(message: &str) -> Result> { Ok(get_flatbuffer_result(res)) } +#[hyperlight_guest_tracing::trace_function] fn simple_print_output(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { print_output(&message) @@ -110,6 +115,7 @@ fn simple_print_output(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(mut vec) = function_call.parameters.clone().unwrap()[0].clone() { @@ -123,6 +129,7 @@ fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_two_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -138,6 +145,7 @@ fn print_two_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_three_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2), ParameterValue::Long(arg3)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -154,6 +162,7 @@ fn print_three_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_four_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -179,6 +188,7 @@ fn print_four_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_five_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -206,6 +216,7 @@ fn print_five_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_six_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -235,6 +246,7 @@ fn print_six_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_seven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -266,6 +278,7 @@ fn print_seven_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_eight_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -299,6 +312,7 @@ fn print_eight_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_nine_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -334,6 +348,7 @@ fn print_nine_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_ten_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -371,6 +386,7 @@ fn print_ten_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_eleven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -410,6 +426,7 @@ fn print_eleven_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn buffer_overrun(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { let c_str = value.as_str(); @@ -432,6 +449,7 @@ fn buffer_overrun(function_call: &FunctionCall) -> Result> { } #[allow(unconditional_recursion)] +#[hyperlight_guest_tracing::trace_function] fn infinite_recursion(_a: &FunctionCall) -> Result> { // blackbox is needed so something //is written to the stack in release mode, @@ -441,6 +459,7 @@ fn infinite_recursion(_a: &FunctionCall) -> Result> { infinite_recursion(_a) } +#[hyperlight_guest_tracing::trace_function] fn stack_overflow(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { loop_stack_overflow(i); @@ -453,6 +472,7 @@ fn stack_overflow(function_call: &FunctionCall) -> Result> { } } // This function will allocate i * (8KiB + 1B) on the stack +#[hyperlight_guest_tracing::trace_function] fn loop_stack_overflow(i: i32) { if i > 0 { let _nums = black_box([0u8; 0x2000 + 1]); // chkstk guaranteed to be called for > 8KiB @@ -460,16 +480,19 @@ fn loop_stack_overflow(i: i32) { } } +#[hyperlight_guest_tracing::trace_function] fn large_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; (DEFAULT_GUEST_STACK_SIZE + 1) as usize]); Ok(get_flatbuffer_result(DEFAULT_GUEST_STACK_SIZE + 1)) } +#[hyperlight_guest_tracing::trace_function] fn small_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; 1024]); Ok(get_flatbuffer_result(1024)) } +#[hyperlight_guest_tracing::trace_function] fn call_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { // will panic if OOM, and we need blackbox to avoid optimizing away this test @@ -484,6 +507,7 @@ fn call_malloc(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn malloc_and_free(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { let alloc_length = if size < DEFAULT_GUEST_STACK_SIZE { @@ -503,6 +527,7 @@ fn malloc_and_free(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*value)) @@ -514,6 +539,7 @@ fn echo(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn get_size_prefixed_buffer(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(data) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*data)) @@ -538,6 +564,7 @@ fn spin(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_abort(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { abort_with_code(&[code as u8]); @@ -545,6 +572,7 @@ fn test_abort(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(code), ParameterValue::String(message)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -557,6 +585,7 @@ fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { panic!("{}", message); @@ -564,6 +593,7 @@ fn test_guest_panic(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { if let ParameterValue::Long(offset) = function_call.parameters.clone().unwrap()[0].clone() { let min_stack_addr = unsafe { MIN_STACK_ADDRESS }; @@ -587,6 +617,7 @@ fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn execute_on_stack(_function_call: &FunctionCall) -> Result> { unsafe { let mut noop: u8 = 0x90; @@ -596,6 +627,7 @@ fn execute_on_stack(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn execute_on_heap(_function_call: &FunctionCall) -> Result> { unsafe { // NO-OP followed by RET @@ -608,6 +640,7 @@ fn execute_on_heap(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn test_rust_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { let ptr = unsafe { malloc(code as usize) }; @@ -620,6 +653,7 @@ fn test_rust_malloc(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn log_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(message), ParameterValue::Int(level)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -642,6 +676,7 @@ fn log_message(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn trigger_exception(_: &FunctionCall) -> Result> { unsafe { core::arch::asm!("ud2"); @@ -651,6 +686,7 @@ fn trigger_exception(_: &FunctionCall) -> Result> { static mut COUNTER: i32 = 0; +#[hyperlight_guest_tracing::trace_function] fn add_to_static(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { let res = unsafe { @@ -666,6 +702,7 @@ fn add_to_static(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn get_static(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { Ok(get_flatbuffer_result(unsafe { COUNTER })) @@ -677,6 +714,7 @@ fn get_static(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn add_to_static_and_fail(_: &FunctionCall) -> Result> { unsafe { COUNTER += 10; @@ -687,6 +725,7 @@ fn add_to_static_and_fail(_: &FunctionCall) -> Result> { )) } +#[hyperlight_guest_tracing::trace_function] fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { let res = call_host_function::("MakeGetpidSyscall", None, ReturnType::ULong)?; @@ -700,6 +739,7 @@ fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(hostfuncname) = function_call.parameters.clone().unwrap()[0].clone() @@ -715,6 +755,7 @@ fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) } } +#[hyperlight_guest_tracing::trace_function] fn add(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(a), ParameterValue::Int(b)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -735,6 +776,7 @@ fn add(function_call: &FunctionCall) -> Result> { } // Does nothing, but used for testing large parameters +#[hyperlight_guest_tracing::trace_function] fn large_parameters(function_call: &FunctionCall) -> Result> { if let (ParameterValue::VecBytes(v), ParameterValue::String(s)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -750,6 +792,7 @@ fn large_parameters(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn read_from_user_memory(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(num), ParameterValue::VecBytes(expected)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -775,6 +818,7 @@ fn read_from_user_memory(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -798,6 +842,7 @@ fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -825,6 +870,7 @@ fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -853,6 +899,7 @@ fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { let read_from_user_memory_def = GuestFunctionDefinition::new( "ReadFromUserMemory".to_string(), @@ -1301,6 +1348,7 @@ pub extern "C" fn hyperlight_main() { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { // This test checks the stack behavior of the input/output buffer // by calling the host before serializing the function call. @@ -1346,6 +1394,7 @@ pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { } // Interprets the given guest function call as a host function call and dispatches it to the host. +#[hyperlight_guest_tracing::trace_function] fn fuzz_host_function(func: FunctionCall) -> Result> { let mut params = func.parameters.unwrap(); // first parameter must be string (the name of the host function to call) diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 0be5aec00..611b96b29 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -11,6 +11,6 @@ hyperlight-component-macro = { path = "../../../hyperlight_component_macro" } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest"] unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"]