Skip to content

Commit 610daed

Browse files
committed
[trace-guest] update guest crates to add trace instrumentation
- conditionally handle logs either through tracing or the dedicated VM exit based on whether tracing is initialized on the guest Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent 667d3b6 commit 610daed

File tree

12 files changed

+82
-19
lines changed

12 files changed

+82
-19
lines changed

Cargo.lock

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

src/hyperlight_guest/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
1717
hyperlight-common = { workspace = true }
1818
hyperlight-guest-tracing = { workspace = true, default-features = false }
1919
flatbuffers = { version= "25.2.10", default-features = false }
20+
tracing = { version = "0.1.41", default-features = false, features = ["attributes"] }
2021

2122
[features]
2223
default = []

src/hyperlight_guest/src/exit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ use core::arch::asm;
1818
use core::ffi::{CStr, c_char};
1919

2020
use hyperlight_common::outb::OutBAction;
21+
use tracing::{Span, instrument};
2122

2223
/// Halt the execution of the guest and returns control to the host.
2324
#[inline(never)]
25+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
2426
pub fn halt() {
2527
#[cfg(feature = "trace_guest")]
2628
{
@@ -103,6 +105,7 @@ pub fn write_abort(code: &[u8]) {
103105
}
104106

105107
/// OUT bytes to the host through multiple exits.
108+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
106109
pub(crate) fn outb(port: u16, data: &[u8]) {
107110
// Ensure all tracing data is flushed before sending OUT bytes
108111
unsafe {
@@ -121,6 +124,7 @@ pub(crate) fn outb(port: u16, data: &[u8]) {
121124
}
122125

123126
/// OUT function for sending a 32-bit value to the host.
127+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
124128
pub(crate) unsafe fn out32(port: u16, val: u32) {
125129
#[cfg(feature = "trace_guest")]
126130
{

src/hyperlight_guest/src/guest_handle/host_comm.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel;
3030
use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails;
3131
use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity;
3232
use hyperlight_common::outb::OutBAction;
33+
use tracing::{Span, instrument};
3334

3435
use super::handle::GuestHandle;
3536
use crate::error::{HyperlightGuestError, Result};
3637
use crate::exit::out32;
3738

3839
impl GuestHandle {
3940
/// Get user memory region as bytes.
41+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
4042
pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result<Vec<u8>> {
4143
let peb_ptr = self.peb().unwrap();
4244
let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 };
@@ -65,6 +67,7 @@ impl GuestHandle {
6567
///
6668
/// When calling `call_host_function<T>`, this function is called
6769
/// internally to get the return value.
70+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
6871
pub fn get_host_return_value<T: TryFrom<ReturnValue>>(&self) -> Result<T> {
6972
let return_value = self
7073
.try_pop_shared_input_data_into::<ReturnValue>()
@@ -85,6 +88,7 @@ impl GuestHandle {
8588
///
8689
/// Note: The function return value must be obtained by calling
8790
/// `get_host_return_value`.
91+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
8892
pub fn call_host_function_without_returning_result(
8993
&self,
9094
function_name: &str,
@@ -118,6 +122,7 @@ impl GuestHandle {
118122
/// sends it to the host, and then retrieves the return value.
119123
///
120124
/// The return value is deserialized into the specified type `T`.
125+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
121126
pub fn call_host_function<T: TryFrom<ReturnValue>>(
122127
&self,
123128
function_name: &str,
@@ -128,6 +133,7 @@ impl GuestHandle {
128133
self.get_host_return_value::<T>()
129134
}
130135

136+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
131137
pub fn get_host_function_details(&self) -> HostFunctionDetails {
132138
let peb_ptr = self.peb().unwrap();
133139
let host_function_details_buffer =
@@ -144,6 +150,7 @@ impl GuestHandle {
144150
}
145151

146152
/// Write an error to the shared output data buffer.
153+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
147154
pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) {
148155
let guest_error: GuestError = GuestError::new(
149156
error_code,
@@ -159,6 +166,7 @@ impl GuestHandle {
159166
}
160167

161168
/// Log a message with the specified log level, source, caller, source file, and line number.
169+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
162170
pub fn log_message(
163171
&self,
164172
log_level: LogLevel,
@@ -168,24 +176,46 @@ impl GuestHandle {
168176
source_file: &str,
169177
line: u32,
170178
) {
171-
let guest_log_data = GuestLogData::new(
172-
message.to_string(),
173-
source.to_string(),
174-
log_level,
175-
caller.to_string(),
176-
source_file.to_string(),
177-
line,
178-
);
179-
180-
let bytes: Vec<u8> = guest_log_data
181-
.try_into()
182-
.expect("Failed to convert GuestLogData to bytes");
183-
184-
self.push_shared_output_data(&bytes)
185-
.expect("Unable to push log data to shared output data");
186-
187-
unsafe {
188-
out32(OutBAction::Log as u16, 0);
179+
// Closure to send log message to host
180+
let send_to_host = || {
181+
let guest_log_data = GuestLogData::new(
182+
message.to_string(),
183+
source.to_string(),
184+
log_level,
185+
caller.to_string(),
186+
source_file.to_string(),
187+
line,
188+
);
189+
190+
let bytes: Vec<u8> = guest_log_data
191+
.try_into()
192+
.expect("Failed to convert GuestLogData to bytes");
193+
194+
self.push_shared_output_data(&bytes)
195+
.expect("Unable to push log data to shared output data");
196+
197+
unsafe {
198+
out32(OutBAction::Log as u16, 0);
199+
}
200+
};
201+
202+
#[cfg(feature = "trace_guest")]
203+
if hyperlight_guest_tracing::is_trace_enabled() {
204+
// If the "trace_guest" feature is enabled and tracing is initialized, log using tracing
205+
tracing::trace!(
206+
event = message,
207+
level = ?log_level,
208+
code.filepath = source,
209+
caller = caller,
210+
source_file = source_file,
211+
code.lineno = line,
212+
);
213+
} else {
214+
send_to_host();
215+
}
216+
#[cfg(not(feature = "trace_guest"))]
217+
{
218+
send_to_host();
189219
}
190220
}
191221
}

src/hyperlight_guest/src/guest_handle/io.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ use core::any::type_name;
2020
use core::slice::from_raw_parts_mut;
2121

2222
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
23+
use tracing::{Span, instrument};
2324

2425
use super::handle::GuestHandle;
2526
use crate::error::{HyperlightGuestError, Result};
2627

2728
impl GuestHandle {
2829
/// Pops the top element from the shared input data buffer and returns it as a T
30+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
2931
pub fn try_pop_shared_input_data_into<T>(&self) -> Result<T>
3032
where
3133
T: for<'a> TryFrom<&'a [u8]>,
@@ -87,6 +89,7 @@ impl GuestHandle {
8789
}
8890

8991
/// Pushes the given data onto the shared output data buffer.
92+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
9093
pub fn push_shared_output_data(&self, data: &[u8]) -> Result<()> {
9194
let peb_ptr = self.peb().unwrap();
9295
let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize };

src/hyperlight_guest_bin/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ hyperlight-guest-tracing = { workspace = true, default-features = false }
2727
buddy_system_allocator = "0.11.0"
2828
log = { version = "0.4", default-features = false }
2929
spin = "0.10.0"
30+
tracing = { version = "0.1.41", default-features = false, features = ["attributes"] }
3031

3132
[lints]
3233
workspace = true

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ use hyperlight_common::flatbuffer_wrappers::function_types::ParameterType;
2222
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2323
use hyperlight_guest::error::{HyperlightGuestError, Result};
2424
use hyperlight_guest::exit::halt;
25+
use tracing::{Span, instrument};
2526

2627
use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS};
2728

2829
type GuestFunc = fn(&FunctionCall) -> Result<Vec<u8>>;
2930

31+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
3032
pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>> {
3133
// Validate this is a Guest Function Call
3234
if function_call.function_call_type() != FunctionCallType::Guest {
@@ -80,6 +82,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>
8082
// and we will leak memory as the epilogue will not be called as halt() is not going to return.
8183
#[unsafe(no_mangle)]
8284
#[inline(never)]
85+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
8386
fn internal_dispatch_function() -> Result<()> {
8487
let handle = unsafe { GUEST_HANDLE };
8588

@@ -100,6 +103,7 @@ fn internal_dispatch_function() -> Result<()> {
100103
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()
101104
// which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return
102105
// when running in the hypervisor.
106+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
103107
pub(crate) extern "C" fn dispatch_function() {
104108
// The hyperlight host likes to use one partition and reset it in
105109
// various ways; if that has happened, there might stale TLB

src/hyperlight_guest_bin/src/paging.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
use alloc::alloc::Layout;
1818
use core::arch::asm;
1919

20+
use tracing::{Span, instrument};
21+
2022
use crate::OS_PAGE_SIZE;
2123

2224
/// Convert a physical address in main memory to a virtual address
@@ -61,6 +63,7 @@ struct MapResponse {
6163
/// as such do not use concurrently with any other page table operations
6264
/// - TLB invalidation is not performed,
6365
/// if previously-unmapped ranges are not being mapped, TLB invalidation may need to be performed afterwards.
66+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
6467
pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) {
6568
let mut pml4_base: u64;
6669
unsafe {

src/hyperlight_guest_tracing/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ mod visitor;
3838
pub use state::TraceBatchInfo;
3939
#[cfg(feature = "trace")]
4040
pub use trace::{
41-
clean_trace_state, end_trace, guest_trace_info, init_guest_tracing, set_start_tsc,
41+
clean_trace_state, end_trace, guest_trace_info, init_guest_tracing, is_trace_enabled,
42+
set_start_tsc,
4243
};
4344

4445
/// Maximum number of spans that the guest can store
@@ -212,4 +213,12 @@ mod trace {
212213
}
213214
res
214215
}
216+
217+
/// Returns true if tracing is enabled (the guest tracing state is initialized).
218+
pub fn is_trace_enabled() -> bool {
219+
GUEST_STATE
220+
.get()
221+
.map(|w| w.upgrade().is_some())
222+
.unwrap_or(false)
223+
}
215224
}

src/tests/rust_guests/dummyguest/Cargo.lock

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

0 commit comments

Comments
 (0)