Windows ETW: StartTrace Error with Error 87 (ERROR_INVALID_PARAMETER)

I call event tracking for Windows StartTrace :

 StartTrace(sessionHandle, KERNEL_LOGGER_NAME, sessionProperties); 

Error with error code 87 ( ERROR_INVALID_PARAMETER ). MSDN gives some common reasons for this error:

  • NULL Properties.
  • SessionHandle NULL .
  • Invalid LogFileNameOffset element is invalid.
  • Invalid LoggerNameOffset element is invalid.
  • The LogFileMode element of a property indicates a combination of flags that is not valid.
  • The Wnode.Guid element is SystemTraceControlGuid , but the SessionName parameter is not KERNEL_LOGGER_NAME .

The code I call:

 procedure StartKernelLogging; var sessionProperties: PEVENT_TRACE_PROPERTIES; bufferSize: Int64; loggerName: AnsiString; logFilePath: AnsiString; th: TRACEHANDLE; hr: Cardinal; begin { Allocate memory for the session properties. The memory must be large enough to include the log file name and session name, which get appended to the end of the session properties structure. } loggerName := KERNEL_LOGGER_NAME; logFilePath := 'C:\Users\Ian\foo.etl'; bufferSize := sizeof(EVENT_TRACE_PROPERTIES) + Length(loggerName)+1 + Length(logFilePath)+1; sessionProperties := AllocMem(bufferSize); ZeroMemory(sessionProperties, bufferSize); sessionProperties.Wnode.BufferSize := bufferSize; sessionProperties.Wnode.Flags := WNODE_FLAG_TRACED_GUID; sessionProperties.Wnode.ClientContext := 1; //QPC clock resolution sessionProperties.Wnode.Guid := SystemTraceControlGuid; sessionProperties.EnableFlags := EVENT_TRACE_FLAG_NETWORK_TCPIP; sessionProperties.LogFileMode := EVENT_TRACE_FILE_MODE_CIRCULAR; sessionProperties.MaximumFileSize := 5; // 5 MB sessionProperties.LoggerNameOffset := sizeof(EVENT_TRACE_PROPERTIES); sessionProperties.LogFileNameOffset := sizeof(EVENT_TRACE_PROPERTIES) + Length(loggerName)+1; //Copy LoggerName to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+Cardinal(sessionProperties.LoggerNameOffset)), PAnsiChar(loggerName), Length(loggerName)+1); //Copy LogFilePath to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+Cardinal(sessionProperties.LogFileNameOffset)), PAnsiChar(logFilePath), Length(logFilePath)+1); th := 0; hr := EventTrace.StartTrace({var}th, PChar(loggerName), sessionProperties); if (hr <> ERROR_SUCCESS) then begin raise EWin32Error.Create(SysErrorMessage(hr)); end; end; 

The language of the agnostic version of my call:

 ADVAPI32.StartTraceA( TraceHandle: 0x18F56C InstanceName: 0x44E840 Properties: 0x243BD8); 

where TraceHandle points to a 64-bit integer:

 0018F56C: 00 00 00 00 00 00 00 00 

and InstanceName is a pointer to ansi string with a terminating zero:

 0044E840: 4E 54 20 4B 65 72 6E 65 NT Kerne 0044E848: 6C 20 4C 6F 67 67 65 72 l Logger 0044E850: 00 

and Properties is a pointer to the EVENT_TRACE_PROPERTIES structure, which I will refrain from playing the full hex dump

 002A3BD8: 0000009A (154 bytes) 

The important values โ€‹โ€‹are two offsets:

 properties.LoggerNameOffset = 116 (ie $243BB8 + 116 = $243C4C) properties.LogFileNameOffset = 133 (ie $243BD8 + 133 = $243C5D) 

which also contain valid ansi strings ending with zero, which they must:

"NT Logger":

 $243C4C 4B20544E 656E7265 NT Kerne $243C54 6F4C206C 72656767 l Logger $243C5C xxxxxx00 . 

"C: \ Users \ Jan \ foo.etl":

 $243C5C 5C3A43xx 72657355 .C:\User $243C64 61495C73 6F665C6E s\Ian\fo $243C6C 74652E6F xxxx006C o.etc. 

Why are my options incorrect?


Reading bonuses

Update:

Session Options:

 9A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AD 4A 81 9E 04 32 D2 11 9A 82 00 60 08 A8 69 39 01 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 02 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 85 00 00 00 74 00 00 00 

