3 * Copyright 2020, Odysseus Yang
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define WS_LOG_DOMAIN "etwdump"
14 #include "etw_message.h"
15 #include <wsutil/wslog.h>
16 ULONGLONG g_num_events
= 0;
18 VOID
format_message(WCHAR
* lpszMessage
, PROPERTY_KEY_VALUE
* propArray
, DWORD dwPropertyCount
, WCHAR
* lpszOutBuffer
, DWORD dwOutBufferCount
)
23 for (int i
= 0; lpszMessage
[i
] != L
'\0';)
25 if (lpszMessage
[i
] != L
'%')
30 if (lpszMessage
[i
+ 1] == '%')
39 if (iswdigit(lpszMessage
[i
]))
41 DWORD dwDigitalCount
= 0;
42 WCHAR smallBuffer
[MAX_SMALL_BUFFER
] = { 0 };
43 while (iswdigit(lpszMessage
[i
]))
45 if (dwDigitalCount
< (MAX_SMALL_BUFFER
- 1))
47 smallBuffer
[dwDigitalCount
] = lpszMessage
[i
];
53 /* We are not parsing this */
54 if (dwDigitalCount
>= (MAX_SMALL_BUFFER
- 1))
58 DWORD num
= _wtoi(smallBuffer
);
59 /* We are not parsing this */
60 if (num
== 0 || num
> dwPropertyCount
|| propArray
[num
- 1].value
[0] == L
'\0')
65 if (lpszMessage
[i
] == L
'!' && lpszMessage
[i
+ 1] == L
'S' && lpszMessage
[i
+ 2] == L
'!')
70 /* We have everything */
71 lpszMessage
[percent_loc
] = L
'\0';
72 StringCbCat(lpszOutBuffer
, dwOutBufferCount
, lpszMessage
+ startLoc
);
73 StringCbCat(lpszOutBuffer
, dwOutBufferCount
, propArray
[num
- 1].value
);
78 StringCbCat(lpszOutBuffer
, dwOutBufferCount
, lpszMessage
+ startLoc
);
82 * Get the length of the property data. For MOF-based events, the size is inferred from the data type
83 * of the property. For manifest-based events, the property can specify the size of the property value
84 * using the length attribute. The length attribue can specify the size directly or specify the name
85 * of another property in the event data that contains the size. If the property does not include the
86 * length attribute, the size is inferred from the data type. The length will be zero for variable
87 * length, null-terminated strings and structures.
89 DWORD
GetPropertyLength(PEVENT_RECORD pEvent
, PTRACE_EVENT_INFO pInfo
, USHORT i
, PUSHORT PropertyLength
)
91 DWORD status
= ERROR_SUCCESS
;
92 PROPERTY_DATA_DESCRIPTOR DataDescriptor
= { 0 };
93 DWORD PropertySize
= 0;
96 * If the property is a binary blob and is defined in a manifest, the property can
97 * specify the blob's size or it can point to another property that defines the
98 * blob's size. The PropertyParamLength flag tells you where the blob's size is defined.
100 if ((pInfo
->EventPropertyInfoArray
[i
].Flags
& PropertyParamLength
) == PropertyParamLength
)
102 DWORD Length
= 0; // Expects the length to be defined by a UINT16 or UINT32
103 DWORD j
= pInfo
->EventPropertyInfoArray
[i
].lengthPropertyIndex
;
104 DataDescriptor
.PropertyName
= ((ULONGLONG
)(pInfo
)+(ULONGLONG
)pInfo
->EventPropertyInfoArray
[j
].NameOffset
);
105 DataDescriptor
.ArrayIndex
= ULONG_MAX
;
106 status
= TdhGetPropertySize(pEvent
, 0, NULL
, 1, &DataDescriptor
, &PropertySize
);
107 status
= TdhGetProperty(pEvent
, 0, NULL
, 1, &DataDescriptor
, PropertySize
, (PBYTE
)&Length
);
108 *PropertyLength
= (USHORT
)Length
;
112 if (pInfo
->EventPropertyInfoArray
[i
].length
> 0)
114 *PropertyLength
= pInfo
->EventPropertyInfoArray
[i
].length
;
119 * If the property is a binary blob and is defined in a MOF class, the extension
120 * qualifier is used to determine the size of the blob. However, if the extension
121 * is IPAddrV6, you must set the PropertyLength variable yourself because the
122 * EVENT_PROPERTY_INFO.length field will be zero.
124 if (TDH_INTYPE_BINARY
== pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
&&
125 TDH_OUTTYPE_IPV6
== pInfo
->EventPropertyInfoArray
[i
].nonStructType
.OutType
)
127 *PropertyLength
= (USHORT
)sizeof(IN6_ADDR
);
129 else if (TDH_INTYPE_UNICODESTRING
== pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
||
130 TDH_INTYPE_ANSISTRING
== pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
||
131 (pInfo
->EventPropertyInfoArray
[i
].Flags
& PropertyStruct
) == PropertyStruct
)
133 *PropertyLength
= pInfo
->EventPropertyInfoArray
[i
].length
;
137 ws_debug("Event %d Unexpected length of 0 for intype %d and outtype %d", g_num_events
,
138 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
,
139 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.OutType
);
141 status
= ERROR_EVT_INVALID_EVENT_DATA
;
150 DWORD
GetArraySize(PEVENT_RECORD pEvent
, PTRACE_EVENT_INFO pInfo
, USHORT i
, PUSHORT ArraySize
)
152 DWORD status
= ERROR_SUCCESS
;
153 PROPERTY_DATA_DESCRIPTOR DataDescriptor
= { 0 };
154 DWORD PropertySize
= 0;
156 if ((pInfo
->EventPropertyInfoArray
[i
].Flags
& PropertyParamCount
) == PropertyParamCount
)
158 /* Expects the count to be defined by a UINT16 or UINT32 */
160 DWORD j
= pInfo
->EventPropertyInfoArray
[i
].countPropertyIndex
;
161 DataDescriptor
.PropertyName
= ((ULONGLONG
)(pInfo
)+(ULONGLONG
)(pInfo
->EventPropertyInfoArray
[j
].NameOffset
));
162 DataDescriptor
.ArrayIndex
= ULONG_MAX
;
163 status
= TdhGetPropertySize(pEvent
, 0, NULL
, 1, &DataDescriptor
, &PropertySize
);
164 status
= TdhGetProperty(pEvent
, 0, NULL
, 1, &DataDescriptor
, PropertySize
, (PBYTE
)&Count
);
165 *ArraySize
= (USHORT
)Count
;
169 *ArraySize
= pInfo
->EventPropertyInfoArray
[i
].count
;
174 DWORD
GetMapInfo(PEVENT_RECORD pEvent
, LPWSTR pMapName
, PEVENT_MAP_INFO
* pMapInfo
)
176 DWORD status
= ERROR_SUCCESS
;
179 /* Retrieve the required buffer size for the map info. */
180 status
= TdhGetEventMapInformation(pEvent
, pMapName
, *pMapInfo
, &MapSize
);
181 if (ERROR_INSUFFICIENT_BUFFER
== status
)
183 *pMapInfo
= (PEVENT_MAP_INFO
)g_malloc(MapSize
);
184 if (*pMapInfo
== NULL
)
186 status
= ERROR_OUTOFMEMORY
;
189 /* Retrieve the map info. */
190 status
= TdhGetEventMapInformation(pEvent
, pMapName
, *pMapInfo
, &MapSize
);
193 if (ERROR_NOT_FOUND
== status
)
195 /* This case is okay. */
196 status
= ERROR_SUCCESS
;
205 PBYTE
extract_properties(PEVENT_RECORD pEvent
, PTRACE_EVENT_INFO pInfo
, DWORD PointerSize
, USHORT i
, PBYTE pUserData
, PBYTE pEndOfUserData
, PROPERTY_KEY_VALUE
* pExtract
)
207 TDHSTATUS status
= ERROR_SUCCESS
;
208 USHORT PropertyLength
= 0;
209 USHORT UserDataConsumed
= 0;
210 /* Last member of a structure */
211 DWORD LastMember
= 0;
212 USHORT ArraySize
= 0;
213 PEVENT_MAP_INFO pMapInfo
= NULL
;
214 WCHAR formatted_data
[MAX_LOG_LINE_LENGTH
];
215 DWORD formatted_data_size
= sizeof(formatted_data
);
216 LPWSTR oversize_formatted_data
= NULL
;
220 StringCbCopy(pExtract
->key
, sizeof(pExtract
->key
), (PWCHAR
)((PBYTE
)(pInfo
)+pInfo
->EventPropertyInfoArray
[i
].NameOffset
));
221 /* Get the length of the property. */
222 status
= GetPropertyLength(pEvent
, pInfo
, i
, &PropertyLength
);
223 if (ERROR_SUCCESS
!= status
)
225 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: GetPropertyLength failed 0x%x", pExtract
->key
, status
);
229 /* Get the size of the array if the property is an array. */
230 status
= GetArraySize(pEvent
, pInfo
, i
, &ArraySize
);
231 if (ERROR_SUCCESS
!= status
)
233 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: GetArraySize failed 0x%x", pExtract
->key
, status
);
237 /* Add [] for an array property */
240 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
"[");
243 for (USHORT k
= 0; k
< ArraySize
; k
++)
245 /* Add array item separator "," */
248 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
",");
250 /* If the property is a structure, print the members of the structure. */
251 if ((pInfo
->EventPropertyInfoArray
[i
].Flags
& PropertyStruct
) == PropertyStruct
)
253 /* Add {} for an array property */
254 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
"{");
255 /* Add struct member separator ";" */
258 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
";");
260 LastMember
= pInfo
->EventPropertyInfoArray
[i
].structType
.StructStartIndex
+
261 pInfo
->EventPropertyInfoArray
[i
].structType
.NumOfStructMembers
;
263 for (USHORT j
= pInfo
->EventPropertyInfoArray
[i
].structType
.StructStartIndex
; j
< LastMember
; j
++)
265 pUserData
= extract_properties(pEvent
, pInfo
, PointerSize
, j
, pUserData
, pEndOfUserData
, pExtract
);
266 if (NULL
== pUserData
)
268 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: extract_properties of member %d failed 0x%x", pExtract
->key
, j
, status
);
272 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
"}");
276 /* Get the name/value mapping only at the first time if the property specifies a value map. */
277 if (pMapInfo
== NULL
)
279 status
= GetMapInfo(pEvent
,
280 (PWCHAR
)((PBYTE
)(pInfo
)+pInfo
->EventPropertyInfoArray
[i
].nonStructType
.MapNameOffset
),
283 if (ERROR_SUCCESS
!= status
)
285 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: GetMapInfo failed 0x%x", pExtract
->key
, status
);
290 /* Get the size of the buffer required for the formatted data. */
292 status
= TdhFormatProperty(
296 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
,
297 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.OutType
,
299 (USHORT
)(pEndOfUserData
- pUserData
),
301 &formatted_data_size
,
305 if (ERROR_INSUFFICIENT_BUFFER
== status
)
307 if (oversize_formatted_data
)
309 g_free(oversize_formatted_data
);
310 oversize_formatted_data
= NULL
;
313 oversize_formatted_data
= (LPWSTR
)g_malloc(formatted_data_size
);
314 if (oversize_formatted_data
== NULL
)
316 status
= ERROR_OUTOFMEMORY
;
317 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: Allocate FormattedData memory (size %d) for array item %d failed 0x%x", pExtract
->key
, formatted_data_size
, k
, status
);
321 /* Retrieve the formatted data. */
322 status
= TdhFormatProperty(
326 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.InType
,
327 pInfo
->EventPropertyInfoArray
[i
].nonStructType
.OutType
,
329 (USHORT
)(pEndOfUserData
- pUserData
),
331 &formatted_data_size
,
332 oversize_formatted_data
,
336 if (ERROR_SUCCESS
== status
)
338 if (formatted_data_size
> sizeof(formatted_data
) && oversize_formatted_data
!= NULL
)
340 /* Any oversize FormattedData will be truncated */
341 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), oversize_formatted_data
);
345 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), formatted_data
);
347 pUserData
+= UserDataConsumed
;
351 StringCbPrintf(pExtract
->value
, sizeof(pExtract
->value
), L
"%s: TdhFormatProperty for array item %d failed 0x%x", pExtract
->key
, k
, status
);
356 /* Add [] for an array property */
359 StringCbCat(pExtract
->value
, sizeof(pExtract
->value
), L
"]");
363 if (oversize_formatted_data
)
365 g_free(oversize_formatted_data
);
366 oversize_formatted_data
= NULL
;
374 return (ERROR_SUCCESS
== status
) ? pUserData
: NULL
;
378 BOOL
get_event_information(PEVENT_RECORD pEvent
, PTRACE_EVENT_INFO
* pInfo
)
380 BOOL bReturn
= false;
382 DWORD BufferSize
= 0;
384 /* Retrieve the required buffer size for the event metadata. */
385 status
= TdhGetEventInformation(pEvent
, 0, NULL
, *pInfo
, &BufferSize
);
386 if (ERROR_INSUFFICIENT_BUFFER
== status
)
388 *pInfo
= (TRACE_EVENT_INFO
*)g_malloc(BufferSize
);
391 ws_debug("Event %d GetEventInformation Failed to allocate memory for event info (size=%lu).", g_num_events
, BufferSize
);
394 /* Retrieve the event metadata. */
395 status
= TdhGetEventInformation(pEvent
, 0, NULL
, *pInfo
, &BufferSize
);
398 if (ERROR_SUCCESS
!= status
)
409 * Editor modelines - https://www.wireshark.org/tools/modelines.html
414 * indent-tabs-mode: nil
417 * vi: set shiftwidth=4 tabstop=8 expandtab:
418 * :indentSize=4:tabSize=8:noTabs=true: