SKETCH OF HOW RESEARCH MIGHT CONTINUE AND RESULTS BE PRESENTED

StartTrace

This function starts an Event Tracing for Windows (ETW) tracing session, also known informally as an event logger.

Declaration

ULONG
StartTrace (
    TRACEHANDLE *SessionHandle,
    LPCTSTR InstanceName,
    EVENT_TRACE_PROPERTIES *Properties);

Parameters

The SessionHandle argument is the address of an 8-byte variable that is to receive a handle to the started session.

The InstanceName argument is the address of a null-terminated case-insensitive string that names the session.

The Properties argument is the address of a buffer that is used for both input and output to describe the session. On input, it specifies what properties are wanted for the session. The successful function updates the buffer to show what properties are accepted for the session.

Return Value

The function returns zero for success, else an error code (which is also set as the thread’s last Win32 error).

Availability

The StartTrace function is exported by name from ADVAPI32.DLL in both ANSI and Unicode variants, StartTraceA and StartTraceW, in version 5.0 and higher.

As with many ETW functions, the StartTrace implementation has moved. It is natively in ADVAPI32 only in versions 5.0 to 5.1 and again in 6.0 to 6.1. In version 5.2 only, the export from ADVAPI32 is merely a forward to the NTDLL function EtwStartTrace, again in ANSI and Unicode variants. In version 6.2 and higher, the ADVAPI32 implementations are merely stubs for jumping to or calling the true implementations elsewhere: KERNELBASE.DLL in version 6.2, but SECHOST.DLL in versions 6.3 and higher; StartTraceA as a direct import but StartTraceW via the API Set api-ms-win-eventing-controller-l1-1-0.dll.

Documentation Status

The StartTrace function has always been documented. A curiosity is that for nearly two decades, the documentation used SessionName for the argument that the declaration in EVNTRACE.H has always had as InstanceName.  

Behaviour

Broadly speaking, the successful function proceeds in distinct stages:

Validation

All three arguments are required. The returned error code is ERROR_INVALID_PARAMETER if either of SessionHandle or Properties is NULL, but ERROR_INVALID_NAME if InstanceName is NULL. Note that although Microsoft’s documentation has long gone to unusual trouble to list “some common errors”, it somehow misses this second possibility.

Properties Buffer

The buffer at Properties begins with an EVENT_TRACE_PROPERTIES structure which directly specifies many properties for the session but which is in general a fixed-size header to be followed by variable-size properties. The total size in bytes must be supplied as the BufferSize in the Wnode. If this is not large enough for at least the EVENT_TRACE_PROPERTIES structure, the function fails, returning ERROR_BAD_LENGTH.

The variable-size properties on input can be:

On the function’s success, the variable-size output can be:

All are optional. The original two are indicated by obviously named members of the EVENT_TRACE_PROPERTIES. A non-zero LogFileNameOffset on input is the offset in bytes from Properties to the filename that the tracing session is to log to. If only in principle (see below), a non-zero LoggerNameOffset on input is the offset from Properties to where the function is to place the tracing session’s name. It is an error (ERROR_INVALID_PARAMETER) if either offset is non-zero but would place the corresponding name to start inside the EVENT_TRACE_PROPERTIES or beyond the buffer.

Session Name

Every tracing session has a GUID and a name. The GUID can be specified in the Guid member of the Wnode. The name is supplied by the InstanceName argument.

If the session name is either of the reserved names in the following table, then the Guid in the Wnode is forced to the corresponding GUID. Conversely, if the Guid is either of these but the InstanceName is not the corresponding reserved name, the function returns ERROR_INVALID_PARAMETER. Comparison is case-sensitive before version 6.0 but case-insensitive since.

Session Name GUID Versions
NT Kernel Logger {9E814AAD-3204-11D2-9A82-006008A86939} 5.1 and higher
Circular Kernel Context Logger {54DEA73A-ED1F-42A4-AF71-3E63D056F174} 6.0 and higher

Log File Name

If the Properties name a log file, i.e., if LogFileNameOffset is non-zero, then the function attempts to obtain the full pathname to use instead of the given name. Failure to get the full pathname is not of itself an error, but if sufficient memory cannot be found for the attempt, the function fails, returning ERROR_NOT_ENOUGH_MEMORY in version 5.2 and higher (but ERROR_OUTOFMEMORY before).

Name Lengths