What breaks:

 000| Wnode.BufferSize: 9A 00 00 00 (154) 004| Wnode.ProviderID: 00 00 00 00 008| Wnode.Version: 00 00 00 00 012| Wnode.Linkage: 00 00 00 00 016| Wnode.Timestamp: 00 00 00 00 00 00 00 00 024| Wnode.Guid: AD 4A 81 9E 04 32 D2 11 9A 82 00 60 08 A8 69 39 (SystemTraceControlGuid) 040| Wnode.ClientContext: 01 00 00 00 (1) 044| Wnode.Flags: 00 00 02 00 (WNODE_FLAG_TRACED_GUID) 048| BufferSize: 00 00 00 00 052| MinimumBuffers: 00 00 00 00 056| MaximumBuffers: 00 00 00 00 060| MaximumFileSize: 05 00 00 00 (5 MB) 064| LogFileMode: 02 00 00 00 (EVENT_TRACE_FILE_MODE_CIRCULAR) 068| FlushTimer: 00 00 00 00 072| EnableFlags: 00 00 01 00 (EVENT_TRACE_FLAG_NETWORK_TCPIP) 076| AgeLimit: 00 00 00 00 080| NumberOfBuffers: 00 00 00 00 084| FreeBuffers: 00 00 00 00 088| EventsLost: 00 00 00 00 092| BuffersWritten: 00 00 00 00 096| LogBuffersLost: 00 00 00 00 100| RealTimeBuffersLost: 00 00 00 00 104| LoggerThreadId: 00 00 00 00 108| LogFileNameOffset: 85 00 00 00 (133) 112| LoggerNameOffset: 74 00 00 00 (116) 116| NT Kernel Logger\0 133| C:\Users\Ian\foo.etl\0 154| 

If the alignment problem, I can not detect it myself.


Structure:

 EVENT_TRACE_PROPERTIES = packed record Wnode : WNODE_HEADER; // data provided by caller BufferSize : Longword; // buffer size for logging (kbytes) MinimumBuffers : Longword; // minimum to preallocate MaximumBuffers : Longword; // maximum buffers allowed MaximumFileSize : Longword; // maximum logfile size (in MBytes) LogFileMode : Longword; // sequential, circular FlushTimer : Longword; // buffer flush timer, in seconds EnableFlags :Longword; // trace enable flags AgeLimit : Longint; // age decay time, in minutes // data returned to caller NumberOfBuffers : Longword; // no of buffers in use FreeBuffers : Longword; // no of buffers free EventsLost : Longword; // event records lost BuffersWritten : Longword; // no of buffers written to file LogBuffersLost : Longword; // no of logfile write failures RealTimeBuffersLost : Longword; // no of rt delivery failures LoggerThreadId : HANDLE; // thread id of Logger LogFileNameOffset : Longword; // Offset to LogFileName LoggerNameOffset : Longword; // Offset to LoggerName end; 

together with:

 WNODE_HEADER = packed record BufferSize : Longword; ProviderId : Longword; Version : Longword; Linkage : Longword; TimeStamp : Int64; Guid : TGUID; ClientContext : Longword; Flags : Longword; end; 
+1
winapi delphi etw
source share
2 answers

Oh, see what the comments from Lukeโ€™s comments say.

Not that the structure has been displaced, anyway. Content after , the structure should be 8-byte aligned. In other words:

 000| Wnode.BufferSize: 9A 00 00 00 (154) 004| Wnode.ProviderID: 00 00 00 00 ...snip... 108| LogFileNameOffset: 85 00 00 00 (133) 112| LoggerNameOffset: 74 00 00 00 (116) 116| 00 00 00 00 (4 bytes padding) 120| NT Kernel Logger\0 136| 00 00 00 00 00 00 00 (7 bytes padding) 144| C:\Users\Ian\foo.etl\0 

It looks like the data should be aligned on 8-byte borders in Windows (7 (Professional (64-bit))

To help fill out, I wrote a Pad function that rounds a number to the nearest multiple of 8:

 function Pad(length: Cardinal): Cardinal; var m: Integer; const DataAlignment = 8; //align data on 8-byte boundaries begin Result := length; m := length mod DataAlignment; if (m > 0) then Result := result + DataAlignment-m; end; 

Then I changed a piece of code from the original question to use it.

  • calculate the required buffserSize value:

     loggerName := KERNEL_LOGGER_NAME; logFilePath := 'C:\Users\Ian\foo.etl'; bufferSize := sizeof(EVENT_TRACE_PROPERTIES) + Pad(Length(loggerName)+1) + Pad(Length(logFilePath)+1); 
  • then I need to push my offsets on an 8-byte border:

     sessionProperties.LoggerNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES)); sessionProperties.LogFileNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES)) + Pad(Length(loggerName)+1); 
  • and as long as I copy the lines to the offsets declared in the structure, I'm fine:

     //Copy LoggerName to the offset address MoveMemory( Pointer(Cardinal(sessionProperties)+sessionProperties.LoggerNameOffset), PAnsiChar(loggerName), Length(loggerName)+1); //Copy LogFilePath to the offset address MoveMemory( Pointer(Cardinal(sessionProperties)+sessionProperties.LogFileNameOffset), PAnsiChar(logFilePath), Length(logFilePath)+1); 

And blingo-blango, it works.

Note Any code issued in a public domain. No attribution required.

+2
source share

Not an answer, but something interesting I found: If you replace the line:

 hr := EventTrace.StartTrace({var}th, PChar(loggerName), sessionProperties); 

from

 hr := EventTrace.StartTrace({var}th, KERNEL_LOGGER_NAME, sessionProperties); 

then the error code will become ERROR_BAD_LENGTH (24). I think I am using a different set of units for the tracing APIs, and in my case StartTrace wants PWideChar, but loggerName is AnsiString. Since I donโ€™t know what your EventTrace device looks like, itโ€™s hard to say whether this is the case for you or not. And independently, this does not make the StartTrace () call successful.

+1
source share

All Articles