1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
//! Safe wrappers over the EVENT_RECORD type
use windows::Win32::System::Diagnostics::Etw::EVENT_RECORD;
use windows::core::GUID;
use crate::native::etw_types::extended_data::EventHeaderExtendedDataItem;
/// A read-only wrapper over an [EVENT_RECORD](https://docs.microsoft.com/en-us/windows/win32/api/evntcons/ns-evntcons-event_record)
#[repr(transparent)]
pub struct EventRecord(EVENT_RECORD);
impl EventRecord {
/// Create a `&self` from a Windows pointer.
///
/// # Safety
///
/// 1. Once an instance of `Self` is created, one should make sure the pointed data does not get modified (or dealloc'ed).
/// 2. The returned lifetime is arbitray. To restrict the use of the returned reference (and to ensure the first safety guarantee), simply pass it to a sub-function whose signature has no explicit lifetime.
/// Thus, the sub-function will not be able to leak this reference.
pub(crate) unsafe fn from_ptr<'a>(p: *const EVENT_RECORD) -> Option<&'a Self> {
let s = p as *const Self;
s.as_ref()
}
/// Get the wrapped `EVENT_RECORD` (usually to feed Windows API functions)
///
/// # Safety
///
/// Obviously, the returned pointer is only valid as long `self` is valid and not modified.
pub(crate) fn as_raw_ptr(&self) -> *const EVENT_RECORD {
&self.0 as *const EVENT_RECORD
}
/// The `UserContext` field from the wrapped `EVENT_RECORD`
///
/// In this crate, it is always populated to point to a valid [`CallbackData`](crate::trace::CallbackData)
pub(crate) fn user_context(&self) -> *const std::ffi::c_void {
self.0.UserContext as *const _
}
/// The `ProviderId` field from the wrapped `EVENT_RECORD`
pub fn provider_id(&self) -> GUID {
self.0.EventHeader.ProviderId
}
/// The `Id` field from the wrapped `EVENT_RECORD`
pub fn event_id(&self) -> u16 {
self.0.EventHeader.EventDescriptor.Id
}
/// The `Opcode` field from the wrapped `EVENT_RECORD`
pub fn opcode(&self) -> u8 {
self.0.EventHeader.EventDescriptor.Opcode
}
/// The `Version` field from the wrapped `EVENT_RECORD`
pub fn version(&self) -> u8 {
self.0.EventHeader.EventDescriptor.Version
}
/// The `Level` field from the wrapped `EVENT_RECORD`
pub fn level(&self) -> u8 {
self.0.EventHeader.EventDescriptor.Level
}
/// The `Flags` field from the wrapped `EVENT_RECORD`
pub fn event_flags(&self) -> u16 {
self.0.EventHeader.Flags
}
/// The `ProcessId` field from the wrapped `EVENT_RECORD`
pub fn process_id(&self) -> u32 {
self.0.EventHeader.ProcessId
}
/// The `ThreadId` field from the wrapped `EVENT_RECORD`
pub fn thread_id(&self) -> u32 {
self.0.EventHeader.ThreadId
}
/// The `ActivityId` field from the wrapped `EVENT_RECORD`
pub fn activity_id(&self) -> GUID {
self.0.EventHeader.ActivityId
}
/// The `TimeStamp` field from the wrapped `EVENT_RECORD`
///
/// As per [Microsoft's documentation](https://docs.microsoft.com/en-us/windows/win32/api/evntcons/ns-evntcons-event_header):
/// > Contains the time that the event occurred.<br/>
/// > The resolution is system time unless the `ProcessTraceMode member` of `EVENT_TRACE_LOGFILE`
/// > contains the `PROCESS_TRACE_MODE_RAW_TIMESTAMP` flag, in which case the resolution depends
/// > on the value of the `Wnode.ClientContext` member of `EVENT_TRACE_PROPERTIES` at the time
/// > the controller created the session.
///
/// Note: the `time_rs` Cargo feature enables to convert this into strongly-typed values
pub fn raw_timestamp(&self) -> i64 {
self.0.EventHeader.TimeStamp
}
/// The `TimeStamp` field from the wrapped `EVENT_RECORD`, as a strongly-typed `time::OffsetDateTime`
#[cfg(feature = "time_rs")]
pub fn timestamp(&self) -> time::OffsetDateTime {
// "system time" means the count of hundreds of nanoseconds since midnight, January 1, 1601
let system_time = self.0.EventHeader.TimeStamp;
const SECONDS_BETWEEN_1601_AND_1970: i128 = 11_644_473_600;
const HUNDREDS_OF_NANOS_IN_SECOND: i128 = 10_000_000;
const HUNDREDS_OF_NANOSECONDS_BETWEEN_1601_AND_1970: i128 =
SECONDS_BETWEEN_1601_AND_1970 * HUNDREDS_OF_NANOS_IN_SECOND;
let unix_as_hundreds_of_nano_seconds = (system_time as i128) - HUNDREDS_OF_NANOSECONDS_BETWEEN_1601_AND_1970;
let unix_as_nano_seconds = unix_as_hundreds_of_nano_seconds * 100;
// Can't panic.
// A filetime can go from 1601 to 30828.
// OffsetDateTime (with the 'large-dates' feature) can represent any time from year -999_999 to +999_999. Meanwhile, .
time::OffsetDateTime::from_unix_timestamp_nanos(unix_as_nano_seconds).unwrap()
}
pub(crate) fn user_buffer(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
self.0.UserData as *mut _,
self.0.UserDataLength.into(),
)
}
}
/// Returns the `ExtendedData` from the ETW Event
///
/// Their availability is mostly determined by the flags passed to [`Provider::trace_flags`](crate::provider::Provider::trace_flags)
///
/// # Example
/// ```
/// # use ferrisetw::EventRecord;
/// # use ferrisetw::schema_locator::SchemaLocator;
/// use windows::Win32::System::Diagnostics::Etw::EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID;
///
/// let my_callback = |record: &EventRecord, schema_locator: &SchemaLocator| {
/// let schema = schema_locator.event_schema(record).unwrap();
/// let activity_id = record
/// .extended_data()
/// .iter()
/// .find(|edata| edata.data_type() as u32 == EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID)
/// .map(|edata| edata.to_extended_data_item());
/// };
/// ```
pub fn extended_data(&self) -> &[EventHeaderExtendedDataItem] {
let n_extended_data = self.0.ExtendedDataCount;
let p_ed_array = self.0.ExtendedData;
if n_extended_data == 0 || p_ed_array.is_null() {
return &[];
}
// Safety: * we're building a slice from an array pointer size given by Windows
// * the pointed data is not supposed to be mutated during the lifetime of `Self`
unsafe {
std::slice::from_raw_parts(
p_ed_array as *const EventHeaderExtendedDataItem,
n_extended_data as usize)
}
}
}