Geoff Chappell - Software Analyst
The ETW_REG_ENTRY structure (formally _ETW_REG_ENTRY) is the kernel’s representation of an event registration object. This can exist as a formal object, with handles and access control, or not. The typical case in which an instance is created as a formal object is when an event provider is registered from user mode. The object type is named EtwRegistration. Note that the kernel has no exported variable for this object type, presumably because only the kernel is ever involved in interpreting a handle that refers to such an object.
The ETW_REG_ENTRY structure is not documented.
For a non-trivial structure that is plainly very much internal to the kernel, the ETW_REG_ENTRY has been relatively stable. There has been growth, inevitably, but the only rearrangement was that version 6.2 compacts a few members and moves them towards the end.
Version | Size (x86) | Size (x64) |
---|---|---|
6.0 to 6.1 | 0x2C | 0x50 |
6.2 to 6.3 | 0x28 | 0x50 |
10.0 to 2004 | 0x3C | 0x70 |
The preceding sizes, and the offsets, types and names in the table below are from Microsoft’s symbol files for the kernel starting with Windows Vista.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
LIST_ENTRY RegList; |
6.0 and higher | |
0x08 | 0x10 |
LIST_ENTRY GroupRegList; |
10.0 and higher | |
0x08 (6.0 to 6.3); 0x10 |
0x10 (6.0 to 6.3); 0x20 |
ETW_GUID_ENTRY *GuidEntry; |
6.0 and higher | |
0x14 | 0x28 |
ETW_GUID_ENTRY *GroupEntry; |
10.0 and higher | |
0x0C (6.0 to 6.1) | 0x18 (6.0 to 6.1) |
USHORT Index; |
6.0 to 6.1 | next at 0x24 and 0x48 |
0x0E (6.0 to 6.1) | 0x1A (6.0 to 6.1) |
USHORT Flags; |
6.0 to 6.1 | next as UCHAR at 0x26 and 0x4A |
0x10 (6.0 to 6.1) | 0x1C (6.0 to 6.1) |
UCHAR EnableMask; |
6.0 to 6.1 | next at 0x27 and 0x4B |
0x14 (6.0 to 6.1); 0x0C (6.2 to 6.3); 0x18 |
0x20 (6.0 to 6.1); 0x18 (6.2 to 6.3); 0x30 |
union { /* changing members, see below */ }; |
6.0 and higher | |
0x24 (6.0 to 6.1); 0x1C (6.2 to 6.3); 0x28 |
0x40 (6.0 to 6.1); 0x38 (6.2 to 6.3); 0x50 |
union { EPROCESS *Process; struct { PVOID Callback; PVOID CallbackContext; }; }; |
6.0 to 6.1 | last member in 6.0 to 6.1 |
union { EPROCESS *Process; struct { PVOID CallbackContext; PVOID Callback; }; }; |
6.2 and higher | |||
0x24 (6.2 to 6.3); 0x30 |
0x48 (6.2 to 6.3); 0x60 |
USHORT Index; |
6.2 and higher | previously at 0x0C and 0x18 |
0x26 (6.2 to 6.3); 0x32 |
0x4A (6.2 to 6.3); 0x62 |
union { UCHAR Flags; struct { /* bit fields, follow link */ }; }; |
6.2 to 1511 | previously USHORT at 0x0E and 01A |
union { USHORT Flags; struct { /* bit fields, follow link */ }; }; |
1607 and higher | |||
0x27 (6.2 to 6.3); 0x33 (10.0 to 1511); 0x34 |
0x4B (6.2 to 6.3); 0x63 (10.0 to 1511); 0x64 |
UCHAR EnableMask; |
6.2 and higher | previously at 0x10 and 0x1C; last member in 6.2 to 6.3 |
0x34 (10.0 to 1511); 0x35 |
0x64 (10.0 to 1511); 0x65 |
UCHAR GroupEnableMask; |
10.0 and higher | |
0x36 | 0x66 |
UCHAR HostEnableMask; |
2004 and higher | |
0x37 | 0x67 |
UCHAR HostGroupEnableMask; |
2004 and higher | |
0x35 (10.0 to 1511); 0x36 (1607 to 1703) |
0x65 (10.0 to 1511); 0x66 (1607 to 1703) |
BOOLEAN UseDescriptorType; |
10.0 to 1703 | next in Flags |
0x38 | 0x68 |
ETW_PROVIDER_TRAITS *Traits; |
10.0 and higher | last member in 10.0 and higher |
Any number of registrations can be opened to any one event provider. The ETW_REG_ENTRY structures for the registrations are linked through the RegList member to the RegListHead in the ETW_GUID_ENTRY that represents the provider (and whose address is the GuidEntry). There are also ETW_REG_ENTRY structures that exist only to support a notification mechanism. These reply objects are not associated with any provider. They have their own list, again linking through RegList, but with a head that is an internal variable in the kernel’s data.
Each registration allows that its holder can write events through the provider. On the other side, the provider can be accessed by as many as eight loggers, known more formally as event tracing sessions. The eight bits of the EnableMask track which of the possible loggers are enabled.
Space for four pointers in the middle of the structure is used very differently in the different types of object.
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x14 (6.1) | 0x20 (6.1) |
ULONG SessionId; |
6.1 only |
0x14 (6.0 to 6.1); 0x0C (6.2 to 6.3); 0x18 |
0x20 (6.0 to 6.1); 0x18 (6.2 to 6.3); 0x30 |
ETW_REPLY_QUEUE *ReplyQueue; |
6.0 and higher |
0x14 (6.0 to 6.1); 0x0C (6.2 to 6.3); 0x18 |
0x20 (6.0 to 6.1); 0x18 (6.2 to 6.3); 0x30 |
ETW_REG_ENTRY *ReplySlot [4]; |
6.0 to 6.1 |
ETW_QUEUE_ENTRY *ReplySlot [4]; |
6.2 and higher | ||
0x0C (6.2 to 6.3); 0x18 |
0x18 (6.2 to 6.3); 0x30 |
struct { PVOID Caller; ULONG SessionId; }; |
6.2 and higher |
The ReplyQueue is meaningful in a registration object that has DbgReplyRegistration set among the Flags to denote that it exists to support the retrieval of replies to a notification.
A registration object for which DbgUserRegistration is set can be sent notifications which may request replies. The ReplySlot array is how the replies are kept until their retrieval.
The SessionId and later the Caller are meaningful only for kernel-mode registrations, i.e., when DbgKernelRegistration is set. The Caller is in fact older but was kept separately from the ETW_REG_ENTRY as a member of the ETW_PROVIDER_TABLE_ENTRY.