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
13 * Reads an ETL file and writes out a pcap file with LINKTYPE_ETW.
15 * https://docs.microsoft.com/en-us/windows/win32/etw/event-tracing-portal
19 #define WS_LOG_DOMAIN "etwdump"
22 #include "wsutil/ws_getopt.h"
23 #include "wsutil/strtoi.h"
24 #include "etw_message.h"
29 #define MAX_PACKET_SIZE 0xFFFF
30 #define G_NSEC_PER_SEC 1000000000
31 #define ADD_OFFSET_TO_POINTER(buffer, offset) (((PBYTE)buffer) + offset)
32 #define ROUND_UP_COUNT(Count,Pow2) \
33 ( ((Count)+(Pow2)-1) & (~(((int)(Pow2))-1)) )
35 extern int g_include_undecidable_event
;
37 //Microsoft-Windows-Wmbclass-Opn
38 const GUID mbb_provider
= { 0xA42FE227, 0xA7BF, 0x4483, {0xA5, 0x02, 0x6B, 0xCD, 0xA4, 0x28, 0xCD, 0x96} };
39 // Microsoft-Windows-NDIS-PacketCapture
40 const GUID ndis_capture_provider
= { 0x2ed6006e, 0x4729, 0x4609, 0xb4, 0x23, 0x3e, 0xe7, 0xbc, 0xd6, 0x78, 0xef };
42 EXTERN_C
const GUID DECLSPEC_SELECTANY EventTraceGuid
= { 0x68fdd900, 0x4a3e, 0x11d1, {0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3} };
43 EXTERN_C
const GUID DECLSPEC_SELECTANY ImageIdGuid
= { 0xb3e675d7, 0x2554, 0x4f18, { 0x83, 0xb, 0x27, 0x62, 0x73, 0x25, 0x60, 0xde } };
44 EXTERN_C
const GUID DECLSPEC_SELECTANY SystemConfigExGuid
= { 0x9b79ee91, 0xb5fd, 0x41c0, { 0xa2, 0x43, 0x42, 0x48, 0xe2, 0x66, 0xe9, 0xd0 } };
45 EXTERN_C
const GUID DECLSPEC_SELECTANY EventMetadataGuid
= { 0xbbccf6c1, 0x6cd1, 0x48c4, {0x80, 0xff, 0x83, 0x94, 0x82, 0xe3, 0x76, 0x71 } };
46 EXTERN_C
const GUID DECLSPEC_SELECTANY ZeroGuid
= { 0 };
48 typedef struct _WTAP_ETL_RECORD
{
49 EVENT_HEADER EventHeader
; // Event header
50 ETW_BUFFER_CONTEXT BufferContext
; // Buffer context
62 static struct ws_option longopts
[] = {
63 { "p", ws_required_argument
, NULL
, OPT_PROVIDER
},
64 { "k", ws_required_argument
, NULL
, OPT_KEYWORD
},
65 { "l", ws_required_argument
, NULL
, OPT_LEVEL
},
69 typedef struct _PROVIDER_FILTER
{
75 char g_err_info
[FILENAME_MAX
] = { 0 };
76 int g_err
= ERROR_SUCCESS
;
77 static wtap_dumper
* g_pdh
= NULL
;
78 extern ULONGLONG g_num_events
;
79 static PROVIDER_FILTER g_provider_filters
[32] = { 0 };
80 static BOOL g_is_live_session
= false;
82 static void WINAPI
event_callback(PEVENT_RECORD ev
);
83 void etw_dump_write_opn_event(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
);
84 void etw_dump_write_ndiscap_event(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
);
85 void etw_dump_write_general_event(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
);
86 void etw_dump_write_event_head_only(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
);
87 void wtap_etl_rec_dump(char* etl_record
, ULONG total_packet_length
, ULONG original_packet_length
, unsigned int interface_id
, BOOLEAN is_inbound
, ULARGE_INTEGER timestamp
, int pkt_encap
, char* comment
, unsigned short comment_length
);
88 wtap_dumper
* etw_dump_open(const char* pcapng_filename
, int* err
, char** err_info
);
90 DWORD
GetPropertyValue(WCHAR
* ProviderId
, EVT_PUBLISHER_METADATA_PROPERTY_ID PropertyId
, PEVT_VARIANT
* Value
)
93 DWORD err
= ERROR_SUCCESS
;
94 PEVT_VARIANT value
= NULL
;
96 DWORD bufUsedOrReqd
= 0;
98 EVT_HANDLE pubHandle
= EvtOpenPublisherMetadata(NULL
, ProviderId
, NULL
, GetThreadLocale(), 0);
99 if (pubHandle
== NULL
)
101 return GetLastError();
105 * Get required size for property
107 bRet
= EvtGetPublisherMetadataProperty(
115 if (!bRet
&& ((err
= GetLastError()) != ERROR_INSUFFICIENT_BUFFER
))
119 else if (bRet
) /* Didn't expect this to succeed */
121 return ERROR_INVALID_STATE
;
124 value
= (PEVT_VARIANT
)g_malloc(bufUsedOrReqd
);
127 return ERROR_INSUFFICIENT_BUFFER
;
129 bufSize
= bufUsedOrReqd
;
132 * Get the property value
134 bRet
= EvtGetPublisherMetadataProperty(
144 return GetLastError();
148 return ERROR_SUCCESS
;
151 wtap_open_return_val
etw_dump(const char* etl_filename
, const char* pcapng_filename
, const char* params
, int* err
, char** err_info
)
153 EVENT_TRACE_LOGFILE log_file
= { 0 };
154 WCHAR w_etl_filename
[FILENAME_MAX
] = { 0 };
155 wtap_open_return_val returnVal
= WTAP_OPEN_MINE
;
157 SUPER_EVENT_TRACE_PROPERTIES super_trace_properties
= { 0 };
158 super_trace_properties
.prop
.Wnode
.BufferSize
= sizeof(SUPER_EVENT_TRACE_PROPERTIES
);
159 super_trace_properties
.prop
.Wnode
.ClientContext
= 2;
160 super_trace_properties
.prop
.Wnode
.Flags
= WNODE_FLAG_TRACED_GUID
;
161 super_trace_properties
.prop
.LoggerNameOffset
= sizeof(EVENT_TRACE_PROPERTIES
);
162 super_trace_properties
.prop
.LogFileMode
= EVENT_TRACE_REAL_TIME_MODE
;
163 TRACEHANDLE traceControllerHandle
= (TRACEHANDLE
)INVALID_HANDLE_VALUE
;
164 TRACEHANDLE trace_handle
= INVALID_PROCESSTRACE_HANDLE
;
166 SecureZeroMemory(g_provider_filters
, sizeof(g_provider_filters
));
167 SecureZeroMemory(g_err_info
, FILENAME_MAX
);
168 g_err
= ERROR_SUCCESS
;
170 g_is_live_session
= false;
176 int provider_idx
= 0;
177 char** params_array
= NULL
;
178 int params_array_num
= 0;
179 WCHAR provider_id
[FILENAME_MAX
] = { 0 };
180 ULONG convert_level
= 0;
182 params_array
= g_strsplit(params
, " ", -1);
183 while (params_array
[params_array_num
])
189 while ((opt_result
= ws_getopt_long(params_array_num
, params_array
, ":", longopts
, &option_idx
)) != -1) {
190 switch (opt_result
) {
192 mbstowcs(provider_id
, ws_optarg
, FILENAME_MAX
);
193 if (UuidFromString(provider_id
, &g_provider_filters
[provider_idx
].ProviderId
) == RPC_S_INVALID_STRING_UUID
)
195 PEVT_VARIANT value
= NULL
;
197 *err
= GetPropertyValue(
199 EvtPublisherMetadataPublisherGuid
,
203 * Copy returned GUID locally
205 if (*err
== ERROR_SUCCESS
)
207 if (value
->Type
== EvtVarTypeGuid
&& value
->GuidVal
)
209 g_provider_filters
[provider_idx
].ProviderId
= *(value
->GuidVal
);
213 *err
= ERROR_INVALID_DATA
;
218 *err_info
= ws_strdup_printf("Cannot convert provider %s to a GUID, err is 0x%x", ws_optarg
, *err
);
219 return WTAP_OPEN_ERROR
;
225 if (IsEqualGUID(&g_provider_filters
[0].ProviderId
, &ZeroGuid
))
227 *err
= ERROR_INVALID_PARAMETER
;
228 *err_info
= ws_strdup_printf("Provider %s is zero, err is 0x%x", ws_optarg
, *err
);
229 return WTAP_OPEN_ERROR
;
234 if (provider_idx
== 0)
236 *err
= ERROR_INVALID_PARAMETER
;
237 *err_info
= ws_strdup_printf("-k parameter must follow -p, err is 0x%x", *err
);
238 return WTAP_OPEN_ERROR
;
241 g_provider_filters
[provider_idx
- 1].Keyword
= _strtoui64(ws_optarg
, NULL
, 0);
242 if (!g_provider_filters
[provider_idx
- 1].Keyword
)
244 *err
= ERROR_INVALID_PARAMETER
;
245 *err_info
= ws_strdup_printf("Keyword %s cannot be converted, err is 0x%x", ws_optarg
, *err
);
246 return WTAP_OPEN_ERROR
;
250 if (provider_idx
== 0)
252 *err
= ERROR_INVALID_PARAMETER
;
253 *err_info
= ws_strdup_printf("-l parameter must follow -p, err is 0x%x", *err
);
254 return WTAP_OPEN_ERROR
;
257 convert_level
= strtoul(ws_optarg
, NULL
, 0);
258 if (convert_level
> UCHAR_MAX
)
260 *err
= ERROR_INVALID_PARAMETER
;
261 *err_info
= ws_strdup_printf("Level %s is bigger than 0xff, err is 0x%x", ws_optarg
, *err
);
262 return WTAP_OPEN_ERROR
;
266 *err
= ERROR_INVALID_PARAMETER
;
267 *err_info
= ws_strdup_printf("Level %s cannot be converted, err is 0x%x", ws_optarg
, *err
);
268 return WTAP_OPEN_ERROR
;
271 g_provider_filters
[provider_idx
- 1].Level
= (UCHAR
)convert_level
;
275 g_strfreev(params_array
);
278 /* do/while(false) is used to jump out of loop so no complex nested if/else is needed */
281 /* Read ETW from an etl file */
284 mbstowcs(w_etl_filename
, etl_filename
, FILENAME_MAX
);
286 log_file
.LogFileName
= w_etl_filename
;
287 log_file
.ProcessTraceMode
= PROCESS_TRACE_MODE_EVENT_RECORD
;
288 log_file
.EventRecordCallback
= event_callback
;
289 log_file
.Context
= NULL
;
294 * Try the best to stop the leftover session since extcap has no way to cleanup when stop capturing. See issue
295 * https://gitlab.com/wireshark/wireshark/-/issues/17131
297 ControlTrace((TRACEHANDLE
)NULL
, LOGGER_NAME
, &super_trace_properties
.prop
, EVENT_TRACE_CONTROL_STOP
);
299 g_is_live_session
= true;
301 log_file
.LoggerName
= LOGGER_NAME
;
302 log_file
.LogFileName
= NULL
;
303 log_file
.ProcessTraceMode
= PROCESS_TRACE_MODE_REAL_TIME
| PROCESS_TRACE_MODE_EVENT_RECORD
;
304 log_file
.EventRecordCallback
= event_callback
;
305 log_file
.BufferCallback
= NULL
;
306 log_file
.Context
= NULL
;
309 &traceControllerHandle
,
311 &super_trace_properties
.prop
);
312 if (*err
!= ERROR_SUCCESS
)
314 *err_info
= ws_strdup_printf("StartTrace failed with 0x%x", *err
);
315 returnVal
= WTAP_OPEN_ERROR
;
319 for (int i
= 0; i
< ARRAYSIZE(g_provider_filters
); i
++)
321 if (IsEqualGUID(&g_provider_filters
[i
].ProviderId
, &ZeroGuid
))
325 *err
= EnableTraceEx(
326 &g_provider_filters
[i
].ProviderId
,
328 traceControllerHandle
,
330 g_provider_filters
[i
].Level
,
331 g_provider_filters
[i
].Keyword
,
335 if (*err
!= ERROR_SUCCESS
)
337 *err_info
= ws_strdup_printf("EnableTraceEx failed with 0x%x", *err
);
338 returnVal
= WTAP_OPEN_ERROR
;
344 trace_handle
= OpenTrace(&log_file
);
345 if (trace_handle
== INVALID_PROCESSTRACE_HANDLE
) {
346 *err
= GetLastError();
347 *err_info
= ws_strdup_printf("OpenTrace failed with 0x%x", *err
);
348 returnVal
= WTAP_OPEN_NOT_MINE
;
352 g_pdh
= etw_dump_open(pcapng_filename
, err
, err_info
);
355 returnVal
= WTAP_OPEN_ERROR
;
359 *err
= ProcessTrace(&trace_handle
, 1, 0, 0);
360 if (*err
!= ERROR_SUCCESS
) {
361 returnVal
= WTAP_OPEN_ERROR
;
362 *err_info
= ws_strdup_printf("ProcessTrace failed with 0x%x", *err
);
366 if (g_err
!= ERROR_SUCCESS
)
369 *err_info
= g_strdup(g_err_info
);
370 returnVal
= WTAP_OPEN_ERROR
;
375 *err
= ERROR_NO_DATA
;
376 *err_info
= ws_strdup_printf("Didn't find any etw event");
377 returnVal
= WTAP_OPEN_NOT_MINE
;
382 if (trace_handle
!= INVALID_PROCESSTRACE_HANDLE
)
384 CloseTrace(trace_handle
);
388 if (*err
== ERROR_SUCCESS
)
390 if (!wtap_dump_close(g_pdh
, NULL
, err
, err_info
))
392 returnVal
= WTAP_OPEN_ERROR
;
398 char* err_info_ignore
= NULL
;
399 if (!wtap_dump_close(g_pdh
, NULL
, &err_ignore
, &err_info_ignore
))
401 returnVal
= WTAP_OPEN_ERROR
;
402 g_free(err_info_ignore
);
409 BOOL
is_event_filtered_out(PEVENT_RECORD ev
)
411 if (g_is_live_session
)
416 if (IsEqualGUID(&g_provider_filters
[0].ProviderId
, &ZeroGuid
))
421 for (int i
= 0; i
< ARRAYSIZE(g_provider_filters
); i
++)
423 if (IsEqualGUID(&g_provider_filters
[i
].ProviderId
, &ev
->EventHeader
.ProviderId
))
427 if (IsEqualGUID(&g_provider_filters
[i
].ProviderId
, &ZeroGuid
))
436 static void WINAPI
event_callback(PEVENT_RECORD ev
)
438 ULARGE_INTEGER timestamp
;
441 if (is_event_filtered_out(ev
))
447 * 100ns since 1/1/1601 -> usec since 1/1/1970.
448 * The offset of 11644473600 seconds can be calculated with a couple of calls to SystemTimeToFileTime.
450 timestamp
.QuadPart
= (ev
->EventHeader
.TimeStamp
.QuadPart
/ 10) - 11644473600000000ll;
452 /* Write OPN events that needs mbim sub dissector */
453 if (IsEqualGUID(&ev
->EventHeader
.ProviderId
, &mbb_provider
))
455 etw_dump_write_opn_event(ev
, timestamp
);
457 else if (IsEqualGUID(&ev
->EventHeader
.ProviderId
, &ndis_capture_provider
))
459 etw_dump_write_ndiscap_event(ev
, timestamp
);
461 /* Write any event form other providers other than above */
464 etw_dump_write_general_event(ev
, timestamp
);
468 wtap_dumper
* etw_dump_open(const char* pcapng_filename
, int* err
, char** err_info
)
470 wtap_dump_params params
= { 0 };
471 GArray
* shb_hdrs
= NULL
;
472 wtap_block_t shb_hdr
;
473 wtapng_iface_descriptions_t
* idb_info
;
475 wtap_block_t idb_data
;
476 wtapng_if_descr_mandatory_t
* descr_mand
;
478 wtap_dumper
* pdh
= NULL
;
480 shb_hdrs
= g_array_new(false, false, sizeof(wtap_block_t
));
481 shb_hdr
= wtap_block_create(WTAP_BLOCK_SECTION
);
482 g_array_append_val(shb_hdrs
, shb_hdr
);
484 /* In the future, may create multiple WTAP_BLOCK_IF_ID_AND_INFO separately for IP packet */
485 idb_info
= g_new(wtapng_iface_descriptions_t
, 1);
486 idb_datas
= g_array_new(false, false, sizeof(wtap_block_t
));
487 idb_data
= wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO
);
488 descr_mand
= (wtapng_if_descr_mandatory_t
*)wtap_block_get_mandatory_data(idb_data
);
489 descr_mand
->tsprecision
= WTAP_TSPREC_USEC
;
490 descr_mand
->wtap_encap
= WTAP_ENCAP_ETW
;
491 /* Timestamp for each pcapng packet is usec units, so time_units_per_second need be set to 10^6 */
492 descr_mand
->time_units_per_second
= G_USEC_PER_SEC
;
493 g_array_append_val(idb_datas
, idb_data
);
494 idb_info
->interface_data
= idb_datas
;
496 params
.encap
= WTAP_ENCAP_ETW
;
498 params
.tsprec
= WTAP_TSPREC_USEC
;
499 params
.shb_hdrs
= shb_hdrs
;
500 params
.idb_inf
= idb_info
;
502 pdh
= wtap_dump_open(pcapng_filename
, wtap_pcapng_file_type_subtype(), WTAP_UNCOMPRESSED
, ¶ms
, err
, err_info
);
506 wtap_block_array_free(shb_hdrs
);
510 if (params
.idb_inf
->interface_data
)
512 wtap_block_array_free(params
.idb_inf
->interface_data
);
514 g_free(params
.idb_inf
);
515 params
.idb_inf
= NULL
;
521 ULONG
wtap_etl_record_buffer_init(WTAP_ETL_RECORD
** out_etl_record
, PEVENT_RECORD ev
, BOOLEAN include_user_data
, WCHAR
* message
, WCHAR
* provider_name
)
523 ULONG total_packet_length
= sizeof(WTAP_ETL_RECORD
);
524 WTAP_ETL_RECORD
* etl_record
= NULL
;
525 ULONG user_data_length
= 0;
526 ULONG user_data_offset
= 0;
527 ULONG message_offset
= 0;
528 ULONG provider_name_offset
= 0;
529 ULONG message_length
= 0;
530 ULONG provider_name_length
= 0;
532 if (include_user_data
)
534 if (ev
->UserDataLength
< MAX_PACKET_SIZE
)
536 user_data_length
= ev
->UserDataLength
;
540 user_data_length
= MAX_PACKET_SIZE
;
542 user_data_offset
= sizeof(WTAP_ETL_RECORD
);
543 total_packet_length
+= ROUND_UP_COUNT(user_data_length
, sizeof(LONG
));
545 if (message
&& message
[0] != L
'\0')
547 message_offset
= total_packet_length
;
548 message_length
= (ULONG
)((wcslen(message
) + 1) * sizeof(WCHAR
));
549 total_packet_length
+= ROUND_UP_COUNT(message_length
, sizeof(LONG
));
551 if (provider_name
&& provider_name
[0] != L
'\0')
553 provider_name_offset
= total_packet_length
;
554 provider_name_length
= (ULONG
)((wcslen(provider_name
) + 1) * sizeof(WCHAR
));
555 total_packet_length
+= ROUND_UP_COUNT(provider_name_length
, sizeof(LONG
));
558 etl_record
= g_malloc(total_packet_length
);
559 SecureZeroMemory(etl_record
, total_packet_length
);
560 etl_record
->EventHeader
= ev
->EventHeader
;
561 etl_record
->BufferContext
= ev
->BufferContext
;
562 etl_record
->UserDataLength
= user_data_length
;
563 etl_record
->MessageLength
= message_length
;
564 etl_record
->ProviderLength
= provider_name_length
;
566 if (user_data_offset
)
568 memcpy(ADD_OFFSET_TO_POINTER(etl_record
, user_data_offset
), ev
->UserData
, user_data_length
);
572 memcpy(ADD_OFFSET_TO_POINTER(etl_record
, message_offset
), message
, message_length
);
574 if (provider_name_offset
)
576 memcpy(ADD_OFFSET_TO_POINTER(etl_record
, provider_name_offset
), provider_name
, provider_name_length
);
579 *out_etl_record
= etl_record
;
580 return total_packet_length
;
583 void wtap_etl_add_interface(int pkt_encap
, char* interface_name
, unsigned short interface_name_length
, char* interface_desc
, unsigned short interface_desc_length
)
585 wtap_block_t idb_data
;
586 wtapng_if_descr_mandatory_t
* descr_mand
;
590 idb_data
= wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO
);
591 descr_mand
= (wtapng_if_descr_mandatory_t
*)wtap_block_get_mandatory_data(idb_data
);
592 descr_mand
->wtap_encap
= pkt_encap
;
593 descr_mand
->tsprecision
= WTAP_TSPREC_USEC
;
594 /* Timestamp for each pcapng packet is usec units, so time_units_per_second need be set to 10^6 */
595 descr_mand
->time_units_per_second
= G_USEC_PER_SEC
;
596 if (interface_name_length
) {
597 wtap_block_add_string_option(idb_data
, OPT_IDB_NAME
, interface_name
, interface_name_length
);
599 if (interface_desc_length
) {
600 wtap_block_add_string_option(idb_data
, OPT_IDB_DESCRIPTION
, interface_desc
, interface_desc_length
);
602 if(!wtap_dump_add_idb(g_pdh
, idb_data
, &err
, &err_info
)) {
604 sprintf_s(g_err_info
, sizeof(g_err_info
), "wtap_dump failed, %s", err_info
);
609 void wtap_etl_rec_dump(char* etl_record
, ULONG total_packet_length
, ULONG original_packet_length
, unsigned int interface_id
, BOOLEAN is_inbound
, ULARGE_INTEGER timestamp
, int pkt_encap
, char* comment
, unsigned short comment_length
)
613 wtap_rec rec
= { 0 };
616 rec
.rec_header
.packet_header
.caplen
= total_packet_length
;
617 rec
.rec_header
.packet_header
.len
= original_packet_length
;
618 rec
.rec_header
.packet_header
.pkt_encap
= pkt_encap
;
619 rec
.rec_header
.packet_header
.interface_id
= interface_id
;
620 rec
.presence_flags
= WTAP_HAS_INTERFACE_ID
;
621 rec
.block
= wtap_block_create(WTAP_BLOCK_PACKET
);
622 wtap_block_add_uint32_option(rec
.block
, OPT_PKT_FLAGS
, is_inbound
? PACK_FLAGS_DIRECTION_INBOUND
: PACK_FLAGS_DIRECTION_OUTBOUND
);
623 if (comment_length
) {
624 wtap_block_add_string_option(rec
.block
, OPT_COMMENT
, comment
, comment_length
);
626 /* Convert usec of the timestamp into nstime_t */
627 rec
.ts
.secs
= (time_t)(timestamp
.QuadPart
/ G_USEC_PER_SEC
);
628 rec
.ts
.nsecs
= (int)(((timestamp
.QuadPart
% G_USEC_PER_SEC
) * G_NSEC_PER_SEC
) / G_USEC_PER_SEC
);
630 /* and save the packet */
631 if (!wtap_dump(g_pdh
, &rec
, (uint8_t*)etl_record
, &err
, &err_info
)) {
633 sprintf_s(g_err_info
, sizeof(g_err_info
), "wtap_dump failed, %s", err_info
);
637 /* Only flush when live session */
638 if (g_is_live_session
&& !wtap_dump_flush(g_pdh
, &err
)) {
640 sprintf_s(g_err_info
, sizeof(g_err_info
), "wtap_dump failed, 0x%x", err
);
642 wtap_rec_cleanup(&rec
);
645 void etw_dump_write_opn_event(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
)
647 WTAP_ETL_RECORD
* etl_record
= NULL
;
648 ULONG total_packet_length
= 0;
649 BOOLEAN is_inbound
= false;
650 /* 0x80000000 mask the function to host message */
651 is_inbound
= ((*(INT32
*)(ev
->UserData
)) & 0x80000000) ? true : false;
652 total_packet_length
= wtap_etl_record_buffer_init(&etl_record
, ev
, true, NULL
, NULL
);
653 wtap_etl_rec_dump((char*)etl_record
, total_packet_length
, total_packet_length
, 0, is_inbound
, timestamp
, WTAP_ENCAP_ETW
, NULL
, 0);
657 void etw_dump_write_event_head_only(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
)
659 WTAP_ETL_RECORD
* etl_record
= NULL
;
660 ULONG total_packet_length
= 0;
661 total_packet_length
= wtap_etl_record_buffer_init(&etl_record
, ev
, false, NULL
, NULL
);
662 wtap_etl_rec_dump((char*)etl_record
, total_packet_length
, total_packet_length
, 0, false, timestamp
, WTAP_ENCAP_ETW
, NULL
, 0);
666 void etw_dump_write_general_event(PEVENT_RECORD ev
, ULARGE_INTEGER timestamp
)
668 PTRACE_EVENT_INFO pInfo
= NULL
;
669 PBYTE pUserData
= NULL
;
670 PBYTE pEndOfUserData
= NULL
;
671 DWORD PointerSize
= 0;
672 PROPERTY_KEY_VALUE
* prop_arr
= NULL
;
673 DWORD dwTopLevelPropertyCount
= 0;
674 DWORD dwSizeofArray
= 0;
675 WCHAR wszMessageBuffer
[MAX_LOG_LINE_LENGTH
] = { 0 };
676 WCHAR formatMessage
[MAX_LOG_LINE_LENGTH
] = { 0 };
678 WTAP_ETL_RECORD
* etl_record
= NULL
;
679 ULONG total_packet_length
= 0;
680 BOOLEAN is_message_dumped
= false;
684 /* Skip EventTrace events */
685 if (ev
->EventHeader
.Flags
& EVENT_HEADER_FLAG_CLASSIC_HEADER
&&
686 IsEqualGUID(&ev
->EventHeader
.ProviderId
, &EventTraceGuid
))
689 * The first event in every ETL file contains the data from the file header.
690 * This is the same data as was returned in the EVENT_TRACE_LOGFILEW by
691 * OpenTrace. Since we've already seen this information, we'll skip this
697 /* Skip events injected by the XPerf tracemerger - they will never be decodable */
698 if (IsEqualGUID(&ev
->EventHeader
.ProviderId
, &ImageIdGuid
) ||
699 IsEqualGUID(&ev
->EventHeader
.ProviderId
, &SystemConfigExGuid
) ||
700 IsEqualGUID(&ev
->EventHeader
.ProviderId
, &EventMetadataGuid
))
705 if (!get_event_information(ev
, &pInfo
))
710 /* Skip those events without format message since most of them need special logic to decode like NDIS-PackCapture */
711 if (pInfo
->EventMessageOffset
<= 0)
716 if (EVENT_HEADER_FLAG_32_BIT_HEADER
== (ev
->EventHeader
.Flags
& EVENT_HEADER_FLAG_32_BIT_HEADER
))
725 pUserData
= (PBYTE
)ev
->UserData
;
726 pEndOfUserData
= (PBYTE
)ev
->UserData
+ ev
->UserDataLength
;
728 dwTopLevelPropertyCount
= pInfo
->TopLevelPropertyCount
;
729 if (dwTopLevelPropertyCount
> 0)
731 prop_arr
= g_malloc(sizeof(PROPERTY_KEY_VALUE
) * dwTopLevelPropertyCount
);
732 dwSizeofArray
= dwTopLevelPropertyCount
* sizeof(PROPERTY_KEY_VALUE
);
733 SecureZeroMemory(prop_arr
, dwSizeofArray
);
736 StringCbCopy(formatMessage
, MAX_LOG_LINE_LENGTH
, (LPWSTR
)ADD_OFFSET_TO_POINTER(pInfo
, pInfo
->EventMessageOffset
));
738 for (USHORT i
= 0; i
< dwTopLevelPropertyCount
; i
++)
740 pUserData
= extract_properties(ev
, pInfo
, PointerSize
, i
, pUserData
, pEndOfUserData
, &prop_arr
[i
]);
741 if (NULL
== pUserData
)
747 format_message(formatMessage
, prop_arr
, dwTopLevelPropertyCount
, wszMessageBuffer
, sizeof(wszMessageBuffer
));
749 total_packet_length
= wtap_etl_record_buffer_init(&etl_record
, ev
, false, wszMessageBuffer
, (WCHAR
*)ADD_OFFSET_TO_POINTER(pInfo
, pInfo
->ProviderNameOffset
));
750 wtap_etl_rec_dump((char*)etl_record
, total_packet_length
, total_packet_length
, 0, false, timestamp
, WTAP_ENCAP_ETW
, NULL
, 0);
753 is_message_dumped
= true;
756 if (NULL
!= prop_arr
)
767 if (!is_message_dumped
&& g_include_undecidable_event
)
769 etw_dump_write_event_head_only(ev
, timestamp
);
774 * Editor modelines - https://www.wireshark.org/tools/modelines.html
779 * indent-tabs-mode: nil
782 * vi: set shiftwidth=4 tabstop=8 expandtab:
783 * :indentSize=4:tabSize=8:noTabs=true: