ferrisetw/native/etw_types.rs
1//! Basic ETW types
2//!
3//! The `etw_types` module provides an abstraction over the basic ETW types needed to control and
4//! parse a trace session. Most of the types in this module are wrappers over the windows bindings
5//! using the newtype pattern to extend their implementations
6//!
7//! In most cases a user of the crate won't have to deal with this and can directly obtain the data
8//! needed by using the functions exposed by the modules at the crate level
9#![allow(clippy::bad_bit_mask)]
10
11use crate::provider::event_filter::EventFilterDescriptor;
12use crate::provider::TraceFlags;
13use crate::trace::callback_data::CallbackData;
14use crate::trace::{RealTimeTraceTrait, TraceProperties};
15use std::ffi::{c_void, OsString};
16use std::fmt::Formatter;
17use std::marker::PhantomData;
18use std::sync::Arc;
19
20use widestring::{U16CStr, U16CString};
21use windows::core::GUID;
22use windows::core::PWSTR;
23use windows::Win32::System::Diagnostics::Etw;
24use windows::Win32::System::Diagnostics::Etw::EVENT_FILTER_DESCRIPTOR;
25
26pub(crate) mod event_record;
27pub(crate) mod extended_data;
28
29pub const TRACE_NAME_MAX_CHARS: usize = 200; // Microsoft documentation says the limit is 1024, but do not trust us. Experience shows that traces with names longer than ~240 character silently fail.
30
31/// This enum is <https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ne-evntrace-trace_query_info_class>
32///
33/// Re-defining it here, because all these values are not defined in windows-rs (yet?)
34#[derive(Debug, Copy, Clone)]
35#[allow(dead_code)]
36#[non_exhaustive]
37#[repr(i32)]
38pub enum TraceInformation {
39 TraceGuidQueryList,
40 TraceGuidQueryInfo,
41 TraceGuidQueryProcess,
42 TraceStackTracingInfo,
43 TraceSystemTraceEnableFlagsInfo,
44 TraceSampledProfileIntervalInfo,
45 TraceProfileSourceConfigInfo,
46 TraceProfileSourceListInfo,
47 TracePmcEventListInfo,
48 TracePmcCounterListInfo,
49 TraceSetDisallowList,
50 TraceVersionInfo,
51 TraceGroupQueryList,
52 TraceGroupQueryInfo,
53 TraceDisallowListQuery,
54 TraceInfoReserved15,
55 TracePeriodicCaptureStateListInfo,
56 TracePeriodicCaptureStateInfo,
57 TraceProviderBinaryTracking,
58 TraceMaxLoggersQuery,
59 TraceLbrConfigurationInfo,
60 TraceLbrEventListInfo,
61 /// Query the maximum PMC counters that can be specified simultaneously.
62 /// May be queried without an active ETW session.
63 ///
64 /// Output: u32
65 TraceMaxPmcCounterQuery,
66 TraceStreamCount,
67 TraceStackCachingInfo,
68 TracePmcCounterOwners,
69 TraceUnifiedStackCachingInfo,
70 TracePmcSessionInformation,
71 MaxTraceSetInfoClass,
72}
73
74#[allow(dead_code)]
75pub(crate) enum ControlValues {
76 Query = 0,
77 Stop = 1,
78 Update = 2,
79}
80
81bitflags! {
82 /// Logging Mode constants that applies to a general trace
83 ///
84 /// This is a subset of <https://learn.microsoft.com/en-us/windows/win32/etw/logging-mode-constants>
85 pub struct LoggingMode: u32 {
86 // Commented values only apply to DumpFileLoggingMod
87
88 // EVENT_TRACE_FILE_MODE_NONE
89 // EVENT_TRACE_FILE_MODE_SEQUENTIAL
90 // EVENT_TRACE_FILE_MODE_CIRCULAR
91 // EVENT_TRACE_FILE_MODE_APPEND
92 // EVENT_TRACE_FILE_MODE_NEWFILE
93 // EVENT_TRACE_FILE_MODE_PREALLOCATE
94 const EVENT_TRACE_NONSTOPPABLE_MODE = Etw::EVENT_TRACE_NONSTOPPABLE_MODE;
95 const EVENT_TRACE_SECURE_MODE = Etw::EVENT_TRACE_SECURE_MODE;
96 const EVENT_TRACE_REAL_TIME_MODE = Etw::EVENT_TRACE_REAL_TIME_MODE;
97 // On Windows Vista or later, this mode is not applicable should not be used.
98 // EVENT_TRACE_DELAY_OPEN_FILE_MODE
99 const EVENT_TRACE_BUFFERING_MODE = Etw::EVENT_TRACE_BUFFERING_MODE;
100 const EVENT_TRACE_PRIVATE_LOGGER_MODE = Etw::EVENT_TRACE_PRIVATE_LOGGER_MODE;
101 // EVENT_TRACE_USE_KBYTES_FOR_SIZE
102 // EVENT_TRACE_USE_GLOBAL_SEQUENCE
103 // EVENT_TRACE_USE_LOCAL_SEQUENCE
104 const EVENT_TRACE_PRIVATE_IN_PROC = Etw::EVENT_TRACE_PRIVATE_IN_PROC;
105 const EVENT_TRACE_MODE_RESERVED = Etw::EVENT_TRACE_MODE_RESERVED;
106 const EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN = Etw::EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN;
107 const EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN = Etw::EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN;
108 const EVENT_TRACE_USE_PAGED_MEMORY = Etw::EVENT_TRACE_USE_PAGED_MEMORY;
109 const EVENT_TRACE_SYSTEM_LOGGER_MODE = Etw::EVENT_TRACE_SYSTEM_LOGGER_MODE;
110 const EVENT_TRACE_INDEPENDENT_SESSION_MODE = Etw::EVENT_TRACE_INDEPENDENT_SESSION_MODE;
111 const EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = Etw::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING;
112 const EVENT_TRACE_ADDTO_TRIAGE_DUMP = Etw::EVENT_TRACE_ADDTO_TRIAGE_DUMP;
113 }
114}
115
116bitflags! {
117 /// Logging Mode constants that applies to a dump file.
118 ///
119 /// This is a subset of <https://learn.microsoft.com/en-us/windows/win32/etw/logging-mode-constants>
120 ///
121 /// See the documentation of [`crate::trace::TraceBuilder::set_etl_dump_file`] for more info.
122 pub struct DumpFileLoggingMode: u32 {
123 // Commented values only apply to LoggingMode
124
125 /// > Same as EVENT_TRACE_FILE_MODE_SEQUENTIAL with no maximum file size specified.
126 const EVENT_TRACE_FILE_MODE_NONE = Etw::EVENT_TRACE_FILE_MODE_NONE;
127 /// > Writes events to a log file sequentially; stops when the file reaches its maximum size.Do not use with EVENT_TRACE_FILE_MODE_CIRCULAR or EVENT_TRACE_FILE_MODE_NEWFILE.
128 ///
129 /// Note: "stop" here means "stop appending to the file", not "stop the trace"
130 const EVENT_TRACE_FILE_MODE_SEQUENTIAL = Etw::EVENT_TRACE_FILE_MODE_SEQUENTIAL;
131 /// > Writes events to a log file. After the file reaches the maximum size, the oldest events are replaced with incoming events.Note that the contents of the circular log file may appear out of order on multiprocessor computers.<br/>
132 /// > Do not use with EVENT_TRACE_FILE_MODE_APPEND, EVENT_TRACE_FILE_MODE_NEWFILE, or EVENT_TRACE_FILE_MODE_SEQUENTIAL.
133 const EVENT_TRACE_FILE_MODE_CIRCULAR = Etw::EVENT_TRACE_FILE_MODE_CIRCULAR;
134 /// > Appends events to an existing sequential log file. If the file does not exist, it is created. Use only if you specify system time for the clock resolution, otherwise, ProcessTrace will return events with incorrect time stamps. When using EVENT_TRACE_FILE_MODE_APPEND, the values for BufferSize, NumberOfProcessors, and ClockType must be explicitly provided and must be the same in both the logger and the file being appended.<br/>
135 /// > Do not use with EVENT_TRACE_REAL_TIME_MODE, EVENT_TRACE_FILE_MODE_CIRCULAR, EVENT_TRACE_FILE_MODE_NEWFILE, or EVENT_TRACE_PRIVATE_LOGGER_MODE.
136 const EVENT_TRACE_FILE_MODE_APPEND = Etw::EVENT_TRACE_FILE_MODE_APPEND;
137 /// > Automatically switches to a new log file when the file reaches the maximum size. The MaximumFileSize member of EVENT_TRACE_PROPERTIES must be set.The specified file name must be a formatted string (for example, the string contains a %d, such as c:\test%d.etl). Each time a new file is created, a counter is incremented and its value is used, the formatted string is updated, and the resulting string is used as the file name.<br/>
138 /// > This option is not allowed for private event tracing sessions and should not be used for NT kernel logger sessions.<br/>
139 /// > Do not use with EVENT_TRACE_FILE_MODE_CIRCULAR, EVENT_TRACE_FILE_MODE_APPEND or EVENT_TRACE_FILE_MODE_SEQUENTIAL.
140 const EVENT_TRACE_FILE_MODE_NEWFILE = Etw::EVENT_TRACE_FILE_MODE_NEWFILE;
141 /// > Reserves EVENT_TRACE_PROPERTIES.MaximumFileSize bytes of disk space for the log file in advance. The file occupies the entire space during logging, for both circular and sequential log files. When you stop the session, the log file is reduced to the size needed. You must set EVENT_TRACE_PROPERTIES.MaximumFileSize.<br/>
142 /// > You cannot use the mode for private event tracing sessions.
143 const EVENT_TRACE_FILE_MODE_PREALLOCATE = Etw::EVENT_TRACE_FILE_MODE_PREALLOCATE;
144 // EVENT_TRACE_NONSTOPPABLE_MODE
145 // EVENT_TRACE_SECURE_MODE
146 // EVENT_TRACE_REAL_TIME_MODE
147 // On Windows Vista or later, this mode is not applicable should not be used.
148 // EVENT_TRACE_DELAY_OPEN_FILE_MODE
149 // EVENT_TRACE_BUFFERING_MODE
150 // EVENT_TRACE_PRIVATE_LOGGER_MODE
151 /// > Use kilobytes as the unit of measure for specifying the size of a file. The default unit of measure is megabytes. This mode applies to the MaxFileSize registry value for an AutoLogger session and the MaximumFileSize member of EVENT_TRACE_PROPERTIES.
152 const EVENT_TRACE_USE_KBYTES_FOR_SIZE = Etw::EVENT_TRACE_USE_KBYTES_FOR_SIZE;
153 /// > Uses sequence numbers that are unique across event tracing sessions. This mode only applies to events logged using the TraceMessage function. For more information, see TraceMessage for usage details.<br/>
154 /// > EVENT_TRACE_USE_GLOBAL_SEQUENCE and EVENT_TRACE_USE_LOCAL_SEQUENCE are mutually exclusive.
155 const EVENT_TRACE_USE_GLOBAL_SEQUENCE = Etw::EVENT_TRACE_USE_GLOBAL_SEQUENCE;
156 /// > Uses sequence numbers that are unique only for an individual event tracing session. This mode only applies to events logged using the TraceMessage function. For more information, see TraceMessage for usage details.<br/>
157 /// > EVENT_TRACE_USE_GLOBAL_SEQUENCE and EVENT_TRACE_USE_LOCAL_SEQUENCE are mutually exclusive.
158 const EVENT_TRACE_USE_LOCAL_SEQUENCE = Etw::EVENT_TRACE_USE_LOCAL_SEQUENCE;
159 // EVENT_TRACE_PRIVATE_IN_PROC
160 // EVENT_TRACE_MODE_RESERVED
161 // EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN
162 // EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN
163 // EVENT_TRACE_USE_PAGED_MEMORY
164 // EVENT_TRACE_SYSTEM_LOGGER_MODE
165 // EVENT_TRACE_INDEPENDENT_SESSION_MODE
166 // EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING
167 // EVENT_TRACE_ADDTO_TRIAGE_DUMP
168 }
169}
170
171impl std::default::Default for DumpFileLoggingMode {
172 fn default() -> Self {
173 Self::EVENT_TRACE_FILE_MODE_NONE
174 }
175}
176
177/// The data source the trace is subscribed to
178#[derive(Clone, Debug)]
179pub enum SubscriptionSource {
180 /// Subscribe to a real-time session
181 RealTimeSession(U16CString),
182 /// Open an ETL file
183 FromFile(U16CString),
184}
185
186/// Wrapper over an [EVENT_TRACE_PROPERTIES](https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties), and its allocated companion members
187///
188/// The [EventTraceProperties] struct contains the information about a tracing session, this struct
189/// also needs two buffers right after it to hold the log file name and the session name. This struct
190/// provides the full definition of the properties plus the the allocation for both names
191#[repr(C)]
192#[derive(Clone, Copy)]
193pub struct EventTraceProperties {
194 etw_trace_properties: Etw::EVENT_TRACE_PROPERTIES,
195 /// The trace name to subscribe to
196 wide_trace_name: [u16; TRACE_NAME_MAX_CHARS + 1], // The +1 leaves space for the final null widechar.
197 /// The file name (if any) we store our events to
198 wide_etl_dump_file_path: [u16; TRACE_NAME_MAX_CHARS + 1], // The +1 leaves space for the final null widechar.
199}
200
201impl std::fmt::Debug for EventTraceProperties {
202 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203 let name = U16CString::from_vec_truncate(self.wide_trace_name).to_string_lossy();
204 f.debug_struct("EventTraceProperties")
205 .field("name", &name)
206 .finish()
207 }
208}
209
210impl EventTraceProperties {
211 /// Create a new instance
212 ///
213 /// # Notes
214 /// `trace_name` is limited to 200 characters.<br/>
215 /// The path to the dump file is limited to 200 characters.
216 pub(crate) fn new<T>(
217 trace_name: &U16CStr,
218 etl_dump_file: Option<(&U16CStr, DumpFileLoggingMode, Option<u32>)>,
219 trace_properties: &TraceProperties,
220 enable_flags: Etw::EVENT_TRACE_FLAG,
221 ) -> Self
222 where
223 T: RealTimeTraceTrait,
224 {
225 let mut etw_trace_properties = Etw::EVENT_TRACE_PROPERTIES::default();
226
227 etw_trace_properties.Wnode.BufferSize = std::mem::size_of::<EventTraceProperties>() as u32;
228 etw_trace_properties.Wnode.Guid = T::trace_guid();
229 etw_trace_properties.Wnode.Flags = Etw::WNODE_FLAG_TRACED_GUID;
230 etw_trace_properties.Wnode.ClientContext = 1; // QPC clock resolution
231 etw_trace_properties.BufferSize = trace_properties.buffer_size;
232 etw_trace_properties.MinimumBuffers = trace_properties.min_buffer;
233 etw_trace_properties.MaximumBuffers = trace_properties.max_buffer;
234 etw_trace_properties.FlushTimer = trace_properties
235 .flush_timer
236 .as_secs()
237 .clamp(1, u32::MAX as u64) as u32; // See https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties
238
239 if !trace_properties.log_file_mode.is_empty() {
240 etw_trace_properties.LogFileMode = trace_properties.log_file_mode.bits();
241 } else {
242 etw_trace_properties.LogFileMode = (LoggingMode::EVENT_TRACE_REAL_TIME_MODE
243 | LoggingMode::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING)
244 .bits()
245 }
246
247 etw_trace_properties.LogFileMode |= T::augmented_file_mode();
248 etw_trace_properties.EnableFlags = enable_flags;
249
250 let mut s = Self {
251 etw_trace_properties,
252 wide_trace_name: [0u16; TRACE_NAME_MAX_CHARS + 1],
253 wide_etl_dump_file_path: [0u16; TRACE_NAME_MAX_CHARS + 1],
254 };
255
256 // https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties#remarks
257 // > You do not copy the session name to the offset. The StartTrace function copies the name for you.
258 //
259 // Let's do it anyway, even though that's not required
260 let name_len = trace_name.len().min(TRACE_NAME_MAX_CHARS);
261 s.wide_trace_name[..name_len].copy_from_slice(&trace_name.as_slice()[..name_len]);
262 s.etw_trace_properties.LoggerNameOffset =
263 offset_of!(EventTraceProperties, wide_trace_name) as u32;
264
265 // Also populate the file name, if any
266 match etl_dump_file {
267 None => {
268 // Here, we do not want to dump events to a file
269 // > If you do not want to log events to a log file (for example, if you specify EVENT_TRACE_REAL_TIME_MODE only), set LogFileNameOffset to 0.
270 // (https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties)
271 s.etw_trace_properties.LogFileNameOffset = 0;
272 }
273 Some((path, file_mode, max_size)) => {
274 // Set the file path, and set the dump-file-related flags
275 let path_len = path.len().min(TRACE_NAME_MAX_CHARS);
276 s.wide_etl_dump_file_path[..path_len].copy_from_slice(&path.as_slice()[..path_len]);
277 s.etw_trace_properties.LogFileNameOffset =
278 offset_of!(EventTraceProperties, wide_etl_dump_file_path) as u32;
279
280 s.etw_trace_properties.LogFileMode |= file_mode.bits();
281 if let Some(max_file_size) = max_size {
282 s.etw_trace_properties.MaximumFileSize = max_file_size;
283 }
284 }
285 }
286
287 s
288 }
289
290 /// Gets a pointer to the wrapped [Etw::EVENT_TRACE_PROPERTIES]
291 ///
292 /// # Safety
293 ///
294 /// The API enforces this points to an allocated, valid `EVENT_TRACE_PROPERTIES` instance.
295 /// As evey other mutable raw pointer, you should not use it in case someone else is keeping a reference to this object.
296 ///
297 /// Note that `OpenTraceA` **will** modify its content on output.
298 pub unsafe fn as_mut_ptr(&mut self) -> *mut Etw::EVENT_TRACE_PROPERTIES {
299 &mut self.etw_trace_properties as *mut Etw::EVENT_TRACE_PROPERTIES
300 }
301
302 pub fn trace_name_array(&self) -> &[u16] {
303 &self.wide_trace_name
304 }
305 pub fn name(&self) -> OsString {
306 widestring::U16CStr::from_slice_truncate(&self.wide_trace_name)
307 .map(|ws| ws.to_os_string())
308 .unwrap_or_else(|_| OsString::from("<invalid name>"))
309 }
310}
311
312/// Newtype wrapper over an [EVENT_TRACE_LOGFILEW]
313///
314/// Its lifetime is tied a to [`CallbackData`] because it contains raw pointers to it.
315///
316/// [EVENT_TRACE_LOGFILEW]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Diagnostics/Etw/struct.EVENT_TRACE_LOGFILEW.html
317#[repr(C)]
318#[derive(Clone)]
319pub struct EventTraceLogfile<'callbackdata> {
320 native: Etw::EVENT_TRACE_LOGFILEW,
321 owned_subscription_source: SubscriptionSource,
322 lifetime: PhantomData<&'callbackdata CallbackData>,
323}
324
325impl<'callbackdata> EventTraceLogfile<'callbackdata> {
326 /// Create a new instance
327 #[allow(clippy::borrowed_box)] // Being Boxed is really important, let's keep the Box<...> in the function signature to make the intent clearer (see https://github.com/n4r1b/ferrisetw/issues/72)
328 pub fn create(
329 callback_data: &'callbackdata Box<Arc<CallbackData>>,
330 subscription_source: SubscriptionSource,
331 callback: unsafe extern "system" fn(*mut Etw::EVENT_RECORD),
332 ) -> Self {
333 let not_really_mut_ptr =
334 callback_data.as_ref() as *const Arc<CallbackData> as *const c_void as *mut c_void; // That's kind-of fine because the user context is _not supposed_ to be changed by Windows APIs
335
336 let native = Etw::EVENT_TRACE_LOGFILEW {
337 Anonymous2: Etw::EVENT_TRACE_LOGFILEW_1 {
338 EventRecordCallback: Some(callback),
339 },
340 Context: not_really_mut_ptr,
341 ..Default::default()
342 };
343
344 let mut log_file = Self {
345 native,
346 owned_subscription_source: subscription_source,
347 lifetime: PhantomData,
348 };
349
350 // What should we subscribe to?
351 match &mut log_file.owned_subscription_source {
352 SubscriptionSource::RealTimeSession(wide_logger_name) => {
353 log_file.native.LoggerName = PWSTR(wide_logger_name.as_mut_ptr());
354
355 log_file.native.Anonymous1 = Etw::EVENT_TRACE_LOGFILEW_0 {
356 ProcessTraceMode: Etw::PROCESS_TRACE_MODE_REAL_TIME
357 | Etw::PROCESS_TRACE_MODE_EVENT_RECORD, // In case you really want to use PROCESS_TRACE_MODE_RAW_TIMESTAMP, please review EventRecord::timestamp(), which could not be valid anymore
358 };
359 }
360 SubscriptionSource::FromFile(wide_file_name) => {
361 log_file.native.LogFileName = PWSTR(wide_file_name.as_mut_ptr());
362
363 log_file.native.Anonymous1 = Etw::EVENT_TRACE_LOGFILEW_0 {
364 ProcessTraceMode: Etw::PROCESS_TRACE_MODE_EVENT_RECORD, // In case you really want to use PROCESS_TRACE_MODE_RAW_TIMESTAMP, please review EventRecord::timestamp(), which could not be valid anymore
365 };
366 }
367 }
368
369 log_file
370 }
371
372 /// Retrieve the windows-rs compatible pointer to the contained `EVENT_TRACE_LOGFILEA`
373 ///
374 /// # Safety
375 ///
376 /// This pointer is valid as long as [`Self`] is alive (and not modified elsewhere)<br/>
377 /// Note that `OpenTraceW` **will** modify its content on output, and thus you should make sure to be the only user of this instance.
378 pub(crate) unsafe fn as_mut_ptr(&mut self) -> *mut Etw::EVENT_TRACE_LOGFILEW {
379 &mut self.native as *mut Etw::EVENT_TRACE_LOGFILEW
380 }
381
382 /// The current Context pointer.
383 pub fn context_ptr(&self) -> *const std::ffi::c_void {
384 self.native.Context
385 }
386}
387
388/// Newtype wrapper over an [ENABLE_TRACE_PARAMETERS]
389///
390/// [ENABLE_TRACE_PARAMETERS]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Diagnostics/Etw/struct.ENABLE_TRACE_PARAMETERS.html
391#[repr(C)]
392#[derive(Clone, Default)]
393pub struct EnableTraceParameters<'filters> {
394 native: Etw::ENABLE_TRACE_PARAMETERS,
395 /// `native` has pointers to an array of EVENT_FILTER_DESCRIPTOR, let's store it here
396 array_of_event_filter_descriptor: Vec<EVENT_FILTER_DESCRIPTOR>,
397 /// `array_of_event_filter_descriptor` points to data somewhere else. Let's bind it to their lifetime
398 lifetime: PhantomData<&'filters EventFilterDescriptor>,
399}
400
401impl<'filters> EnableTraceParameters<'filters> {
402 pub fn create(
403 guid: GUID,
404 trace_flags: TraceFlags,
405 filters: &'filters [EventFilterDescriptor],
406 ) -> Self {
407 let mut params = EnableTraceParameters::default();
408 params.native.ControlFlags = 0;
409 params.native.Version = Etw::ENABLE_TRACE_PARAMETERS_VERSION_2;
410 params.native.SourceId = guid;
411 params.native.EnableProperty = trace_flags.bits();
412
413 // Note: > Each type of filter (a specific Type member) may only appear once in a call to the EnableTraceEx2 function.
414 // https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-enabletraceex2#remarks
415 // > The maximum number of filters that can be included in a call to EnableTraceEx2 is set by MAX_EVENT_FILTERS_COUNT
416 params.array_of_event_filter_descriptor = filters
417 .iter()
418 .map(|efd| efd.as_event_filter_descriptor())
419 .collect();
420 params.native.FilterDescCount = params.array_of_event_filter_descriptor.len() as u32; // (let's assume we won't try to fit more than 4 billion filters)
421 if filters.is_empty() {
422 params.native.EnableFilterDesc = std::ptr::null_mut();
423 } else {
424 params.native.EnableFilterDesc = params.array_of_event_filter_descriptor.as_mut_ptr();
425 }
426
427 params
428 }
429
430 /// Returns an unsafe pointer over the wrapped `ENABLE_TRACE_PARAMETERS`
431 ///
432 /// # Safety
433 ///
434 /// This pointer is valid as long `self` is valid (and not mutated)
435 pub fn as_ptr(&self) -> *const Etw::ENABLE_TRACE_PARAMETERS {
436 &self.native as *const _
437 }
438}
439
440/// Wrapper over the [DECODING_SOURCE] type
441///
442/// [DECODING_SOURCE]: https://learn.microsoft.com/en-us/windows/win32/api/tdh/ne-tdh-decoding_source
443#[derive(Debug)]
444pub enum DecodingSource {
445 DecodingSourceXMLFile,
446 DecodingSourceWbem,
447 DecodingSourceWPP,
448 DecodingSourceTlg,
449 DecodingSourceMax,
450}
451
452impl From<Etw::DECODING_SOURCE> for DecodingSource {
453 fn from(val: Etw::DECODING_SOURCE) -> Self {
454 match val {
455 Etw::DecodingSourceXMLFile => DecodingSource::DecodingSourceXMLFile,
456 Etw::DecodingSourceWbem => DecodingSource::DecodingSourceWbem,
457 Etw::DecodingSourceWPP => DecodingSource::DecodingSourceWPP,
458 Etw::DecodingSourceTlg => DecodingSource::DecodingSourceTlg,
459 _ => DecodingSource::DecodingSourceMax,
460 }
461 }
462}
463
464// Safe cast (EVENT_HEADER_FLAG_32_BIT_HEADER = 32)
465#[doc(hidden)]
466pub const EVENT_HEADER_FLAG_32_BIT_HEADER: u16 = Etw::EVENT_HEADER_FLAG_32_BIT_HEADER as u16;