Geoff Chappell - Software Analyst
This page is being prepared for a substantial reworking. Some content may be temporarily missing. Temporarily may turn into indefinitely. New content may be more than usually defective. The page is now published only as a revision in progress. Use with caution.
The PERFINFO_TRACE_HEADER is one of several types of fixed-size header that introduce variable-size data for events that are logged through Event Tracing for Windows (ETW). As with other types of event, those that begin with a PERFINFO_TRACE_HEADER accumulate first in trace buffers. To have these events persist in this raw form for ready inspection, configure the event tracing session to flush the trace buffers to an Event Trace Log (ETL) file.
The PERFINFO_TRACE_HEADER is not documented, but a C-language definition is published in the NTWMI.H from the Enterprise edition of the Windows Driver Kit (WDK) for Windows 10 version 1511.
Were it not for this relatively recent and possibly unintended disclosure, much would anyway be known from type information in symbol files. Curiously though, type information for this structure has never appeared in any public symbol files for the kernel or for the obvious low-level user-mode DLLs. In the whole of Microsoft’s packages of public symbol files, at least to the original Windows 10, relevant type information is unknown before Windows 8 and appears in symbol files only for AppXDeploymentClient.dll, CertEnroll.dll (before Windows 10) and Windows.Storage.ApplicationData.dll.
The PERFINFO_TRACE_HEADER is 0x18 bytes in both 32-bit and 64-bit Windows in versions that are known to have it.
Offset | Definition |
---|---|
0x00 |
union { ULONG Marker; struct { USHORT Version; UCHAR HeaderType; UCHAR Flags; }; }; |
0x04 |
union { ULONG Header; WMI_TRACE_PACKET Packet; }; |
0x08 |
union { PERFINFO_TIMESTAMP TS; LARGE_INTEGER SystemTime; }; |
0x10 |
UCHAR Data [ANYSIZE_ARRAY]; |
The first 4 bytes have common elements in all the various Trace Headers. All have the high bit set in the Flags at offset 0x03. Of those that have the two highest bits set, what distinguishes a header as continuing specifically as a PERFINFO_TRACE_HEADER is the HeaderType at offset 0x02:
Value | Name | Implied Layout |
---|---|---|
0x10 | TRACE_HEADER_TYPE_PERFINFO32 | 0x10 bytes of header followed by 32-bit event data as Data array |
0x11 | TRACE_HEADER_TYPE_PERFINFO64 | 0x10 bytes of header followed by 64-bit event data as Data array |
Also defined in NTWMI.H are combinations of the Flags and HeaderType, ready for use as a basis for the Marker as the first dword:
Value (x86) | Value (x64) | Name |
---|---|---|
0xC0100000 | 0xC0110000 | PERFINFO_TRACE_MARKER |
To these markers must yet be added the Version. Though the Version is formally the low word, the kernel treats it as 8-bit. It is not presently clear what is meant by this Version. Both 0x02 and 0x03 are observed in Windows 10. The high 8 bits of the Version can anyway be treated as more flags. NTWMI.H defines the following, again as bits to merge into the Marker:
Value | Name |
---|---|
0x00000700 | TRACE_HEADER_PMC_COUNTERS_MASK |
0x00008000 | TRACE_HEADER_PEBS_INDEX_FLAG |
Note that where SECHOST translates any trace header to an EVENT_HEADER or EVENT_TRACE_HEADER for presentation to an event consumer, it also recognises these flags in a SYSTEM_TRACE_HEADER, but the kernel only ever uses these flags for a PERFINFO_TRACE_HEADER. For their meaning, look below to Extended Data Items.
The WMI_TRACE_PACKET at offset 0x04 is two words:
Offset | Definition |
---|---|
0x00 |
USHORT Size; |
0x02 |
union { USHORT HookId; struct { UCHAR Type; UCHAR Group; }; }; |
The total size of data for the event, i.e., both the fixed-size header and the variable-size event data, is given by the Size member of the Packet, i.e., at offset 0x04 in the header. The HookId at offset 0x06 in the header tells what type of event is logged and determines the meaning of whatever event data follows the header. In the absence of an EVENT_DESCRIPTOR for events that have a SYSTEM_TRACE_HEADER, the HookId is effectively the event identifier (no matter that by the time it gets translated for consumers its Group and Type show as a ProviderId and Opcode). A list of the known Hook IDs for NT Kernel Logger Events is presented separately.
Ordinarily, the Data array marks the end of the header and the beginning of event-specific data. When the Marker has the TRACE_HEADER_PMC_COUNTERS_MASK or TRACE_HEADER_PEBS_INDEX_FLAG bits set, an extended data item is inserted. In both cases, the format is documented because it is ultimately translated by SECHOST for presentation to event consumers as the data for an extended data item. C-language definitions are in EVNTCONS.H.
When TRACE_HEADER_PMC_COUNTERS_MASK is set, the inserted data is an EVENT_EXTENDED_ITEM_PMC_COUNTERS:
Offset | Definition |
---|---|
0x00 |
ULONG64 Counter [ANYSIZE_ARRAY]; |
The value in the mask, i.e., from 0 to 7, tells how many of the current processor’s performance monitoring counters are in the Counter array. The implementation presently allows at most 4 counters. The trace session’s controller can choose the counters and the events for which the counters are collected. (Details are in preparation.)
When TRACE_HEADER_PEBS_INDEX_FLAG is set, the inserted data is an EVENT_EXTENDED_ITEM_PEBS_INDEX:
Offset | Definition |
---|---|
0x00 |
ULONG64 PebsIndex; |
The kernel sets this flag only for the PERFINFO_LOG_TYPE_CONTEXTSWAP (0x0524) event. The event-specific data is then a WMI_CONTEXTSWAP.