MESSAGE_TRACE_HEADER

The MESSAGE_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 MESSAGE_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.

Usage

The events that get a MESSAGE_TRACE_HEADER, rather than one of the other types of trace header, are generated through a handful of interfaces that are mostly used for Windows Pre-Processor (WPP) software tracing. The kernel-mode interface is the pair of documented kernel exports WmiTraceMessage and WmiTraceMessageVa. The kernel exposes the functionality to user mode through the undocumented NtTraceEvent function, specifically when the Flags argument includes ETW_NT_FLAGS_TRACE_MESSAGE (0x00000200). In user mode, this path to the kernel-mode implementation goes through the the undocumented NTDLL functions EtwTraceMessage and EtwTraceMessageVa, which are in turn accessed as forwards from the documented ADVAPI32 functions TraceMessage and TraceMessageVa.

Documentation Status

Though the relevant API functions, both in kernel mode and user mode, are documented, the MESSAGE_TRACE_HEADER structure itself is not. However, a C-language definition is published in the NTWMI.H header from some editions of the Windows Driver Kit (WDK) for Windows 10.

Were it not for this relatively recent and possibly unintended disclosure, much but certainly not all 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, 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.

Layout

The MESSAGE_TRACE_HEADER is 8 bytes in both 32-bit and 64-bit Windows in all known versions.

Offset Definition
0x00
union {
    ULONG Marker;
    struct {
        USHORT Size;
        UCHAR Reserved;
        UCHAR Version;
    };
};
0x04
union {
    ULONG Header;
    WMI_TRACE_MESSAGE_PACKET Packet;
};

What distinguishes the MESSAGE_TRACE_HEADER from other Trace Headers is a particular combination of high bits in the Marker. NTWMI.H defines them as:

Value Name Remarks
0x80000000 TRACE_HEADER_FLAG set in all trace headers
0x40000000 TRACE_HEADER_EVENT_TRACE clear, but set in other trace headers
0x10000000 TRACE_MESSAGE set, but clear in other trace headers

While the WMI_TRACE_MESSAGE_PACKET is not known to have any other use, it is as well presented here:

Offset Definition
0x00
USHORT MessageNumber;
0x02
USHORT OptionFlags;

The MessageNumber is the primary identifier of what event occurred. Interpretation is a matter for the provider and consumer. It is what the kernel received as the MessageNumber argument via the documented API functions. Both the MessageNumber and OptionFlags have a vital additional role. They tell what data follow the header. There can be any selection of the following items in the following order:

Note that although the MESSAGE_TRACE_HEADER always has 8-byte alignment in a trace buffer, the 8-byte time stamp need not be (and typically isn’t) 8-byte-aligned. The OptionFlags tell which of the non-arbitrary data is present. Most come from the MessageFlags argument of the relevant API functions.

Value Name Remarks
0x0001 TRACE_MESSAGE_SEQUENCE 32-bit sequence number included from logger
0x0002 TRACE_MESSAGE_GUID GUID included from provider via MessageGuid argument
0x0004 TRACE_MESSAGE_COMPONENT_ID component ID included from provider via MessageGuid argument
0x0008 TRACE_MESSAGE_TIMESTAMP time stamp included from logger
0x0010 TRACE_MESSAGE_PERFORMANCE_TIMESTAMP space included for time stamp, but no time stamp generated
0x0020 TRACE_MESSAGE_SYSTEMINFO thread ID and process ID included
0x0040 TRACE_MESSAGE_POINTER32 message traced for 32-bit provider
0x0080 TRACE_MESSAGE_POINTER64 message traced for 64-bit provider

The arbitrary data are copied from the addresses and sizes that are given to the API functions as variable arguments or via the MessageArgList argument. See that no types or sizes are recorded. The data is simply aggregated as one blob. Separation and interpretation depend entirely on the MessageNumber—and, where pointers are expected in the data, on the last two of the OptionFlags.