windows-nt/Source/XPSP1/NT/base/wmi/ntdll/logsup.c
2020-09-26 16:20:57 +08:00

2534 lines
81 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
logsup.c
Abstract:
WMI logger api set. The routines here will need to appear like they
are system calls. They are necessary to do the necessary error checking
and do most of the legwork that can be done outside the kernel. The
kernel portion will subsequently only deal with the actual logging
and tracing.
Author:
28-May-1997 JeePang
Revision History:
--*/
#ifndef MEMPHIS
#include <nt.h>
#include <ntrtl.h> // for ntutrl.h
#include <nturtl.h> // for RTL_CRITICAL_SECTION in winbase.h/wtypes.h
#include <wtypes.h> // for LPGUID in wmium.h
#include "wmiump.h"
#include "evntrace.h"
#include "traceump.h"
#include "tracelib.h"
#include <math.h>
#include "trcapi.h"
NTSTATUS
WmipProcessRunDown(
IN PWMI_LOGGER_CONTEXT Logger,
IN ULONG StartFlag,
IN ULONG fEnableFlags
);
NTSTATUS
WmipThreadRunDown(
IN PWMI_LOGGER_CONTEXT Logger,
IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
IN ULONG StartFlag,
IN BOOLEAN bExtended
);
ULONG WmiTraceAlignment = DEFAULT_TRACE_ALIGNMENT;
/*
ULONG
WmipStartLogger(
IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
)
/*++
Routine Description:
This is the actual routine to communicate with the kernel to start
the logger. All the required parameters must be in LoggerInfo.
Arguments:
LoggerInfo The actual parameters to be passed to and return from
kernel.
Return Value:
The status of performing the action requested.
--*//*
{
ULONG Status;
ULONG BufferSize;
ACCESS_MASK DesiredAccess = 0;
LPGUID Guid;
PVOID SavedChecksum;
ULONG SavedLogFileMode;
BOOLEAN IsKernelTrace = FALSE;
BOOLEAN bLogFile = FALSE;
BOOLEAN bRealTime = FALSE;
Guid = &LoggerInfo->Wnode.Guid;
if (IsEqualGUID(Guid, &SystemTraceControlGuid) ||
IsEqualGUID(Guid, &WmiEventLoggerGuid)) {
IsKernelTrace = TRUE;
DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
}
if ((LoggerInfo->LogFileName.Length > 0) &&
(LoggerInfo->LogFileName.Buffer != NULL)) {
DesiredAccess |= TRACELOG_CREATE_ONDISK;
bLogFile = TRUE;
}
SavedLogFileMode = LoggerInfo->LogFileMode;
if (SavedLogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
DesiredAccess |= TRACELOG_CREATE_REALTIME;
bRealTime = TRUE;
}
Status = WmipCheckGuidAccess( Guid, DesiredAccess );
if (Status != ERROR_SUCCESS) {
return Status;
}
//
// Set the Default Clock Type
//
if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME) {
LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_PERFCOUNTER;
}
if (SavedLogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
Status = WmipSendUmLogRequest(
WmiStartLoggerCode,
LoggerInfo
);
}
else if (IsKernelTrace) {
//
// In order to capture the process/thread rundown accurately, we need to
// start kernel logger in two steps. Start logger with delay write,
// do rundown from user mode and then updatelogger with filename.
//
WMI_LOGGER_INFORMATION DelayLoggerInfo;
ULONG EnableFlags = LoggerInfo->EnableFlags;
LARGE_INTEGER Frequency;
WMI_REF_CLOCK RefClock;
//
// If it's only realtime start logger in one step
//
if (bRealTime && !bLogFile) {
BufferSize = LoggerInfo->BufferSize * 1024;
Status = WmipSendWmiKMRequest(
NULL,
IOCTL_WMI_START_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&BufferSize,
NULL
);
return WmipSetDosError(Status);
}
if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
&LoggerInfo->EnableFlags;
EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
}
//
// Take a reference timestamp before actually starting the logger
//
RefClock.StartTime.QuadPart = WmipGetSystemTime();
if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_PERFCOUNTER) {
Status = NtQueryPerformanceCounter(&RefClock.StartPerfClock, &Frequency);
}
else {
RefClock.StartPerfClock = RefClock.StartTime;
}
RtlCopyMemory(&DelayLoggerInfo, LoggerInfo, sizeof(WMI_LOGGER_INFORMATION));
RtlZeroMemory(&DelayLoggerInfo.LogFileName, sizeof(UNICODE_STRING) );
DelayLoggerInfo.Wnode.BufferSize = sizeof(WMI_LOGGER_INFORMATION);
DelayLoggerInfo.LogFileMode |= EVENT_TRACE_DELAY_OPEN_FILE_MODE;
//
// Since there's no filename in step 1 of StartLogger we need to mask
// the NEWFILE mode to prevent kernel trying to generate a file
//
DelayLoggerInfo.LogFileMode &= ~EVENT_TRACE_FILE_MODE_NEWFILE;
DelayLoggerInfo.EnableFlags = (EVENT_TRACE_FLAG_PROCESS & EnableFlags);
DelayLoggerInfo.EnableFlags |= (EVENT_TRACE_FLAG_THREAD & EnableFlags);
DelayLoggerInfo.EnableFlags |= (EVENT_TRACE_FLAG_IMAGE_LOAD & EnableFlags);
BufferSize = DelayLoggerInfo.BufferSize * 1024;
Status = WmipSendWmiKMRequest(
NULL,
IOCTL_WMI_START_LOGGER,
&DelayLoggerInfo,
DelayLoggerInfo.Wnode.BufferSize,
&DelayLoggerInfo,
DelayLoggerInfo.Wnode.BufferSize,
&BufferSize,
NULL
);
if (Status != ERROR_SUCCESS) {
return Status;
}
//
// We need to pick up any parameter adjustment done by the kernel
// here so UpdateTrace does not fail.
//
LoggerInfo->Wnode.HistoricalContext = DelayLoggerInfo.Wnode.HistoricalContext;
LoggerInfo->MinimumBuffers = DelayLoggerInfo.MinimumBuffers;
LoggerInfo->MaximumBuffers = DelayLoggerInfo.MaximumBuffers;
LoggerInfo->NumberOfBuffers = DelayLoggerInfo.NumberOfBuffers;
LoggerInfo->BufferSize = DelayLoggerInfo.BufferSize;
LoggerInfo->AgeLimit = DelayLoggerInfo.AgeLimit;
BufferSize = LoggerInfo->BufferSize * 1024;
//
// Add the LogHeader
//
LoggerInfo->Checksum = NULL;
Status = WmipAddLogHeaderToLogFile(LoggerInfo, &RefClock, FALSE);
if (Status == ERROR_SUCCESS) {
SavedChecksum = LoggerInfo->Checksum;
//
// Update the logger with the filename
//
Status = WmipSendWmiKMRequest(
NULL,
IOCTL_WMI_UPDATE_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&BufferSize,
NULL
);
if (LoggerInfo->Checksum != NULL) {
WmipFree(LoggerInfo->Checksum);
}
}
if (Status != ERROR_SUCCESS) {
ULONG lStatus;
//
// Logger must be stopped now
//
lStatus = WmipSendWmiKMRequest(
NULL,
IOCTL_WMI_STOP_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&BufferSize,
NULL
);
LoggerInfo->LogFileMode = SavedLogFileMode;
return WmipSetDosError(Status);
}
else {
if (LoggerInfo->LogFileHandle != NULL) {
NtClose(LoggerInfo->LogFileHandle);
LoggerInfo->LogFileHandle = NULL;
}
}
}
else {
LoggerInfo->Checksum = NULL;
Status = WmipAddLogHeaderToLogFile(LoggerInfo, NULL, FALSE);
if (Status != ERROR_SUCCESS) {
return WmipSetDosError(Status);
}
BufferSize = LoggerInfo->BufferSize * 1024;
SavedChecksum = LoggerInfo->Checksum;
Status = WmipSendWmiKMRequest( // actually start the logger here
NULL,
IOCTL_WMI_START_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&BufferSize,
NULL
);
if (Status == ERROR_SUCCESS) {
if (LoggerInfo->LogFileHandle != NULL) {
NtClose(LoggerInfo->LogFileHandle);
LoggerInfo->LogFileHandle = NULL;
}
}
if (SavedChecksum != NULL) {
WmipFree(SavedChecksum);
}
}
//
// Restore the LogFileMode
//
LoggerInfo->LogFileMode = SavedLogFileMode;
return WmipSetDosError(Status);
}*/
ULONG
WmipFinalizeLogFileHeader(
IN PWMI_LOGGER_INFORMATION LoggerInfo
)
{
ULONG Status = ERROR_SUCCESS;
ULONG ErrorCode = ERROR_SUCCESS;
HANDLE LogFile = INVALID_HANDLE_VALUE;
LARGE_INTEGER CurrentTime;
ULONG BuffersWritten;
WMI_LOGGER_CONTEXT Logger;
IO_STATUS_BLOCK IoStatus;
FILE_POSITION_INFORMATION FileInfo;
FILE_STANDARD_INFORMATION FileSize;
PWMI_BUFFER_HEADER Buffer; // need to initialize buffer first
SYSTEM_BASIC_INFORMATION SystemInfo;
ULONG EnableFlags;
RtlZeroMemory(&Logger, sizeof(WMI_LOGGER_CONTEXT));
Logger.BufferSpace = NULL;
if (LoggerInfo->LogFileName.Length > 0 ) {
// open the file for writing synchronously for the logger
// others may want to read it as well.
//
LogFile = WmipCreateFileW(
(LPWSTR)LoggerInfo->LogFileName.Buffer,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (LogFile == INVALID_HANDLE_VALUE) {
ErrorCode = WmipSetDosError(WmipGetLastError());
goto cleanup;
}
Logger.BuffersWritten = LoggerInfo->BuffersWritten;
Logger.BufferSpace = WmipAlloc(LoggerInfo->BufferSize * 1024);
if (Logger.BufferSpace == NULL) {
ErrorCode = WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
RtlZeroMemory(Buffer, LoggerInfo->BufferSize * 1024);
Buffer->Wnode.BufferSize = LoggerInfo->BufferSize * 1024;
Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
Buffer->EventsLost = 0;
Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
Status = NtQuerySystemInformation(
SystemBasicInformation,
&SystemInfo, sizeof (SystemInfo), NULL);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
Logger.TimerResolution = SystemInfo.TimerResolution;
Logger.LogFileHandle = LogFile;
Logger.BufferSize = LoggerInfo->BufferSize * 1024;
// For Circular LogFile the process rundown data is appended at the
// last buffer written and not to the end of file.
//
Status = NtQueryInformationFile(
LogFile,
&IoStatus,
&FileSize,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid)) {
if (LoggerInfo->LogFileMode != EVENT_TRACE_FILE_MODE_CIRCULAR) {
FileInfo.CurrentByteOffset = FileSize.EndOfFile;
}
else {
ULONG BufferSize = LoggerInfo->BufferSize; // in KB
ULONG BuffersWritten = LoggerInfo->BuffersWritten;
ULONG maxBuffers = (LoggerInfo->MaximumFileSize * 1024) / BufferSize;
ULONG LastBuffer;
ULONG StartBuffers;
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(StartBuffers);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
Status = NtReadFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&StartBuffers,
sizeof(ULONG),
NULL,
NULL
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
LastBuffer = (maxBuffers > StartBuffers) ?
(StartBuffers + (BuffersWritten - StartBuffers)
% (maxBuffers - StartBuffers))
: 0;
FileInfo.CurrentByteOffset.QuadPart = LastBuffer *
BufferSize * 1024;
}
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
EnableFlags = LoggerInfo->EnableFlags;
if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
&LoggerInfo->EnableFlags;
if (LoggerInfo->Wnode.BufferSize >= (tFlagExt->Offset + sizeof(ULONG)) ) {
EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
}
else {
EnableFlags = 0; // Should not happen.
}
}
if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME) {
LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_PERFCOUNTER;
}
Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
WmipProcessRunDown(&Logger, FALSE, EnableFlags);
{
PWMI_BUFFER_HEADER Buffer1 =
(PWMI_BUFFER_HEADER) Logger.BufferSpace;
if (Buffer1->Offset < Logger.BufferSize) {
RtlFillMemory(
(char *) Logger.BufferSpace + Buffer1->Offset,
Logger.BufferSize - Buffer1->Offset,
0xFF);
}
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
Logger.BufferSpace,
Logger.BufferSize,
NULL,
NULL);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
Logger.BuffersWritten++;
}
}
else { // For Application Traces, need to dump the guidmaps again.
// Set the FilePointer to end of file so that Rundown data may be appended.
//
FileInfo.CurrentByteOffset = FileSize.EndOfFile;
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
// Dump the Guid Maps once more at the End.
//
Buffer->EventsLost = 0;
Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
BuffersWritten = Logger.BuffersWritten;
if (WmipDumpGuidMaps(&Logger, NULL, FALSE) > 0) {
if (Buffer->Offset < Logger.BufferSize) {
RtlFillMemory(
(char *) Logger.BufferSpace + Buffer->Offset,
Logger.BufferSize - Buffer->Offset,
0xFF);
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
Logger.BufferSpace,
Logger.BufferSize,
NULL,
NULL);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
Logger.BuffersWritten = BuffersWritten;
}
}
}
// TODO: should use memory-mapped file
// Update the EndTime stamp field in LogFile.
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(EndTime);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
// End Time is always wallclock time.
//
CurrentTime.QuadPart = WmipGetSystemTime();
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&CurrentTime,
sizeof(ULONGLONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
}
// Update the Number of Buffers Written field in the header
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(BuffersWritten);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&Logger.BuffersWritten,
sizeof(ULONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
}
ErrorCode = RtlNtStatusToDosError(Status);
LoggerInfo->BuffersWritten = Logger.BuffersWritten;
//
// Write the BuffersLost information into the logfile
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(BuffersLost);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&LoggerInfo->LogBuffersLost,
sizeof(ULONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
}
//
// Write the EventsLost information into the logfile
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(EventsLost);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipSetNtStatus(Status);
goto cleanup;
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&LoggerInfo->EventsLost,
sizeof(ULONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
}
}
cleanup:
if (LogFile != INVALID_HANDLE_VALUE) {
NtClose(LogFile);
}
if (Logger.BufferSpace != NULL) {
WmipFree(Logger.BufferSpace);
}
return WmipSetDosError(ErrorCode);
}
ULONG
WmipStopLogger(
IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
)
/*++
Routine Description:
This is the actual routine to communicate with the kernel to stop
the logger. All the properties of the logger will be returned in LoggerInfo.
Arguments:
LoggerInfo The actual parameters to be passed to and return from
kernel.
Return Value:
The status of performing the action requested.
--*/
{
ULONG ErrorCode, ReturnSize;
PTRACE_ENABLE_CONTEXT pContext;
if (LoggerInfo == NULL)
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
return WmipSetDosError(ERROR_INVALID_PARAMETER);
pContext = (PTRACE_ENABLE_CONTEXT) & LoggerInfo->Wnode.HistoricalContext;
if ( (pContext->InternalFlag != 0)
&& (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
// Currently only one possible InternalFlag value. This will filter
// out some bogus LoggerHandle
//
return WmipSetDosError(ERROR_INVALID_HANDLE);
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
ErrorCode = WmipSendUmLogRequest(WmiStopLoggerCode, LoggerInfo);
pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
pContext->LoggerId = 1;
}
else {
ErrorCode = WmipSendWmiKMRequest(
NULL,
IOCTL_WMI_STOP_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&ReturnSize,
NULL
);
//
// if logging to a file, then update the EndTime, BuffersWritten and do
// process rundown for kernel trace.
//
if (ErrorCode == ERROR_SUCCESS) {
ErrorCode = WmipFinalizeLogFileHeader(LoggerInfo);
}
}
return WmipSetDosError(ErrorCode);
}
ULONG
WmipQueryLogger(
IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
IN ULONG Update
)
/*++
Routine Description:
This is the actual routine to communicate with the kernel to query
the logger. All the properties of the logger will be returned in LoggerInfo.
Arguments:
LoggerInfo The actual parameters to be passed to and return from
kernel.
Return Value:
The status of performing the action requested.
--*/
{
ULONG Status, ReturnSize;
HANDLE LogFileHandle = NULL;
PTRACE_ENABLE_CONTEXT pContext;
BOOLEAN bAddAppendFlag = FALSE;
ULONG SavedLogFileMode;
if (LoggerInfo == NULL)
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
return WmipSetDosError(ERROR_INVALID_PARAMETER);
LoggerInfo->Checksum = NULL;
LoggerInfo->LogFileHandle = NULL;
pContext = (PTRACE_ENABLE_CONTEXT) &LoggerInfo->Wnode.HistoricalContext;
if ( (pContext->InternalFlag != 0)
&& (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
// Currently only one possible InternalFlag value. This will filter
// out some bogus LoggerHandle
//
return WmipSetDosError(ERROR_INVALID_HANDLE);
}
//
// If UPDATE and a new logfile is given throw in the LogFileHeader
//
if ( Update
&& LoggerInfo->LogFileName.Length > 0
&& !( (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
|| (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE))) {
Status = WmipAddLogHeaderToLogFile(LoggerInfo, NULL, Update);
if (Status != ERROR_SUCCESS) {
return WmipSetDosError(Status);
}
LogFileHandle = LoggerInfo->LogFileHandle;
bAddAppendFlag = TRUE;
//
// If we are switching to a new file, make sure it is append mode
//
SavedLogFileMode = LoggerInfo->LogFileMode;
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE ||
pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
pContext->LoggerId = 1;
Status = WmipSendUmLogRequest(
(Update) ? (WmiUpdateLoggerCode) : (WmiQueryLoggerCode),
LoggerInfo
);
}
else {
Status = WmipSendWmiKMRequest(
NULL,
(Update ? IOCTL_WMI_UPDATE_LOGGER : IOCTL_WMI_QUERY_LOGGER),
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&ReturnSize,
NULL
);
if (LoggerInfo->Checksum != NULL) {
WmipFree(LoggerInfo->Checksum);
}
}
if (bAddAppendFlag) {
LoggerInfo->LogFileMode = SavedLogFileMode;
}
return WmipSetDosError(Status);
}
PVOID
WmipGetTraceBuffer(
IN PWMI_LOGGER_CONTEXT Logger,
IN PSYSTEM_THREAD_INFORMATION pThread,
IN ULONG GroupType,
IN ULONG RequiredSize
)
{
PSYSTEM_TRACE_HEADER Header;
PWMI_BUFFER_HEADER Buffer;
THREAD_BASIC_INFORMATION ThreadInfo;
KERNEL_USER_TIMES ThreadCpu;
NTSTATUS Status;
ULONG BytesUsed;
PCLIENT_ID Cid;
RequiredSize += sizeof (SYSTEM_TRACE_HEADER); // add in header
RequiredSize = (ULONG) ALIGN_TO_POWER2(RequiredSize, WmiTraceAlignment);
Buffer = (PWMI_BUFFER_HEADER) Logger->BufferSpace;
if (RequiredSize > Logger->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
WmipSetDosError(ERROR_BUFFER_OVERFLOW);
return NULL;
}
if (RequiredSize > (Logger->BufferSize - Buffer->Offset)) {
ULONG Status;
IO_STATUS_BLOCK IoStatus;
if (Buffer->Offset < Logger->BufferSize) {
RtlFillMemory(
(char *) Buffer + Buffer->Offset,
Logger->BufferSize - Buffer->Offset,
0xFF);
}
Status = NtWriteFile(
Logger->LogFileHandle,
NULL,
NULL,
NULL,
&IoStatus,
Buffer,
Logger->BufferSize,
NULL,
NULL);
Buffer->EventsLost = 0;
Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
if (!NT_SUCCESS(Status)) {
return NULL;
}
Logger->BuffersWritten++;
}
Header = (PSYSTEM_TRACE_HEADER) ((char*)Buffer + Buffer->Offset);
if (Logger->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
LARGE_INTEGER Frequency;
ULONGLONG Counter = 0;
Status = NtQueryPerformanceCounter((PLARGE_INTEGER)&Counter,
&Frequency);
Header->SystemTime.QuadPart = Counter;
}
else {
Header->SystemTime.QuadPart = WmipGetSystemTime();
}
Header->Header = (GroupType << 16) + RequiredSize;
Header->Marker = SYSTEM_TRACE_MARKER;
if (pThread == NULL) {
Status = NtQueryInformationThread(
NtCurrentThread(),
ThreadBasicInformation,
&ThreadInfo,
sizeof ThreadInfo, NULL);
if (NT_SUCCESS(Status)) {
Cid = &ThreadInfo.ClientId;
Header->ThreadId = HandleToUlong(Cid->UniqueThread);
Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
}
Status = NtQueryInformationThread(
NtCurrentThread(),
ThreadTimes,
&ThreadCpu, sizeof ThreadCpu, NULL);
if (NT_SUCCESS(Status)) {
Header->KernelTime = (ULONG) (ThreadCpu.KernelTime.QuadPart
/ Logger->TimerResolution);
Header->UserTime = (ULONG) (ThreadCpu.UserTime.QuadPart
/ Logger->TimerResolution);
}
}
else {
Cid = &pThread->ClientId;
Header->ThreadId = HandleToUlong(Cid->UniqueThread);
Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
Header->KernelTime = (ULONG) (pThread->KernelTime.QuadPart
/ Logger->TimerResolution);
Header->UserTime = (ULONG) (pThread->UserTime.QuadPart
/ Logger->TimerResolution);
}
Buffer->Offset += RequiredSize;
// If there is room, throw in a end of buffer marker.
BytesUsed = Buffer->Offset;
if ( BytesUsed <= (Logger->BufferSize-sizeof(ULONG)) ) {
*((long*)((char*)Buffer+Buffer->Offset)) = -1;
}
return (PVOID) ( (char*) Header + sizeof(SYSTEM_TRACE_HEADER) );
}
VOID
WmipCopyPropertiesToInfo(
IN PEVENT_TRACE_PROPERTIES Properties,
IN PWMI_LOGGER_INFORMATION Info
)
{
ULONG SavedBufferSize = Info->Wnode.BufferSize;
RtlCopyMemory(&Info->Wnode, &Properties->Wnode, sizeof(WNODE_HEADER));
Info->Wnode.BufferSize = SavedBufferSize;
Info->BufferSize = Properties->BufferSize;
Info->MinimumBuffers = Properties->MinimumBuffers;
Info->MaximumBuffers = Properties->MaximumBuffers;
Info->NumberOfBuffers = Properties->NumberOfBuffers;
Info->FreeBuffers = Properties->FreeBuffers;
Info->EventsLost = Properties->EventsLost;
Info->BuffersWritten = Properties->BuffersWritten;
Info->LoggerThreadId = Properties->LoggerThreadId;
Info->MaximumFileSize = Properties->MaximumFileSize;
Info->EnableFlags = Properties->EnableFlags;
Info->LogFileMode = Properties->LogFileMode;
Info->FlushTimer = Properties->FlushTimer;
Info->LogBuffersLost = Properties->LogBuffersLost;
Info->AgeLimit = Properties->AgeLimit;
Info->RealTimeBuffersLost = Properties->RealTimeBuffersLost;
}
VOID
WmipCopyInfoToProperties(
IN PWMI_LOGGER_INFORMATION Info,
IN PEVENT_TRACE_PROPERTIES Properties
)
{
ULONG SavedSize = Properties->Wnode.BufferSize;
RtlCopyMemory(&Properties->Wnode, &Info->Wnode, sizeof(WNODE_HEADER));
Properties->Wnode.BufferSize = SavedSize;
Properties->BufferSize = Info->BufferSize;
Properties->MinimumBuffers = Info->MinimumBuffers;
Properties->MaximumBuffers = Info->MaximumBuffers;
Properties->NumberOfBuffers = Info->NumberOfBuffers;
Properties->FreeBuffers = Info->FreeBuffers;
Properties->EventsLost = Info->EventsLost;
Properties->BuffersWritten = Info->BuffersWritten;
Properties->LoggerThreadId = Info->LoggerThreadId;
Properties->MaximumFileSize = Info->MaximumFileSize;
Properties->EnableFlags = Info->EnableFlags;
Properties->LogFileMode = Info->LogFileMode;
Properties->FlushTimer = Info->FlushTimer;
Properties->LogBuffersLost = Info->LogBuffersLost;
Properties->AgeLimit = Info->AgeLimit;
Properties->RealTimeBuffersLost = Info->RealTimeBuffersLost;
}
NTSTATUS
WmipThreadRunDown(
IN PWMI_LOGGER_CONTEXT Logger,
IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
IN ULONG StartFlag,
IN BOOLEAN bExtended
)
{
PSYSTEM_THREAD_INFORMATION pThreadInfo;
ULONG GroupType;
ULONG i;
ULONG Size;
ULONG SystemThreadInfoSize;
PWMI_EXTENDED_THREAD_INFORMATION ThreadInfo;
pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
GroupType = EVENT_TRACE_GROUP_THREAD +
((StartFlag) ? EVENT_TRACE_TYPE_DC_START
: EVENT_TRACE_TYPE_DC_END);
Size = sizeof(WMI_EXTENDED_THREAD_INFORMATION);
SystemThreadInfoSize = (bExtended) ? sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION)
: sizeof(SYSTEM_THREAD_INFORMATION);
for (i=0; i < pProcessInfo->NumberOfThreads; i++) {
if (pThreadInfo == NULL)
break;
ThreadInfo = (PWMI_EXTENDED_THREAD_INFORMATION)
WmipGetTraceBuffer( Logger,
pThreadInfo,
GroupType,
Size );
if (ThreadInfo) {
ThreadInfo->ProcessId =
HandleToUlong(pThreadInfo->ClientId.UniqueProcess);
ThreadInfo->ThreadId =
HandleToUlong(pThreadInfo->ClientId.UniqueThread);
if (bExtended) {
PSYSTEM_EXTENDED_THREAD_INFORMATION pExtThreadInfo;
pExtThreadInfo = (PSYSTEM_EXTENDED_THREAD_INFORMATION) pThreadInfo;
ThreadInfo->StackBase = pExtThreadInfo->StackBase;
ThreadInfo->StackLimit = pExtThreadInfo->StackLimit;
ThreadInfo->StartAddr = pExtThreadInfo->ThreadInfo.StartAddress;
ThreadInfo->Win32StartAddr = pExtThreadInfo->Win32StartAddress;
ThreadInfo->UserStackBase = NULL;
ThreadInfo->UserStackLimit = NULL;
ThreadInfo->WaitMode = -1;
}
else {
ThreadInfo->StackBase = NULL;
ThreadInfo->StackLimit = NULL;
ThreadInfo->StartAddr = NULL;
ThreadInfo->Win32StartAddr = NULL;
ThreadInfo->UserStackBase = NULL;
ThreadInfo->UserStackLimit = NULL;
ThreadInfo->WaitMode = -1;
}
}
pThreadInfo = (PSYSTEM_THREAD_INFORMATION)( (char*)pThreadInfo + SystemThreadInfoSize );
}
return STATUS_SUCCESS;
}
void
WmipLogImageLoadEvent(
IN HANDLE ProcessID,
IN PWMI_LOGGER_CONTEXT pLogger,
IN PRTL_PROCESS_MODULE_INFORMATION pModuleInfo,
IN PSYSTEM_THREAD_INFORMATION pThreadInfo
)
{
UNICODE_STRING wstrModuleName;
ANSI_STRING astrModuleName;
ULONG sizeModuleName;
ULONG sizeBuffer;
PCHAR pAuxInfo;
PWMI_IMAGELOAD_INFORMATION ImageLoadInfo;
if ((pLogger == NULL) || (pModuleInfo == NULL) || (pThreadInfo == NULL))
return;
RtlInitAnsiString( & astrModuleName, pModuleInfo->FullPathName);
sizeModuleName = sizeof(WCHAR) * (astrModuleName.Length);
sizeBuffer = sizeModuleName + sizeof(WCHAR)
+ FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION, FileName);
ImageLoadInfo = (PWMI_IMAGELOAD_INFORMATION)
WmipGetTraceBuffer(
pLogger,
pThreadInfo,
EVENT_TRACE_GROUP_PROCESS + EVENT_TRACE_TYPE_LOAD,
sizeBuffer);
if (ImageLoadInfo == NULL) {
return;
}
ImageLoadInfo->ImageBase = pModuleInfo->ImageBase;
ImageLoadInfo->ImageSize = pModuleInfo->ImageSize;
ImageLoadInfo->ProcessId = HandleToUlong(ProcessID);
wstrModuleName.Buffer = (LPWSTR) &ImageLoadInfo->FileName[0];
wstrModuleName.MaximumLength = (USHORT) sizeModuleName + sizeof(WCHAR);
RtlAnsiStringToUnicodeString(& wstrModuleName, & astrModuleName, FALSE);
}
ULONG
WmipSysModuleRunDown(
IN PWMI_LOGGER_CONTEXT pLogger,
IN PSYSTEM_THREAD_INFORMATION pThreadInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
char * pLargeBuffer1;
ULONG ReturnLength;
ULONG CurrentBufferSize;
ULONG i;
PRTL_PROCESS_MODULES pModules;
PRTL_PROCESS_MODULE_INFORMATION pModuleInfo;
pLargeBuffer1 = WmipMemReserve(MAX_BUFFER_SIZE);
if (pLargeBuffer1 == NULL)
{
status = STATUS_NO_MEMORY;
goto Cleanup;
}
if (WmipMemCommit(pLargeBuffer1, BUFFER_SIZE) == NULL)
{
status = STATUS_NO_MEMORY;
goto Cleanup;
}
CurrentBufferSize = BUFFER_SIZE;
retry:
status = NtQuerySystemInformation(
SystemModuleInformation,
pLargeBuffer1,
CurrentBufferSize,
&ReturnLength);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
// Increase buffer size.
//
CurrentBufferSize += 8192;
if (WmipMemCommit(pLargeBuffer1, CurrentBufferSize) == NULL)
{
status = STATUS_NO_MEMORY;
goto Cleanup;
}
goto retry;
}
if (!NT_SUCCESS(status))
{
goto Cleanup;
}
pModules = (PRTL_PROCESS_MODULES) pLargeBuffer1;
for (i = 0, pModuleInfo = & (pModules->Modules[0]);
i < pModules->NumberOfModules;
i ++, pModuleInfo ++)
{
WmipLogImageLoadEvent(NULL, pLogger, pModuleInfo, pThreadInfo);
}
Cleanup:
if (pLargeBuffer1)
{
WmipMemFree(pLargeBuffer1);
}
return WmipSetNtStatus(status);
}
ULONG
WmipProcessModuleRunDown(
IN PWMI_LOGGER_CONTEXT pLogger,
IN HANDLE ProcessID,
IN PSYSTEM_THREAD_INFORMATION pThreadInfo)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG i;
PRTL_DEBUG_INFORMATION pLargeBuffer1 = NULL;
pLargeBuffer1 = RtlCreateQueryDebugBuffer(0, FALSE);
if (pLargeBuffer1 == NULL)
{
status = STATUS_NO_MEMORY;
goto Cleanup;
}
status = RtlQueryProcessDebugInformation(
ProcessID,
RTL_QUERY_PROCESS_MODULES,
pLargeBuffer1);
if ( !NT_SUCCESS(status) || (pLargeBuffer1->Modules == NULL) )
{
goto Cleanup;
}
for (i = 0; i < pLargeBuffer1->Modules->NumberOfModules; i ++)
{
WmipLogImageLoadEvent(
ProcessID,
pLogger,
& (pLargeBuffer1->Modules->Modules[i]),
pThreadInfo);
}
Cleanup:
if (pLargeBuffer1)
{
RtlDestroyQueryDebugBuffer(pLargeBuffer1);
}
return WmipSetNtStatus(status);
}
NTSTATUS
WmipProcessRunDown(
IN PWMI_LOGGER_CONTEXT Logger,
IN ULONG StartFlag,
IN ULONG fEnableFlags
)
{
PSYSTEM_PROCESS_INFORMATION pProcessInfo;
PSYSTEM_THREAD_INFORMATION pThreadInfo;
char* LargeBuffer1;
NTSTATUS status;
ULONG ReturnLength;
ULONG CurrentBufferSize;
ULONG GroupType;
ULONG TotalOffset = 0;
OBJECT_ATTRIBUTES objectAttributes;
BOOLEAN WasEnabled = TRUE;
BOOLEAN bExtended = TRUE;
LargeBuffer1 = WmipMemReserve ( MAX_BUFFER_SIZE );
if (LargeBuffer1 == NULL) {
return STATUS_NO_MEMORY;
}
if (WmipMemCommit (LargeBuffer1, BUFFER_SIZE) == NULL) {
return STATUS_NO_MEMORY;
}
CurrentBufferSize = BUFFER_SIZE;
retry:
if (bExtended) {
status = NtQuerySystemInformation(
SystemExtendedProcessInformation,
LargeBuffer1,
CurrentBufferSize,
&ReturnLength
);
}
else {
status = NtQuerySystemInformation(
SystemProcessInformation,
LargeBuffer1,
CurrentBufferSize,
&ReturnLength
);
}
if (status == STATUS_INFO_LENGTH_MISMATCH) {
//
// Increase buffer size.
//
CurrentBufferSize += 8192;
if (WmipMemCommit (LargeBuffer1, CurrentBufferSize) == NULL) {
return STATUS_NO_MEMORY;
}
goto retry;
}
if (!NT_SUCCESS(status)) {
if (bExtended) {
bExtended = FALSE;
goto retry;
}
WmipMemFree(LargeBuffer1);
return(status);
}
//
// Adjust Privileges to obtain the module information
//
if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
TRUE, FALSE, &WasEnabled);
if (!NT_SUCCESS(status)) {
WmipMemFree(LargeBuffer1);
return (status);
}
}
TotalOffset = 0;
pProcessInfo = (SYSTEM_PROCESS_INFORMATION *) LargeBuffer1;
while (TRUE) {
ULONG Size;
ULONG Length = 0;
ULONG SidLength = 0;
PUCHAR AuxPtr;
PULONG_PTR AuxInfo;
ANSI_STRING s;
HANDLE Token;
HANDLE pProcess;
PCLIENT_ID Cid;
ULONG TempInfo[128];
PWMI_PROCESS_INFORMATION WmiProcessInfo;
Size = FIELD_OFFSET(WMI_PROCESS_INFORMATION, Sid);
GroupType = EVENT_TRACE_GROUP_PROCESS +
((StartFlag) ? EVENT_TRACE_TYPE_DC_START
: EVENT_TRACE_TYPE_DC_END);
pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
if (pProcessInfo->NumberOfThreads > 0) {
Cid = (PCLIENT_ID) &pThreadInfo->ClientId;
}
else {
Cid = NULL;
}
// if at termination, rundown thread first before process
if ( (!StartFlag) &&
(fEnableFlags & EVENT_TRACE_FLAG_THREAD) ){
status = WmipThreadRunDown(Logger,
pProcessInfo,
StartFlag,
bExtended);
if (!NT_SUCCESS(status)) {
break;
}
}
if (fEnableFlags & EVENT_TRACE_FLAG_PROCESS) {
if ( pProcessInfo->ImageName.Buffer &&
pProcessInfo->ImageName.Length > 0 ) {
RtlUnicodeStringToAnsiString(
&s,
(PUNICODE_STRING)&pProcessInfo->ImageName,
TRUE);
Length = s.Length + 1;
}
else {
Length = 1;
}
InitializeObjectAttributes(
&objectAttributes, 0, 0, NULL, NULL);
status = NtOpenProcess(
&pProcess,
PROCESS_QUERY_INFORMATION,
&objectAttributes,
Cid);
if (NT_SUCCESS(status)) {
status = NtOpenProcessToken(
pProcess,
TOKEN_READ,
&Token);
if (NT_SUCCESS(status)) {
status = NtQueryInformationToken(
Token,
TokenUser,
TempInfo,
256,
&SidLength);
NtClose(Token);
}
NtClose(pProcess);
}
if ( (!NT_SUCCESS(status)) || SidLength <= 0) {
TempInfo[0] = 0;
SidLength = sizeof(ULONG);
}
Size += Length + SidLength;
WmiProcessInfo = (PWMI_PROCESS_INFORMATION)
WmipGetTraceBuffer( Logger,
pThreadInfo,
GroupType,
Size);
if (WmiProcessInfo == NULL) {
status = STATUS_NO_MEMORY;
break;
}
WmiProcessInfo->ProcessId = HandleToUlong(pProcessInfo->UniqueProcessId);
WmiProcessInfo->ParentId = HandleToUlong(pProcessInfo->InheritedFromUniqueProcessId);
WmiProcessInfo->SessionId = pProcessInfo->SessionId;
WmiProcessInfo->PageDirectoryBase = pProcessInfo->PageDirectoryBase;
WmiProcessInfo->ExitStatus = 0;
AuxPtr = (PUCHAR) (&WmiProcessInfo->Sid);
RtlCopyMemory(AuxPtr, &TempInfo, SidLength);
AuxPtr += SidLength;
if ( Length > 1) {
RtlCopyMemory(AuxPtr, s.Buffer, Length);
AuxPtr += Length;
RtlFreeAnsiString(&s);
}
*AuxPtr = '\0';
AuxPtr++;
}
// if at beginning, trace threads after process
if (StartFlag) {
if (fEnableFlags & EVENT_TRACE_FLAG_THREAD) {
WmipThreadRunDown(Logger, pProcessInfo, StartFlag, bExtended);
}
if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
if (pProcessInfo->UniqueProcessId == 0) {
WmipSysModuleRunDown(Logger, pThreadInfo);
}
else
WmipProcessModuleRunDown(
Logger,
(HANDLE) pProcessInfo->UniqueProcessId,
pThreadInfo);
}
}
if (pProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += pProcessInfo->NextEntryOffset;
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
}
//
// Restore privileges back to what it was before
//
if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
WasEnabled,
FALSE,
&WasEnabled);
}
WmipMemFree(LargeBuffer1);
return status;
}
VOID
WmipInitString(
IN PVOID Destination,
IN PVOID Buffer,
IN ULONG Size
)
{
PSTRING s = (PSTRING) Destination;
s->Buffer = Buffer;
s->Length = 0;
if (Buffer != NULL)
s->MaximumLength = (USHORT) Size;
else
s->MaximumLength = 0;
}
VOID
WmipGenericTraceEnable(
IN ULONG RequestCode,
IN PVOID Buffer,
IN OUT PVOID *RequestAddress
)
{
PGUIDMAPENTRY pControlGMEntry = *RequestAddress;
PWNODE_HEADER Wnode = (PWNODE_HEADER) Buffer;
PTRACE_REG_INFO pTraceRegInfo;
PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT)&Wnode->HistoricalContext;
*RequestAddress = NULL;
if (Wnode == NULL || pControlGMEntry == NULL)
return;
if (!Wnode->Flags & WNODE_FLAG_TRACED_GUID)
return;
pTraceRegInfo = pControlGMEntry->pControlGuidData;
WmipAssert(pTraceRegInfo != NULL);
if (pTraceRegInfo->InProgressEvent != NULL) {
LARGE_INTEGER Timeout = {(ULONG)(-NOTIFY_RETRY_COUNT * 1000 * 10), -1};
// TODO: Raghu - what if it times out??
NtWaitForSingleObject(pTraceRegInfo->InProgressEvent, 0, &Timeout);
}
*RequestAddress = pTraceRegInfo->NotifyRoutine;
if (RequestCode == WMI_ENABLE_EVENTS) {
pControlGMEntry->LoggerContext = Wnode->HistoricalContext;
if (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
pTraceRegInfo->EnabledState = TRUE;
if (!WmipIsPrivateLoggerOn())
*RequestAddress = NULL; // Do not notify if the logger is not up.
}
}
else if (RequestCode == WMI_DISABLE_EVENTS) {
if (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
pTraceRegInfo->EnabledState = FALSE;
}
pControlGMEntry->LoggerContext = 0;
}
}
ULONG
WmipAddLogHeaderToLogFile(
IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
IN PWMI_REF_CLOCK RefClock,
IN ULONG Update
)
{
NTSTATUS Status;
HANDLE LogFile = INVALID_HANDLE_VALUE;
ULONG BufferSize;
ULONG MemorySize;
ULONG TraceKernel;
SYSTEM_BASIC_INFORMATION SystemInfo;
WMI_LOGGER_CONTEXT Logger;
IO_STATUS_BLOCK IoStatus;
PWMI_BUFFER_HEADER Buffer;
FILE_POSITION_INFORMATION FileInfo;
LPWSTR FileName = NULL;
LPWSTR FileNameBuffer = NULL;
ULONG HeaderSize;
struct WMI_LOGFILE_HEADER {
WMI_BUFFER_HEADER BufferHeader;
SYSTEM_TRACE_HEADER SystemHeader;
TRACE_LOGFILE_HEADER LogFileHeader;
};
struct WMI_LOGFILE_HEADER LoggerBuffer;
BOOLEAN bLogFileAppend =
(LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND)
? (TRUE) : (FALSE);
if (LoggerInfo == NULL)
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) &&
(LoggerInfo->LogFileName.Length > 0)) {
FileName = (LPWSTR) WmipAlloc(LoggerInfo->LogFileName.Length + 64);
if (FileName == NULL) {
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
swprintf(FileName, LoggerInfo->LogFileName.Buffer, 1);
FileNameBuffer = FileName;
}
if (FileName == NULL)
FileName = (LPWSTR) LoggerInfo->LogFileName.Buffer;
//
// If it is Append Mode, we need to open the file and make sure the
// pick up the BufferSize
//
if ( bLogFileAppend ) {
ULONG ReadSize = sizeof(WMI_BUFFER_HEADER)
+ sizeof(SYSTEM_TRACE_HEADER)
+ sizeof(TRACE_LOGFILE_HEADER);
ULONG nBytesRead = 0;
//
// Update and Append do not mix. To Append LoggerInfo
// must have LogFileName
//
if ( (Update) || (LoggerInfo->LogFileName.Length <= 0) ) {
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
LogFile = WmipCreateFileW(FileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (LogFile == INVALID_HANDLE_VALUE) {
// cannot OPEN_EXISTING, assume that logfile is not there and
// create a new one.
//
bLogFileAppend = FALSE;
LoggerInfo->LogFileMode = LoggerInfo->LogFileMode
& (~ (EVENT_TRACE_FILE_MODE_APPEND));
}
else {
// read TRACE_LOGFILE_HEADER structure and update LoggerInfo
// members.
//
Status = WmipReadFile(LogFile,
(LPVOID) & LoggerBuffer,
ReadSize,
& nBytesRead,
NULL);
if (nBytesRead < ReadSize) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_BAD_PATHNAME);
}
if ( LoggerBuffer.LogFileHeader.LogFileMode
& EVENT_TRACE_FILE_MODE_CIRCULAR) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_BAD_PATHNAME);
}
LoggerInfo->BufferSize =
LoggerBuffer.LogFileHeader.BufferSize / 1024;
LoggerInfo->BuffersWritten =
LoggerBuffer.LogFileHeader.BuffersWritten;
LoggerInfo->MaximumFileSize =
LoggerBuffer.LogFileHeader.MaximumFileSize;
// Write back logfile append mode so WmipFinalizeLogFile() correctly
// update BuffersWritten field
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(EndTime);
Status = NtSetInformationFile(LogFile,
& IoStatus,
& FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation);
if (!NT_SUCCESS(Status)) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetNtStatus(Status);
}
LoggerBuffer.LogFileHeader.EndTime.QuadPart = 0;
Status = NtWriteFile(LogFile,
NULL,
NULL,
NULL,
& IoStatus,
& LoggerBuffer.LogFileHeader.EndTime,
sizeof(LARGE_INTEGER),
NULL,
NULL);
if (! NT_SUCCESS(Status)) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetNtStatus(Status);
}
// build checksum structure
//
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
LoggerInfo->Checksum = NULL;
}
else {
LoggerInfo->Checksum = WmipAlloc(
sizeof(WNODE_HEADER) + sizeof(TRACE_LOGFILE_HEADER));
if (LoggerInfo->Checksum != NULL) {
PBYTE ptrChecksum = LoggerInfo->Checksum;
RtlCopyMemory(ptrChecksum,
& LoggerBuffer.BufferHeader,
sizeof(WNODE_HEADER));
ptrChecksum += sizeof(WNODE_HEADER);
RtlCopyMemory(ptrChecksum,
& LoggerBuffer.LogFileHeader,
sizeof(TRACE_LOGFILE_HEADER));
}
else {
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
}
// get the system parameters first
LoggerInfo->LogFileHandle = NULL;
Status = NtQuerySystemInformation(
SystemBasicInformation,
&SystemInfo, sizeof (SystemInfo), NULL);
if (!NT_SUCCESS(Status)) {
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetNtStatus(Status);
}
// choose some logical default value for buffer size if user
// has not provided one
MemorySize = SystemInfo.NumberOfPhysicalPages * SystemInfo.PageSize
/ 1024 / 1024;
if (MemorySize <= 32)
BufferSize = SystemInfo.PageSize;
else if (MemorySize <= 64)
BufferSize = SystemInfo.PageSize;
else if (MemorySize <= 128)
BufferSize = SystemInfo.PageSize * 2;
else if (MemorySize <= 256)
BufferSize = SystemInfo.PageSize * 2;
else if (MemorySize > 512)
BufferSize = SystemInfo.PageSize * 2;
else if (MemorySize <= 256)
BufferSize = SystemInfo.PageSize * 2;
else if (MemorySize > 512)
BufferSize = 64 * 1024; // allocation size
else // > 256 && < 512
BufferSize = SystemInfo.PageSize * 2;
if (LoggerInfo->BufferSize > 1024) // limit to 1Mb
BufferSize = 1024 * 1024;
else if (LoggerInfo->BufferSize > 0)
BufferSize = LoggerInfo->BufferSize * 1024;
TraceKernel = IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid);
if (!TraceKernel) {
GUID guid;
RtlZeroMemory(&guid, sizeof(GUID));
if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &guid)) {
// Generate a Guid for this logger stream
// This will ensure buffer filtering at the WMI service
// based on this GUID.
UUID uid;
WmipUuidCreate(&uid);
LoggerInfo->Wnode.Guid = uid;
}
}
if (!Update) {
// don't want to update BufferSize information if the request is
// to update logger session
//
LoggerInfo->BufferSize = BufferSize / 1024;
}
if (LoggerInfo->LogFileName.Length <= 0)
return ERROR_SUCCESS; //goto SendToKm;
//
// We assumed the exposed API has checked for either RealTime or FileName
// is provided
//
// open the file for writing synchronously for the logger
// others may want to read it as well.
// For logfile append mode, logfile has been opened previously
//
if (! bLogFileAppend) {
/* LogFile = WmipCreateFileW(
(PWCHAR) LoggerInfo->LogFileName.Buffer,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
); */
LogFile = WmipCreateFile(
FileName,
FILE_GENERIC_WRITE,
FILE_SHARE_READ,
FILE_OVERWRITE_IF,
0);
if (LogFile == INVALID_HANDLE_VALUE) {
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_BAD_PATHNAME);
}
}
LoggerInfo->LogFileHandle = LogFile;
//
// If this is an Update call, then we need to pick up the original
// buffer size for the LogFileHeader.
//
if (Update) {
PWMI_LOGGER_INFORMATION pTempLoggerInfo;
PWCHAR strLoggerName = NULL;
PWCHAR strLogFileName = NULL;
ULONG ErrCode;
ULONG SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + MAXSTR * sizeof(WCHAR) * 2;
SizeNeeded = (SizeNeeded +7) & ~7;
pTempLoggerInfo = WmipAlloc(SizeNeeded);
if (pTempLoggerInfo == NULL) {
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
RtlZeroMemory(pTempLoggerInfo, SizeNeeded);
pTempLoggerInfo->Wnode.BufferSize = SizeNeeded;
pTempLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
pTempLoggerInfo->Wnode.HistoricalContext = LoggerInfo->Wnode.HistoricalContext;
pTempLoggerInfo->Wnode.Guid = LoggerInfo->Wnode.Guid;
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
pTempLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE;
}
strLoggerName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION));
WmipInitString(&pTempLoggerInfo->LoggerName,
strLoggerName,
MAXSTR * sizeof(WCHAR));
if (LoggerInfo->LoggerName.Length > 0) {
RtlCopyUnicodeString( &pTempLoggerInfo->LoggerName,
&LoggerInfo->LoggerName);
}
strLogFileName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION)
+ MAXSTR * sizeof(WCHAR) );
WmipInitString(&pTempLoggerInfo->LogFileName,
strLogFileName,
MAXSTR * sizeof(WCHAR) );
//
// Call QueryLogger
//
ErrCode = WmipQueryLogger(pTempLoggerInfo, FALSE);
BufferSize = pTempLoggerInfo->BufferSize * 1024;
WmipFree(pTempLoggerInfo);
if (ErrCode != ERROR_SUCCESS) {
return ErrCode;
}
}
//
// Before Allocating the Buffer for Logfile Header make
// sure the buffer size is atleast as large as the LogFileHeader
//
HeaderSize = sizeof(LoggerBuffer)
+ LoggerInfo->LoggerName.Length + sizeof(WCHAR)
+ LoggerInfo->LogFileName.Length + sizeof(WCHAR);
if (HeaderSize > BufferSize) {
//
// Round it to the nearest power of 2 and check for max size 1 MB
//
double dTemp = log (HeaderSize / 1024.0) / log (2.0);
ULONG lTemp = (ULONG) (dTemp + 0.99);
HeaderSize = (1 << lTemp);
if (HeaderSize > 1024) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
LoggerInfo->BufferSize = HeaderSize;
BufferSize = HeaderSize * 1024;
}
// allocate a buffer to write logger header and process/thread
// rundown information
//
Logger.LogFileHandle = LogFile;
Logger.BufferSize = BufferSize;
Logger.TimerResolution = SystemInfo.TimerResolution;
Logger.BufferSpace = WmipAlloc(BufferSize);
if (Logger.BufferSpace == NULL) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME) {
LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_PERFCOUNTER;
}
Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
// initialize buffer first
RtlZeroMemory(Logger.BufferSpace, BufferSize);
Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
if (TraceKernel) {
Buffer->Wnode.Guid = SystemTraceControlGuid;
}
else {
Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
}
Buffer->Wnode.BufferSize = BufferSize;
Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
if (bLogFileAppend) {
Logger.BuffersWritten = LoggerBuffer.LogFileHeader.BuffersWritten;
WmipSetFilePointer(LogFile, 0, NULL, FILE_END);
}
else {
PTRACE_LOGFILE_HEADER LogfileHeader;
OSVERSIONINFO sVersionInfo;
Logger.BuffersWritten = 0;
HeaderSize = sizeof(TRACE_LOGFILE_HEADER)
+ LoggerInfo->LoggerName.Length + sizeof(WCHAR)
+ LoggerInfo->LogFileName.Length + sizeof(WCHAR);
LogfileHeader = (PTRACE_LOGFILE_HEADER)
WmipGetTraceBuffer(
&Logger,
NULL,
EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_INFO,
HeaderSize
);
if (LogfileHeader == NULL) {
NtClose(LogFile);
WmipFree(Logger.BufferSpace);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
if (Logger.UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
LARGE_INTEGER CurrentTime;
LARGE_INTEGER Frequency;
Status = NtQueryPerformanceCounter(&CurrentTime, &Frequency);
LogfileHeader->PerfFreq = Frequency;
LogfileHeader->ReservedFlags = EVENT_TRACE_CLOCK_PERFCOUNTER;
}
//
// Start and End Times are wall clock time
//
if (RefClock != NULL) {
PSYSTEM_TRACE_HEADER Header;
LogfileHeader->StartTime = RefClock->StartTime;
Header = (PSYSTEM_TRACE_HEADER) ( (char *) LogfileHeader - sizeof(SYSTEM_TRACE_HEADER) );
Header->SystemTime = RefClock->StartPerfClock;
}
else {
LogfileHeader->StartTime.QuadPart = WmipGetSystemTime();
}
RtlZeroMemory(&sVersionInfo, sizeof(OSVERSIONINFO));
sVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
WmipGetVersionExA(&sVersionInfo);
LogfileHeader->BufferSize = BufferSize;
LogfileHeader->VersionDetail.MajorVersion =
(UCHAR)sVersionInfo.dwMajorVersion;
LogfileHeader->VersionDetail.MinorVersion =
(UCHAR)sVersionInfo.dwMinorVersion;
LogfileHeader->VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
LogfileHeader->VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
LogfileHeader->ProviderVersion = sVersionInfo.dwBuildNumber;
LogfileHeader->StartBuffers = 1;
LogfileHeader->LogFileMode
= LoggerInfo->LogFileMode & (~(EVENT_TRACE_REAL_TIME_MODE));
LogfileHeader->NumberOfProcessors = SystemInfo.NumberOfProcessors;
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
{
if ( (LoggerInfo->NumberOfProcessors > 0) &&
(LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) ) {
LogfileHeader->NumberOfProcessors = LoggerInfo->NumberOfProcessors;
}
else {
LoggerInfo->NumberOfProcessors = SystemInfo.NumberOfProcessors;
}
}
LogfileHeader->MaximumFileSize = LoggerInfo->MaximumFileSize;
LogfileHeader->TimerResolution = SystemInfo.TimerResolution;
LogfileHeader->LoggerName = (PWCHAR) ( (PUCHAR) LogfileHeader
+ sizeof(TRACE_LOGFILE_HEADER) );
LogfileHeader->LogFileName = (PWCHAR) ((PUCHAR)LogfileHeader->LoggerName
+ LoggerInfo->LoggerName.Length
+ sizeof (WCHAR));
RtlCopyMemory(LogfileHeader->LoggerName,
LoggerInfo->LoggerName.Buffer,
LoggerInfo->LoggerName.Length + sizeof(WCHAR));
RtlCopyMemory(LogfileHeader->LogFileName,
LoggerInfo->LogFileName.Buffer,
LoggerInfo->LogFileName.Length + sizeof(WCHAR));
WmipGetTimeZoneInformation(&LogfileHeader->TimeZone);
LogfileHeader->PointerSize = sizeof(PVOID);
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
LoggerInfo->Checksum = NULL;
}
else {
LoggerInfo->Checksum = WmipAlloc(
sizeof(WNODE_HEADER)
+ sizeof(TRACE_LOGFILE_HEADER));
if (LoggerInfo->Checksum != NULL) {
PBYTE ptrChecksum = LoggerInfo->Checksum;
RtlCopyMemory(ptrChecksum, Buffer, sizeof(WNODE_HEADER));
ptrChecksum += sizeof(WNODE_HEADER);
RtlCopyMemory(
ptrChecksum, LogfileHeader, sizeof(TRACE_LOGFILE_HEADER));
}
else {
NtClose(LogFile);
WmipFree(Logger.BufferSpace);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
// Dump the GuidMaps to File at the Start
//
if (!Update) {
if (TraceKernel) {
ULONG EnableFlags = LoggerInfo->EnableFlags;
if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
&LoggerInfo->EnableFlags;
EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
}
WmipDumpHardwareConfig(&Logger);
WmipProcessRunDown( &Logger, TRUE, EnableFlags );
}
else {
WmipDumpGuidMaps(&Logger, NULL, FALSE);
}
}
Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
// flush the last buffer
if (Buffer->Offset < Logger.BufferSize) {
RtlFillMemory(
(char *) Buffer + Buffer->Offset,
Logger.BufferSize - Buffer->Offset,
0xFF);
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
Logger.BufferSpace,
BufferSize,
NULL,
NULL);
Logger.BuffersWritten++;
if ((LoggerInfo->LogFileMode == EVENT_TRACE_FILE_MODE_CIRCULAR) ) {
//
// We need to write the number of StartBuffers in the
// Circular Logfile header to process it properly.
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(StartBuffers);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
NtClose(LogFile);
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
return WmipSetNtStatus(Status);
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&Logger.BuffersWritten,
sizeof(ULONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
PTRACE_LOGFILE_HEADER pLogFileHeader;
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
// update StartBuffers in Checksum
//
pLogFileHeader = (PTRACE_LOGFILE_HEADER)
(((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
pLogFileHeader->StartBuffers = Logger.BuffersWritten;
}
}
//
// As a last thing update the Number of BuffersWritten so far
// in the header and also update the checksum. This is to prevent
// Logger failing Update calls under high load.
//
FileInfo.CurrentByteOffset.QuadPart =
LOGFILE_FIELD_OFFSET(BuffersWritten);
Status = NtSetInformationFile(
LogFile,
&IoStatus,
&FileInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
);
if (!NT_SUCCESS(Status)) {
NtClose(LogFile);
return WmipSetNtStatus(Status);
}
Status = NtWriteFile(
LogFile,
NULL,
NULL,
NULL,
&IoStatus,
&Logger.BuffersWritten,
sizeof(ULONG),
NULL,
NULL
);
if (NT_SUCCESS(Status)) {
PTRACE_LOGFILE_HEADER pLogFileHeader;
NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
// update StartBuffers in Checksum
//
if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) ) {
pLogFileHeader = (PTRACE_LOGFILE_HEADER)
(((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
pLogFileHeader->BuffersWritten = Logger.BuffersWritten;
}
}
NtClose(LogFile);
LogFile = WmipCreateFileW(
FileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL
);
/* LogFile = WmipCreateFile(
FileName,
FILE_GENERIC_WRITE,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NO_INTERMEDIATE_BUFFERING);
*/
if (FileNameBuffer != NULL) {
WmipFree(FileNameBuffer);
}
if (LogFile == INVALID_HANDLE_VALUE) {
return WmipGetLastError();
}
LoggerInfo->LogFileHandle = LogFile;
LoggerInfo->BuffersWritten = Logger.BuffersWritten;
WmipFree(Logger.BufferSpace);
return ERROR_SUCCESS;
}
ULONG
WmipDumpGuidMaps(
IN PWMI_LOGGER_CONTEXT Logger,
IN PLIST_ENTRY GuidMapListHeadPtr,
IN ULONG RealTimeFlag
)
/*++
Routine Description:
This routine communicates with the WMI Service and obtains all the
Trace Guids that are currently registered and those guids that unregistered
in the middle of a Logging session.
The GuidMaps are dumped to the logfile or added to the current GuidMapList
for real time processing.
Arguments:
Logger Logger Context.
RealTimeFlag Flag to denote real time processing.
Return Value:
Returns the number of Trace GUIDS obtained from the WMI service.
--*/
{
#if 0
ULONG Status;
PTRACEGUIDMAP GuidMapList = NULL;
ULONG MaxGuidCount;
ULONG TotalGuidCount;
ULONG ReturnGuidCount;
ULONG BusyRetries;
// Ensure that wmi service is around and willing to send us notifications
Status = WmipEnableNotifications();
if (Status != ERROR_SUCCESS)
{
WmipSetLastError(Status);
return(0);
}
MaxGuidCount = 10;
retry:
TotalGuidCount = 0;
ReturnGuidCount = 0;
GuidMapList = WmipAlloc(MaxGuidCount * sizeof(TRACEGUIDMAP));
if (GuidMapList == NULL)
{
WmipSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return (0);
}
RtlZeroMemory(GuidMapList, MaxGuidCount * sizeof(TRACEGUIDMAP));
BusyRetries = 0;
do
{
try
{
#if 0
Status = EnumerateTraceGuidMap(WmipDcCtxHandle,
MaxGuidCount,
&TotalGuidCount,
&ReturnGuidCount,
GuidMapList);
#endif
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
if (Status == STATUS_ACCESS_VIOLATION)
{
Status = ERROR_NOACCESS;
WmipFree(GuidMapList);
WmipSetLastError(Status);
return (0);
}
}
if (Status == RPC_S_SERVER_TOO_BUSY)
{
WmipDebugPrint(("WMI: EnumerateTraceGuidMap too busy for the %d time\n",
BusyRetries));
WmipSleep(RPC_BUSY_WAIT_TIMER);
BusyRetries++;
}
} while ((Status == RPC_S_SERVER_TOO_BUSY) &&
(BusyRetries < RPC_BUSY_WAIT_RETRIES));
//
// If RPC was successful, then write out these events to logfile.
//
if (Status == ERROR_MORE_DATA) {
MaxGuidCount = TotalGuidCount;
WmipFree(GuidMapList);
goto retry;
}
else if (Status == ERROR_SUCCESS) {
ULONG GroupType;
ULONG i;
ULONG Size;
PULONG AuxInfo;
PTRACEGUIDMAP pTraceGuidMap = GuidMapList;
GroupType = EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_GUIDMAP;
Size = sizeof(TRACEGUIDMAP);
for (i=0; i < ReturnGuidCount; i++) {
if (RealTimeFlag) {
WmipAddGuidHandleToGuidMapList(GuidMapListHeadPtr, pTraceGuidMap->GuidMapHandle,
&pTraceGuidMap->Guid);
}
else {
AuxInfo = (PULONG) WmipGetTraceBuffer(
Logger,
NULL,
GroupType,
Size);
if (AuxInfo == NULL) {
WmipFree(GuidMapList);
WmipSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(0);
}
RtlCopyMemory(AuxInfo, pTraceGuidMap, sizeof(TRACEGUIDMAP));
}
pTraceGuidMap++;
}
}
WmipFree(GuidMapList);
WmipSetLastError(Status);
return(ReturnGuidCount);
#else
WmipSetLastError(ERROR_INVALID_PARAMETER);
return(0);
#endif
}
ULONG
WmiUnregisterGuids(
IN WMIHANDLE WMIHandle,
IN LPGUID Guid,
OUT ULONG64 *LoggerContext
)
/*++
Routine Description:
This routine informs WMI that a data provider is no longer available
to receive requests for the guids previously registered. WMI will
unregister any guids registered with this handle.
Arguments:
WMIHandle - Handle returned from WMIRegisterGuids that represents
the guids whose data is not longer available.
Guid - Pointer to the control Guid which is unregistering
LoggerContext - Returned value of the LoggerContext
Return Value:
Returns status code
--*/
{
ULONG Status;
ULONG ReturnSize;
WMIUNREGGUIDS UnregGuids;
UnregGuids.RequestHandle.Handle = WMIHandle;
UnregGuids.Guid = *Guid;
Status = WmipSendWmiKMRequest(NULL,
IOCTL_WMI_UNREGISTER_GUIDS,
&UnregGuids,
sizeof(WMIUNREGGUIDS),
&UnregGuids,
sizeof(WMIUNREGGUIDS),
&ReturnSize,
NULL);
WmipSetLastError(Status);
return(Status);
}
ULONG
WmipFlushLogger(
IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
)
/*++
Routine Description:
This is the actual routine to communicate with the kernel to start
the logger. All the required parameters must be in LoggerInfo.
Arguments:
LoggerInfo The actual parameters to be passed to and return from
kernel.
Return Value:
The status of performing the action requested.
--*/
{
ULONG Status;
ULONG BufferSize;
PTRACE_ENABLE_CONTEXT pContext;
if ( (LoggerInfo == NULL)
|| (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
|| (! (LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID))) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
pContext = (PTRACE_ENABLE_CONTEXT) & LoggerInfo->Wnode.HistoricalContext;
if ( (pContext->InternalFlag != 0)
&& (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
// Currently only one possible InternalFlag value. This will filter
// out some bogus LoggerHandle
//
return WmipSetDosError(ERROR_INVALID_HANDLE);
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
Status = WmipSendUmLogRequest(
WmiFlushLoggerCode,
LoggerInfo
);
}
else {
Status = WmipSendWmiKMRequest( // actually start the logger here
NULL,
IOCTL_WMI_FLUSH_LOGGER,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
LoggerInfo,
LoggerInfo->Wnode.BufferSize,
&BufferSize,
NULL
);
}
return WmipSetDosError(Status);
}
#endif