TRACE_LOGFILE_HEADER

The TRACE_LOGFILE_HEADER is one of many types of fixed-size header that begin the data for an event as held in the trace buffers or flushed to an Event Trace Log (ETL) file.

The type of event for which the TRACE_LOGFILE_HEADER can be the event-specific data is the system event WMI_LOG_TYPE_HEADER (0x0000).

Usage

The WMI_LOG_TYPE_HEADER event is the very first in every ETL file, beginning immediately after the first WMI_BUFFER_HEADER.

Documentation Status

The TRACE_LOGFILE_HEADER is documented. Of course, this is not so that it can be inspected in an ETL file. What is documented is the translation that is presented to callers of the documented OpenTrace function as output in the LogfileHeader member of the EVENT_TRACE_LOGFILE structure whose address is passed to the function as its one argument.

This article is concerned only with the raw TRACE_LOGFILE_HEADER as it appears in trace buffers or ETL files, and only then to note where this differs from what is documented.

Layout

Data for the WMI_LOG_TYPE_HEADER event comprises:

Trace Header

In the Marker that begins the SYSTEM_TRACE_HEADER, the Flags are 0xC0, the HeaderType is 0x01 or 0x02 for a 32-bit or 64-bit trace session, respectively, and the Version is nowadays 0x02 but is 0x01 in traces written by Windows versions before 6.0. The Size is the total in bytes of all the above items, both fixed-size and variable. The HookId, as the identifier of the event and thus of how the event-specific data that follows is interpreted, is WMI_LOG_TYPE_HEADER.

Note that the HeaderType matters since the event-specific data that follows has different 32-bit and 64-bit forms. A 32-bit trace session on 64-bit Windows writes the 32-bit form. An ETL file from a 64-bit trace session may be interpreted on 32-bit Windows.

Event-Specific Data

The TRACE_LOGFILE_HEADER is 0x0110 or 0x0118 bytes in its 32-bit and 64-bit forms, respectively, in all known versions that have it.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
ULONG BufferSize;
5.0 and higher
0x04 0x04
union {
    ULONG Version;
    struct {
        UCHAR MajorVersion;
        UCHAR MinorVersion;
        UCHAR SubVersion;
        UCHAR SubMinorVersion;
    } VersionDetail;
};
5.0 and higher
0x08 0x08
ULONG ProviderVersion;
5.0 and higher
0x0C 0x0C
ULONG NumberOfProcessors;
5.0 and higher
0x10 0x10
LARGE_INTEGER EndTime;
5.0 and higher
0x18 0x18
ULONG TimerResolution;
5.0 and higher
0x1C 0x1C
ULONG MaximumFileSize;
5.0 and higher
0x20 0x20
ULONG LogFileMode;
5.0 and higher
0x24 0x24
ULONG BuffersWritten;
5.0 and higher
0x28 0x28
union {
    GUID LogInstanceGuid;
    struct {
        ULONG StartBuffers;
        ULONG PointerSize;
        ULONG EventsLost;
        ULONG Reserved32;
    };
};
5.0 only
union {
    GUID LogInstanceGuid;
    struct {
        ULONG StartBuffers;
        ULONG PointerSize;
        ULONG EventsLost;
        ULONG CpuSpeedInMHz;
    };
};
5.1 and higher
0x38 0x38
PWSTR LoggerName;
5.0 and higher
0x3C 0x40
PWSTR LogFileName;
5.0 and higher
0x40 0x48
RTL_TIME_ZONE_INFORMATION TimeZone;
5.0 to 5.2
TIME_ZONE_INFORMATION TimeZone;
6.0 and higher
0xF0 0xF8
LARGE_INTEGER BootTime;
5.0 and higher
0xF8 0x0100
LARGE_INTEGER PerfFreq;
5.0 and higher
0x0100 0x0108
LARGE_INTEGER StartTime;
5.0 and higher
0x0108 0x0110
ULONG ReservedFlags;
5.0 and higher
0x010C 0x0114
ULONG BuffersLost;
5.0 and higher

It arguably was only ever a curiosity with no practical effect, and now it is only a historical curiosity, but there is significance to Microsoft’s comments in EVNTRACE.H when introducing the C-language definition of the TRACE_LOGFILE_HEADER:

// TRACE_LOGFILE_HEADER32 and TRACE_LOGFILE_HEADER64 structures
// are also provided to simplify cross platform decoding of the
// header event.

Microsoft added this comment for Windows 7. The separate formal definitions were apparently not just newly provided but newly devised, and not just for interpreting the structure but also for the kernel’s writing of it. Versions 5.1 and 6.0 trust that a set Wow flag in the WMI_LOGGER_INFORMATION that the kernel receives when starting a logger may mean that 32-bit forms of various structures are wanted instead of 64-bit. For the TRACE_LOGFILE_HEADER this means using a 32-bit form that is eight bytes smaller than the 64-bit form that would be native to the 64-bit kernel. The 32-bit kernels for these versions also have code for preparing a reduced structure—but from the already smaller 32-bit structure.

The BufferSize is in bytes, not kilobytes, no matter that Microsoft says differently in both the documentation and the EVNTRACE.H comments. That it should be bytes, if only for the TRACE_LOGFILE_HEADER as prepared by the kernel for flushing to an ETL file, was plainly intended from the start. The version 5.0 kernel prepares the structure directly from the WMI_LOGGER_INFORMATION. The latter’s BufferSize is in KB and the kernel explicitly multiplies by 1024 to get the BufferSize for the TRACE_LOGFILE_HEADER.

In the VersionDetail, all versions set the MajorVersion and MinorVersion to those of Windows itself. The following are known for the SubVersion and SubMinorVersion:

See that the SubVersion and SubMinorVersion nowadays tell a little of the logger’s capability. Sufficiently advanced means any of the following:

In version 6.1 and higher, if the logger is configured for the EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING (0x10000000) mode, then the NumberOfProcessors is 1 no matter how many processors are active.

The LogFileMode reported in this structure is not exactly what was ever specified for the logger as a LogFileMode nor even what the logger keeps as its LoggerMode (in its WMI_LOGGER_CONTEXT). The following flags are cleared from it:

Though Microsoft’s C-language definition of the TRACE_LOGFILE_HEADER has provided for a CpuSpeedInMHz since Windows XP, it is not until Windows Vista that the kernel sets this member.

The null-terminated Unicode strings that are otherwise suggested for the LoggerName and LogFileName simply follow the structure. Before version 6.1, the LoggerName and LogFileName actually are saved as pointers to these strings. They have since been repurposed and now take values from the HAL_PLATFORM_TIMER_SOURCE enumeration to tell of the clock interrupt and performance counter, respectively. This enumeration is defined in the NTOSP.H header from the Enterprise edition of the Windows Driver Kit (WDK) for Windows 10 version 1511:

Microsoft’s C-language definition of the TRACE_LOGFILE_HEADER for kernel-mode programming in all versions provides conditionally that the TimeZone can be an RTL_TIME_ZONE_INFORMATION whose definition Microsoft provides in no other headers. This differs from the documented TIME_ZONE_INFORMATION only in having the kernel-mode TIME_FIELDS instead of the user-mode SYSTEMTIME. Versions before 6.0 do not translate the TimeZone from the undocumented RTL_TIME_ZONE_INFORMATION to a plain old TIME_ZONE_INFORMATION.

Before version 6.0, the ReservedFlags are 1 if the logger uses the performance counter, but are otherwise 0. In modern versions, the ReservedFlags record the logger’s ClockType, which is again 1 if the logger uses the performance counter, but is 2 for the system time and 3 for the CPU cycle counter.