Windows ETW: при запуске StartTrace произошла ошибка 87 (ERROR_INVALID_PARAMETER)
Я вызываю Event Tracing для Windows StartTrace
функция:
StartTrace(sessionHandle, KERNEL_LOGGER_NAME, sessionProperties);
Ошибка с кодом ошибки 87 (ERROR_INVALID_PARAMETER
). В MSDN приведены некоторые распространенные причины этой ошибки:
- СвойстваNULL.
- SessionHandle имеетзначение NULL.
- Элементсвойств LogFileNameOffset недопустим.
- Член LoggerNameOffset свойств недопустим.
- Член LogFileMode в Properties указываетнедопустимую комбинацию флагов.
- Членом 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
является указателем на строку 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)
которые также содержат действительные строки ANSI с нулевым символом в конце, которые они должны:
"NT Kernel Logger":
$243C4C 4B20544E 656E7265 NT Kerne
$243C54 6F4C206C 72656767 l Logger
$243C5C xxxxxx00 .
"C: \ Users \ Ян \foo.etl":
$243C5C 5C3A43xx 72657355 .C:\User
$243C64 61495C73 6F665C6E s\Ian\fo
$243C6C 74652E6F xxxx006C o.etc.
Почему мои параметры неверны?
Бонус Чтение
- wkf хочет знать, как зарегистрироваться для мониторинга событий ядра в реальном времени
- Пример кода MSDN (который является переводом) о том, как подключиться к сеансу регистрации ядра
Обновить:
Параметры сеанса:
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 ответа
О, я вижу, что говорят комментарии из комментариев Люка.
Дело не в том, что структура смещена каким-либо образом. Содержание после структуры должно быть 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
Похоже, данные должны быть выровнены по 8-byte
границы в Windows (7 (Professional (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);
И Блинго-Бланго, это работает.
Примечание. Любой код публикуется в открытом доступе. Атрибуция не требуется.
Не ответ, но кое-что интересное я нашел: Если вы замените строку:
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() успешным.