Whether the function obtains the full pathname or persists with the filename as given, if the name is empty or is too long, then (except for the point in the next paragraph) the function proceeds as if no log file is named. Too long means more than 65,536 characters.

Even if the function obtains the full pathname or rejects the name as too long, it requires that the Properties buffer continues far enough to hold the log file name as given and to be capable of receiving a copy of the InstanceName. Otherwise, the function returns ERROR_BAD_LENGTH.

If the InstanceName is empty or too long, the function fails, returning ERROR_INVALID_NAME.

Log File Mode

There are numerous constraints on the LogFileMode, sometimes in conjunction with other input, most notably to require that a log file is named or that MaximumFileSize is non-zero.

The function requires at least one of the following, else it fails, returning ERROR_BAD_PATHNAME:

From the error code, the thinking may be surmised as: a usable log file name (see above) is required except in real-time or buffering mode. As may be seen below, the converse is not true: even in real-time or buffering mode, a log file name may be required because some other mode is set too.

For other invalid combinations, as listed next, the returned error code is ERROR_INVALID_PARAMETER. Be aware that the kernel or NTDLL, should the function proceed that far, impose yet more constraints. What StartTrace aims for is apparently just to reject the main inconsistencies.

Numerical Value Symbolic Name Requirements Versions
0x00000001 EVENT_TRACE_FILE_MODE_SEQUENTIAL    
0x00000002 EVENT_TRACE_FILE_MODE_CIRCULAR invalid with EVENT_TRACE_FILE_MODE_APPEND;
invalid with EVENT_TRACE_FILE_MODE_NEWFILE;
invalid with EVENT_TRACE_RELOG_MODE
5.1 and higher
requires non-zero MaximumFileSize 5.2 and higher
0x00000004 EVENT_TRACE_FILE_MODE_APPEND invalid with EVENT_TRACE_FILE_MODE_CIRCULAR;
invalid with EVENT_TRACE_REAL_TIME_MODE;
invalid with EVENT_TRACE_RELOG_MODE
5.1 and higher
0x00000008 EVENT_TRACE_FILE_MODE_NEWFILE invalid with EVENT_TRACE_FILE_MODE_CIRCULAR;
invalid with EVENT_TRACE_FILE_MODE_PREALLOCATE;
invalid with EVENT_TRACE_RELOG_MODE;
requires non-zero MaximumFileSize;
requires log file name
5.1 and higher
invalid with EVENT_TRACE_PRIVATE_LOGGER_MODE 5.2 to 6.0
invalid for NT Kernel Logger 5.2 and higher
0x00000010 EVENT_TRACE_USE_MS_FLUSH_TIMER    
0x00000020 EVENT_TRACE_FILE_MODE_PREALLOCATE requires non-zero MaximumFileSize;
invalid with EVENT_TRACE_FILE_MODE_NEWFILE;
requires log file name
5.1 and higher
invalid with EVENT_TRACE_PRIVATE_LOGGER_MODE 5.2 only
0x00000040 EVENT_TRACE_NONSTOPPABLE_MODE invalid 6.0 and higher
0x00000080 EVENT_TRACE_SECURE_MODE    
0x00000100 EVENT_TRACE_REAL_TIME_MODE invalid with EVENT_TRACE_PRIVATE_LOGGER_MODE 5.0 and higher
invalid with EVENT_TRACE_FILE_MODE_APPEND 5.1 and higher
0x00000200 EVENT_TRACE_DELAY_OPEN_FILE_MODE    
0x00000400 EVENT_TRACE_BUFFERING_MODE    
0x00000800 EVENT_TRACE_PRIVATE_LOGGER_MODE invalid with EVENT_TRACE_REAL_TIME_MODE 5.0 and higher
required by EVENT_TRACE_RELOG_MODE 5.1 and higher
invalid with EVENT_TRACE_FILE_MODE_PREALLOCATE 5.2 only
invalid with EVENT_TRACE_FILE_MODE_NEWFILE 5.2 to 6.0
required by EVENT_TRACE_PRIVATE_IN_PROC 6.0 and higher
required by EVENT_TRACE_INDEPENDENT_SESSION_MODE 6.3 and higher
0x00001000 EVENT_TRACE_ADD_HEADER_MODE invalid with EVENT_TRACE_REAL_TIME_MODE 5.0 and higher
0x00002000 EVENT_TRACE_USE_KBYTES_FOR_SIZE requires non-zero MaximumFileSize;
requires log file name
5.2 and higher
0x00004000 EVENT_TRACE_USE_GLOBAL_SEQUENCE    
0x00008000 EVENT_TRACE_USE_LOCAL_SEQUENCE    
0x00010000 EVENT_TRACE_RELOG_MODE invalid with EVENT_TRACE_FILE_MODE_CIRCULAR;
invalid with EVENT_TRACE_FILE_MODE_APPEND;
invalid with EVENT_TRACE_FILE_MODE_NEWFILE;
requires EVENT_TRACE_PRIVATE_LOGGER_MODE
5.1 and higher
0x00020000 EVENT_TRACE_PRIVATE_IN_PROC requires EVENT_TRACE_PRIVATE_LOGGER_MODE 6.0 and higher
0x00040000 EVENT_TRACE_BUFFER_INTERFACE_MODE    
0x00080000 EVENT_TRACE_KD_FILTER_MODE    
0x00100000 EVENT_TRACE_REAL_TIME_RELOG_MODE    
0x00200000 EVENT_TRACE_LOST_EVENTS_DEBUG_MODE    
0x00400000 EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN    
0x00800000 EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN    
0x01000000 EVENT_TRACE_USE_PAGED_MEMORY    
0x02000000 EVENT_TRACE_SYSTEM_LOGGER_MODE    
0x04000000 EVENT_TRACE_COMPRESSED_MODE    
0x08000000 EVENT_TRACE_INDEPENDENT_SESSION_MODE requires EVENT_TRACE_PRIVATE_LOGGER_MODE 6.3 and higher
0x10000000 EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING    
0x20000000 EVENT_TRACE_BLOCKING_MODE    
0x40000000 apparently unused    
0x80000000 EVENT_TRACE_ADDTO_TRIAGE_DUMP    

