Windows ETW:StartTrace失败,错误87(ERROR_INVALID_PARAMETER)

时间:2012-01-29 00:48:23

标签: delphi winapi etw

我正在调用Windows StartTrace函数的事件跟踪:

StartTrace(sessionHandle, KERNEL_LOGGER_NAME, sessionProperties);

失败,错误代码为87(ERROR_INVALID_PARAMETER)。 MSDN给出了此错误的一些常见原因:

  • 属性 NULL
  • SessionHandle NULL
  • 属性 LogFileNameOffset 成员无效。
  • 属性 LoggerNameOffset 成员无效。
  • 属性 LogFileMode 成员指定无效的标记组合。
  • Wnode.Guid 成员 SystemTraceControlGuid ,但 SessionName 参数不是 KERNEL_LOGGER_NAME

我正在调用的代码是:

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;

我的电话语言无关的版本:

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

其中TraceHandle指向64位整数:

0018F56C: 00 00 00 00  00 00 00 00

InstanceName是指向以null结尾的ansi字符串的指针:

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

Properties是指向EVENT_TRACE_PROPERTIES结构的指针,我将避免重现完整的十六进制转储

002A3BD8: 0000009A (154 bytes)

重要的值是两个偏移量:

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

还包含有效的以null结尾的ansi字符串:

“NT内核记录器”:

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

“C:\用户\伊恩\ foo.etl”:

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

为什么我的参数不正确?


奖金阅读

更新

会话参数:

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 

分解为:

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|

如果存在对齐问题,我将无法单独发现它。


结构:

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;

以及:

WNODE_HEADER = packed record
   BufferSize : Longword;
   ProviderId : Longword;
   Version : Longword;
   Linkage : Longword;
   TimeStamp : Int64;
   Guid : TGUID;
   ClientContext : Longword;
   Flags : Longword;
end;

2 个答案:

答案 0 :(得分:2)

哦,我看到卢克评论的评论是什么。

这不是结构错位的方式。 >结构后的内容必须8-byte对齐。换句话说:

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

看起来数据需要在Windows 8-byte边界上对齐(7(专业版(64位)))

为了帮助填充,我编写了一个Pad函数,该函数将数字四舍五入到最接近的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;

然后我改变了原始问题中的一些代码来使用它。

  • 计算所需的总buffserSize

    loggerName := KERNEL_LOGGER_NAME;
    logFilePath := 'C:\Users\Ian\foo.etl';
    
    bufferSize := sizeof(EVENT_TRACE_PROPERTIES)
            + Pad(Length(loggerName)+1)
            + Pad(Length(logFilePath)+1);
    
  • 然后我需要在8字节边界上推动偏移:

    sessionProperties.LoggerNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES));
    sessionProperties.LogFileNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES)) + Pad(Length(loggerName)+1);
    
  • 只要我将字符串复制到结构中声明的偏移量就可以了:

    //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);
    

和blingo-blango一起工作。

  

注意:任何代码都会发布到公共域中。无需归属。

答案 1 :(得分:1)

不是答案,但我找到了一些有趣的事情:如果你更换了这行:

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

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

然后错误代码变为ERROR_BAD_LENGTH(24)。我想我正在为跟踪API使用一组不同的单元,在我的例子中,StartTrace需要一个PWideChar,但是loggerName是一个AnsiString。由于我不知道你的EventTrace单元是什么样的,所以很难说你是否也是这样。无论如何,它都不会使StartTrace()调用成功。