1
1
//! A module to handle Extended Data from ETW traces
2
2
3
+ use std:: { ffi:: CStr , mem} ;
3
4
use windows:: core:: GUID ;
4
5
use windows:: Win32 :: Security :: SID ;
5
6
use windows:: Win32 :: System :: Diagnostics :: Etw :: {
6
7
EVENT_EXTENDED_ITEM_RELATED_ACTIVITYID , EVENT_EXTENDED_ITEM_TS_ID ,
7
8
} ;
8
9
use windows:: Win32 :: System :: Diagnostics :: Etw :: {
9
10
EVENT_HEADER_EXTENDED_DATA_ITEM , EVENT_HEADER_EXT_TYPE_EVENT_KEY ,
10
- EVENT_HEADER_EXT_TYPE_INSTANCE_INFO , EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY ,
11
- EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID , EVENT_HEADER_EXT_TYPE_SID ,
12
- EVENT_HEADER_EXT_TYPE_STACK_TRACE32 , EVENT_HEADER_EXT_TYPE_STACK_TRACE64 ,
13
- EVENT_HEADER_EXT_TYPE_TS_ID ,
11
+ EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL , EVENT_HEADER_EXT_TYPE_INSTANCE_INFO ,
12
+ EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY , EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID ,
13
+ EVENT_HEADER_EXT_TYPE_SID , EVENT_HEADER_EXT_TYPE_STACK_TRACE32 ,
14
+ EVENT_HEADER_EXT_TYPE_STACK_TRACE64 , EVENT_HEADER_EXT_TYPE_TS_ID ,
14
15
} ;
15
16
16
17
// These types are returned by our public API. Let's use their re-exported versions
@@ -28,7 +29,7 @@ pub struct EventHeaderExtendedDataItem(EVENT_HEADER_EXTENDED_DATA_ITEM);
28
29
/// See <https://docs.microsoft.com/en-us/windows/win32/api/relogger/ns-relogger-event_header_extended_data_item>
29
30
#[ derive( Debug ) ]
30
31
pub enum ExtendedDataItem {
31
- /// Unexpected or invalid ( or not implemented yet in Ferrisetw) extended data type
32
+ /// Unexpected, invalid or not implemented yet
32
33
Unsupported ,
33
34
/// Related activity identifier
34
35
RelatedActivityId ( GUID ) ,
@@ -41,9 +42,8 @@ pub enum ExtendedDataItem {
41
42
StackTrace32 ( EVENT_EXTENDED_ITEM_STACK_TRACE32 ) ,
42
43
/// Call stack (if the event is captured on a 64-bit computer)
43
44
StackTrace64 ( EVENT_EXTENDED_ITEM_STACK_TRACE64 ) ,
44
- // TODO: implement them, but the documentation does not clearly define what they are supposed to contain
45
- // /// TraceLogging event metadata information
46
- // SchemaTl,
45
+ /// TraceLogging event metadata information
46
+ TraceLogging ( String ) ,
47
47
// /// Provider traits data
48
48
// /// (for example traits set through EventSetInformation(EventProviderSetTraits) or specified through EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA)
49
49
// ProvTraits,
@@ -61,7 +61,12 @@ impl EventHeaderExtendedDataItem {
61
61
self . 0 . ExtType
62
62
}
63
63
64
+ pub fn is_tlg ( & self ) -> bool {
65
+ self . 0 . ExtType as u32 == EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL
66
+ }
67
+
64
68
/// Returns this extended data as a variant of a Rust enum.
69
+ // TODO: revisit this function
65
70
pub fn to_extended_data_item ( & self ) -> ExtendedDataItem {
66
71
let data_ptr = self . 0 . DataPtr as * const std:: ffi:: c_void ;
67
72
if data_ptr. is_null ( ) {
@@ -109,7 +114,83 @@ impl EventHeaderExtendedDataItem {
109
114
ExtendedDataItem :: EventKey ( unsafe { * data_ptr } )
110
115
}
111
116
117
+ EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL => {
118
+ ExtendedDataItem :: TraceLogging ( unsafe { self . get_event_name ( ) . unwrap_or_default ( ) } )
119
+ }
120
+
112
121
_ => ExtendedDataItem :: Unsupported ,
113
122
}
114
123
}
124
+
125
+ ///
126
+ /// This function will parse the `_tlgEventMetadata_t` to retrieve the EventName
127
+ ///
128
+ /// For more info see `_tlgEventMetadata_t` in `TraceLoggingProvider.h` (Windows SDK)
129
+ ///
130
+ /// ```cpp
131
+ /// struct _tlgEventMetadata_t
132
+ /// {
133
+ /// UINT8 Type; // = _TlgBlobEvent4
134
+ /// UCHAR Channel;
135
+ /// UCHAR Level;
136
+ /// UCHAR Opcode;
137
+ /// ULONGLONG Keyword;
138
+ /// UINT16 RemainingSize; // = sizeof(RemainingSize + Tags + EventName + Fields)
139
+ /// UINT8 Tags[]; // 1 or more bytes. Read until you hit a byte with high bit unset.
140
+ /// char EventName[sizeof("eventName")]; // UTF-8 nul-terminated event name
141
+ /// for each field {
142
+ /// char FieldName[sizeof("fieldName")];
143
+ /// UINT8 InType;
144
+ /// UINT8 OutType;
145
+ /// UINT8 Tags[];
146
+ /// UINT16 ValueCount;
147
+ /// UINT16 TypeInfoSize;
148
+ /// char TypeInfo[TypeInfoSize];
149
+ /// }
150
+ /// }
151
+ /// ```
152
+ ///
153
+ /// We are only interested on `EventName` so we will only consider the first three members.
154
+ ///
155
+ /// # Safety
156
+ ///
157
+ /// As per the MS header 'This structure may change in future revisions of this header.'
158
+ /// **Keep an eye on it!**
159
+ ///
160
+ // TODO: Make this function more robust
161
+ unsafe fn get_event_name ( & self ) -> Option < String > {
162
+ const TAGS_SIZE : usize = 1 ;
163
+ debug_assert ! ( self . is_tlg( ) ) ;
164
+
165
+ let mut data_ptr = self . 0 . DataPtr as * const u8 ;
166
+ if data_ptr. is_null ( ) {
167
+ return None ;
168
+ }
169
+
170
+ let size = data_ptr. read_unaligned ( ) as u16 ;
171
+ data_ptr = data_ptr. add ( mem:: size_of :: < u16 > ( ) ) ;
172
+
173
+ let mut n = 0 ;
174
+ while n < size {
175
+ // Read until you hit a byte with high bit unset.
176
+ let tag = data_ptr. read_unaligned ( ) ;
177
+ data_ptr = data_ptr. add ( TAGS_SIZE ) ;
178
+
179
+ if tag & 0b1000_0000 == 0 {
180
+ break ;
181
+ }
182
+
183
+ n += 1 ;
184
+ }
185
+
186
+ // If debug let's assert here since this is a case we want to investigate
187
+ debug_assert ! ( n != size) ;
188
+ if n == size {
189
+ return None ;
190
+ }
191
+
192
+ Some ( String :: from (
193
+ CStr :: from_ptr ( data_ptr as * const _ ) . to_string_lossy ( ) ,
194
+ ) )
195
+ }
115
196
}
0 commit comments