A set EVENT_TRACE_FILE_MODE_NEWFILE means that the log file’s name is only the basis from which the implementation is to generate new names for new log files. In version 5.2 and higher, the name (as given or as the full pathname) must contain exactly one percent sign which is followed immediately by a lower-case d to make a %d placeholder in the style of the printf function from the C Run-Time. Otherwise, the function fails, returning ERROR_INVALID_NAME.

Version 5.1 also requires a numerical placeholder in this case but is less particular. It rejects the log file name only if a trial resolution of 1 for the placeholder does not change the name. Though this flexibility soon was lost from the code, it remains in Microsoft’s documentation of Logging Mode Constants, which to this day might easily be read as suggesting %d only “for example”.

Enable Flag Extensions

Except on one point, the EnableFlags in the EVENT_TRACE_PROPERTIES are no direct concern to the StartTrace function. They are meaningful to the kernel only if the tracing session is the NT Kernel Logger or, in version 6.2 and higher, has EVENT_TRACE_SYSTEM_LOGGER_MODE in the LogFileMode. They then select broad categories of events that the tracing session seeks from the system trace provider.

The exception applies in version 5.1 and higher if the highest bit of the EnableFlags is set. That Microsoft names this bit EVENT_TRACE_FLAG_EXTENSION has been known from EVNTRACE.H since at least 1999, but it has otherwise been left undocumented for two decades. Its effect is that the 32-bit EnableFlags is re-interpreted as a 4-byte TRACE_ENABLE_FLAG_EXTENSION structure. The low 16 bits are an Offset in bytes from the Properties to the extension. The next 8 bits are the extension’s Length in dwords.

Originally, the extension is opaque to the function but version 6.0 extended the extensibility to allow for multiple items which are each opaque. This is indicated when the Length is 0xFF. The extension then begins as a 4-byte TRACE_ENABLE_FLAG_EXT_HEADER that supplies the extension’s true Length in dwords (including the header just mentioned) and the count of Items that follow. Each item is its own 4-byte TRACE_ENABLE_FLAG_EXT_ITEM as a header to introduce the item’s opaque contents. The item’s header supplies as Offset and a Type. Perhaps confusingly, this Offset is the item’s length in dwords (including the header).

Given that the EVENT_TRACE_FLAG_EXTENSION bit is set in the EnableFlags, the function aims to enforce that a properly formed extension is supplied within the Properties buffer after the EVENT_TRACE_PROPERTIES header, else to return ERROR_INVALID_PARAMETER. The following are required always: 

If Length is not 0xFF, then this last requirement is simply for Length dwords.

If Length is 0xFF, then this space in the Properties buffer must be large enough for a 4-byte TRACE_ENABLE_FLAG_EXT_HEADER

TO BE DONE?