DRAFT: Take more than your usual care.

ETW_REGISTRATION_ENTRY

Right from its introduction for Windows 2000, before it even had its current name, Event Tracing for Windows (ETW) has parallel implementations in kernel and user modes. The practical difference is not just with where the code is but with where the trace buffers are managed. One aim of ETW is that events are written quickly into trace buffers which are then serviced independently from a logger thread, e.g., to flush full buffers to an Event Trace Log (ETL) file. In an important special case for programs that trace their own diagnostics, an event provider that executes as a user-mode process may be enabled into a tracing session that executes in the same process and chooses the user-mode ETW implementation. For such a tracing session, the trace buffers are managed in user mode and writing an event (to a trace buffer) avoids the delay of going to and from kernel mode. This of course requires a substantial user-mode implementation, while also retaining access to the kernel-mode implementation in case the same provider is also enabled into a tracing session in a different process. In this more general case for which writing an event to a trace buffer means sending it to the kernel, some substance is desirable in the user-mode implementation so that the expense of sending an event to the kernel is avoided if it can be known that the event isn’t wanted by any tracing session that has kernel-mode tracing buffers.

Thus does it happen that NTDLL keeps no small amount of its own state about each user-mode registration of an event provider in addition to the ETW_REG_ENTRY that the kernel keeps. The ETW_REGISTRATION_ENTRY structure is this user-mode state.

Documentation Status

The ETW_REGISTRATION_ENTRY structure is not documented. Neither is it known even from public symbol files. The only public disclosure that is yet known of this structure’s name by Microsoft is that the WMITRACE.DLL debugger extension knows to look for it to support its obsolete !regtable command. The suggestion is strong that the type information that WMITRACE needs for this is available only in private symbol files and even then only for Windows 7.

Layout

The ETW_REGISTRATION_ENTRY has been relatively stable. Windows 7 saw an insertion, which lengthened the structure. The only significant change and reordering came with Windows 8 and shows in the relevant API functions as a reinterpretation of the opaque REGHANDLE.

Versions Size (x86) Size (x64)
6.0 0xB8 0xC8
6.1 0xD0 0xF0
6.2 and higher 0xC8 0x0100

These sizes, and the offsets, types and names in the detailed layout below, come from inspection of the binaries for NTDLL. The user-mode registration entry has some points in common with the two kernel-mode structures ETW_REG_ENTRY and ETW_GUID_ENTRY which are known from public symbol files for the kernel, but the correspondence is not close enough even for suppositions of Microsoft’s names and types. A smattering of such names and types are inferred with reasonable certainty by matching known use with the names that WMITRACE seeks from private symbol files. Where the use continues to later versions, the corresponding names and types are assumed to too.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00 an RTL_BALANCED_NODE 6.2 and higher
  0x18 unaccounted eight bytes 6.2 and higher
0x00 (6.0 to 6.1);
0x0C
0x00 (6.0 to 6.1);
0x20
GUID ProviderGuid;
6.0 and higher
0x10 (6.0 to 6.1) 0x10 (6.0 to 6.1) unknown HANDLE to the kernel-mode registration 6.0 to 6.1
0x14 (6.0 to 6.1) 0x18 (6.0 to 6.1)
<unknown-type> RegistrationHandle;
6.0 to 6.1
0x1C (6.1) 0x20 (6.1) unknown CRITICAL_SECTION 6.1 only
0x1C (6.0);
0x34 (6.1);
0x1C
0x20 (6.0);
0x48 (6.1);
0x30
PVOID Callback;
6.0 and higher
0x20 (6.0);
0x38 (6.1);
0x20
0x28 (6.0);
0x50 (6.1);
0x38
PVOID Context;
6.0 and higher
0x24 0x40 unknown SRWLOCK 6.2 and higher
0x28 0x48 unknown SRWLOCK 6.2 and higher
0x2C 0x50 unknown 32-bit thread ID 6.2 and higher
0x30 0x58 unknown HANDLE to the kernel-mode registration 6.2 and higher
0x34 0x60 unknown 16-bit sequence number 6.2 and higher
0x24 (6.0);
0x3C (6.1);
0x36
0x30 (6.0);
0x58 (6.1);
0x62
ULONG Type;
6.0 to 6.1
struct {
    /*  USHORT bit fields, see below  */
};
6.2 and higher
0x28 (6.0);
0x40 (6.1);
0x38
0x38 (6.0);
0x60 (6.1);
0x68
unknown 0x18-byte structure for kernel-mode registration 6.0 and higher
0x40 (6.0);
0x58 (6.1);
0x50
0x50 (6.0);
0x78 (6.1);
0x80
unknown array of four 0x18-byte structures for private registrations 6.0 and higher
0xA0 (6.0);
0xB8 (6.1);
0xB0
0xB0 (6.0);
0xD8 (6.1);
0xE0
unknown 0x18-byte structure as aggregate of private registrations 6.0 and higher
  0xF8 unaccounted eight bytes 6.2 and higher

The Type takes its values from the ETW_NOTIFICATION_TYPE enumeration. Windows 8 narrows it to 16 bits and squeezes in a one-bit flag. Windows 10 slips in another.

Mask Description Versions
0x7FFF (6.2 to 6.3);
0x3FFF
USHORT Type : 15;
6.2 to 6.3
USHORT Type : 14;
10.0 and higher
0x4000 use descriptor type 10.0 and higher
0x8000 track provider binary 6.2 and higher