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 WMI_BUFFER_HEADER structure (formally _WMI_BUFFER_HEADER) begins each trace buffer that an event logger, or more formally an event tracing sesssion, uses for storing event data on the way to an Event Trace Log (ETL) file. Indeed, because such buffers are flushed as is, header and all, the structure is not only at the beginning of every ETL file but also recurs throughout.
The rest of each buffer, after the fixed-size WMI_BUFFER_HEADER, is a sequence of variable-size WMI data blocks. In the formulation for Windows Management Instrumentation (WMI), each data block begins with a fixed-size WNODE_HEADER. Event Tracing for Windows (ETW) repurposes the scheme so that each data block begins with one of several possible fixed-size Trace Headers.
The WMI_BUFFER_HEADER structure is not documented. A C-language definition is published in NTWMI.H from the original and Version 1511 editions of the Windows Driver Kit (WDK) for Windows 10.
The WMI_BUFFER_HEADER is 0x48 bytes in both 32-bit and 64-bit Windows in all versions for which the structure is known, meaning 5.0 and higher. Offsets, names and types below are from type information for the structure in symbol files for the kernel, starting with Windows XP SP3 and Windows Server 2003 SP2. Since symbol files for earlier versions do not contain type information for this structure, what’s known for them is instead inferred from what use these versions of the kernel are seen to make of the structure in comparison with those for which Microsoft’s names and types are known. Where the correspondence is close, it seems reasonable to suppose continuity. Some use, however, has no correspondence, the code having changed too much. Even where the use hasn’t changed, tracking it down exhaustively would be difficult, if not impossible, even with source code.
The structure’s development is hard enough to track even for the versions that do have type information in public symbol files. The modern layout has been very nearly stable since Windows 7. The description of earlier versions is complicated because the structure’s creation from and compatibility with the documented WNODE_HEADER is explicit.
Offset | Definition | Versions |
---|---|---|
0x00 |
union { WNODE_HEADER Wnode; struct { /* see below (Lists) */ }; struct { /* see below (WNODE-compatible) */ }; }; |
5.0 to 5.2 |
union { WNODE_HEADER Wnode; struct { /* see below (WNODE-compatible) */ }; }; |
6.0 only | |
/* unstructured members, see below (WNODE-compatible) */ |
6.1 and higher | |
0x30 |
ULONG Offset; |
5.0 and higher |
0x34 (5.0 to 5.1) |
ULONG EventsLost; |
5.0 to 5.1 |
0x34 |
USHORT BufferFlag; |
5.2 and higher |
0x36 |
USHORT BufferType; |
5.2 and higher |
0x38 |
union { /* changing members, see below (Tail) */ }; |
5.0 and higher |
For Microsoft’s names for the possible values of BufferFlag and BufferType, follow the links.
In versions before 6.0, the WMI_BUFFER_HEADER begins with a WNODE_HEADER in union with two unnamed structures. Version 6.0 removed the first, and version 6.1 did away with the union by removing the WNODE_HEADER.
The first of the unnamed structures that overlays the WNODE_HEADER seems only ever to have had two meaningful members, SlistEntry and Entry, defined in that order but placed with Entry (at offset 0x18) before SlistEntry (at 0x1C and 0x20, for x86 and x64, respectively):
Offset | Definition | Versions | Remarks |
---|---|---|---|
0x00 |
ULONGLONG Reserved1; |
5.0 to 5.2 | |
0x08 |
ULONGLONG Reserved2; |
5.0 to 5.2 | |
0x10 |
LARGE_INTEGER Reserved3; |
5.0 to 5.2 | |
0x18 |
LIST_ENTRY Entry; |
5.0 only | |
union { struct { PVOID Alignment; SINGLE_LIST_ENTRY SlistEntry; }; LIST_ENTRY Entry; }; |
5.1 to 5.2 | SlistEntry next at offset 0x38; Entry next at offset 0x38 |
Versions 5.0 to 5.2 cache free buffers. Version 5.0 keeps a double-linked list, linked through Entry. Versions 5.1 and 5.2 keep a single-linked list with an SLIST_HEADER, linking through SlistEntry. While no use of SlistEntry is known in version 5.0 and none of Entry in versions 5.1 and 5.2, It is here inferred that SlistEntry was not yet defined for version 5.0 and Entry was retained from version 5.0.
When the two list entries were moved beyond the WNODE_HEADER to offset 0x38 for version 6.0, the first unnamed structure in the union was removed. The other unnamed structure was anyway the one that more closely overlaid the WNODE_HEADER, duplicating the latter’s TimeStamp and Guid (and BufferSize, eventually) and keeping at least the names of the ClientContext and Flags members. It remained in union with the WNODE_HEADER until the latter was removed for version 6.1. Its members then became direct members of the WMI_BUFFER_HEADER:
Offset | Definition | Versions | Remarks |
---|---|---|---|
0x00 |
LONG ReferenceCount; |
5.0 to 5.2 | next as LONG volatile at 0x0C |
ULONG BufferSize; |
6.0 and higher | ||
0x04 |
ULONG SavedOffset; |
5.0 and higher | |
0x08 |
ULONG CurrentOffset; |
5.0 to 5.2 | |
ULONG volatile CurrentOffset; |
6.0 and higher | ||
0x0C |
ULONG UsePerfClock; |
5.0 to 5.2 | |
LONG volatile ReferenceCount; |
6.0 and higher | previously LONG at 0x00 | |
0x10 |
LARGE_INTEGER TimeStamp; |
5.0 to 5.2 | |
union { LARGE_INTEGER TimeStamp; LARGE_INTEGER StartPerfClock; }; |
6.0 only | ||
LARGE_INTEGER TimeStamp; |
6.1 and higher | ||
0x18 (5.0 to 5.2) |
GUID Guid; |
5.0 to 5.2 | |
0x18 |
LONGLONG SequenceNumber; |
6.0 and higher | |
0x20 |
ULONG Spare0; ULONG Spare1; |
early 6.0 | |
union { ULONG Padding0 [2]; SINGLE_LIST_ENTRY SlistEntry; WMI_BUFFER_HEADER *NextBuffer; }; |
late 6.0 to 6.1 | SlistEntry previously at 0x38; NextBuffer previously at 0x38; |
|
union { struct { ULONGLONG ClockType : 3; ULONGLONG Frequency : 61; }; SINGLE_LIST_ENTRY SlistEntry; WMI_BUFFER_HEADER *NextBuffer; }; |
6.2 and higher | ||
0x28 |
WMI_CLIENT_CONTEXT ClientContext; |
5.0 to 5.2 | |
ETW_BUFFER_CONTEXT ClientContext; |
6.0 and higher | ||
0x2C |
ULONG Flags; |
5.0 only | |
union { WMI_BUFFER_STATE State; ULONG Flags; }; |
5.1 to 5.2 | ||
union { ETW_BUFFER_STATE State; ULONG Flags; }; |
6.0 only | ||
ETW_BUFFER_STATE State; |
6.1 and higher |
For a WMI_BUFFER_HEADER in an ETL file, the BufferSize might as well be regarded as the offset in bytes to the next buffer in the file (or to the end of the file). The SavedOffset is similarly the number of bytes that are valid within the buffer, both of the WMI_BUFFER_HEADER and the events that follow.
The WMI_BUFFER_STATE is a structure of ULONG bit fields. It is not known to be accessed as bit fields in version 5.0 and is here regarded as being not yet defined for that version. The ETW_BUFFER_STATE that supersedes it is an enumeration. Though the Flags member is retained for version 6.0, it will no longer have been useful for allowing the bit fields of the WMI_BUFFER_STATE to be manipulated together, and version 6.1 removes it.
The last 0x10 bytes, at offset 0x38, of the WMI_BUFFER_HEADER are an unnamed union in all versions, with numerous complications for orderly description:
Offset | Definition | Versions | Remarks |
---|---|---|---|
0x38 |
GUID InstanceGuid; |
5.0 to 5.2 | |
ULONG Padding1 [4]; |
6.0 and higher | ||
0x38 |
LARGE_INTEGER StartTime; |
6.0 only | |
ETW_REF_CLOCK ReferenceTime; |
6.1 and higher | ||
0x38 |
LIST_ENTRY Entry; |
6.0 only | previously at 0x18 |
0x38 |
SINGLE_LIST_ENTRY SlistEntry; |
early 6.0 only | previously at 0x1C (x86) and 0x20 (x64); next at 0x20 |
0x38 |
struct { PVOID LoggerContext; SINGLE_LIST_ENTRY GlobalEntry; }; |
5.0 to 5.2 | |
struct { WMI_BUFFER_HEADER *NextBuffer; SINGLE_LIST_ENTRY GlobalEntry; }; |
early 6.0 | NextBuffer next at 0x20 | |
struct { PVOID Padding2; SINGLE_LIST_ENTRY GlobalEntry; }; |
late 6.0 | ||
LIST_ENTRY GlobalEntry; |
6.1 and higher | ||
0x38 |
struct { PVOID Pointer0; PVOID Pointer1; }; |
late 6.0 and higher |