Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2435 lines
81 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000.
//
// File: wmiTrace.c
//
// Contents: windbg extension to dump WMI Trace Buffers
//
// Classes:
//
// Functions: help Standard KD Extension Function
// strdump Dump the Logger Structure
// logdump Dump the in-memory part of the TraceBuffers
// logsave Save the in-memory part of the TraceBuffers
// to a file.
// wmiLogDump Callable procedure used when caller wishes
// to replace the filter, sort, or output routines
//
// Coupling:
//
// Notes:
//
// History: 04-27-2000 glennp Created
// 07-17-2000 glennp Added support for Stephen Hsiao's
// Non-Blocking Buffers.
// 12-13-2000 glennp Changed from typedefs to struct tags
// per change in compiler behavior.
//
//----------------------------------------------------------------------------
#include "kdExts.h"
#define _WMI_SOURCE_
#include <wmium.h>
#include <ntwmi.h>
#include <evntrace.h>
#include <wmiumkm.h>
#include <traceprt.h>
#include <tchar.h>
#include "wmiTrace.h"
#pragma hdrstop
typedef ULONG64 TARGET_ADDRESS;
typedef VOID (*WMITRACING_KD_LISTENTRY_PROC)
( PVOID Context
, TARGET_ADDRESS Buffer
, ULONG Length
, ULONG CpuNo
, ULONG Align
, WMI_BUFFER_SOURCE Source
);
typedef struct _WMITRACING_BUFFER_SOURCES {
ULONG FreeBuffers:1;
ULONG FlushBuffers:1;
ULONG ActiveBuffers:1;
ULONG TransitionBuffer:1;
ULONG PrintInformation:1;
ULONG PrintProgressIndicator:1;
} WMITRACING_BUFFER_SOURCES;
struct sttSortControl
{
ULONG MaxEntries;
ULONG CurEntries;
WMITRACING_KD_SORTENTRY *pstSortEntries;
};
struct sttTraceContext
{
struct sttSortControl *pstSortControl;
PVOID UserContext;
ULONG BufferSize;
ULONG Ordinal;
WMITRACING_KD_FILTER Filter;
};
struct sttSaveContext
{
FILE *pfSaveFile;
};
extern DBGKD_GET_VERSION64 KernelVersionData;
TARGET_ADDRESS TransitionBuffer;
//Global guid filename
//LPSTR g_pszGuidFileName = "default.tmf";
CHAR g_pszGuidFileName[MAX_PATH] = "default.tmf";
//Global guid list head pointer
PLIST_ENTRY g_GuidListHeadPtr = NULL;
//Global value to determine if dynamic printing is on or off
ULONG g_ulPrintDynamicMessages = 1;
//Global handle to TracePrt.dll module
HMODULE g_hmTracePrtHandle = NULL;
//Global handle to WmiTrace.dll modlue
HMODULE g_hmWmiTraceHandle = NULL;
//Global proc address of TracePrt's FormatTraceEvent function
FARPROC g_fpFormatTraceEvent = NULL;
//Global proc address of TracePrt's SetTraceFormatParameter function
FARPROC g_fpSetTraceFormatParameter = NULL;
//Global proc address of TracePrt's GetTraceFormatParameter function
FARPROC g_fpGetTraceFormatSearchPath = NULL;
//Global proc address of TracePrt's GetTraceGuids function
FARPROC g_fpGetTraceGuids = NULL;
//Global proc address of TracePrt's CleanupTraceEventList function
FARPROC g_fpCleanupTraceEventList = NULL;
//Prototype for private function to get handle to TracePrt DLL
HMODULE getTracePrtHandle();
//Prototype for private function to get the address of a function in the TracePrt DLL
FARPROC GetAddr(LPCSTR lpProcName);
NTSTATUS
EtwpDeinitializeDll ();
NTSTATUS
EtwpInitializeDll ();
#ifdef UNICODE
#define FormatTraceEventString "FormatTraceEventW"
#define GetTraceGuidsString "GetTraceGuidsW"
#else
#define FormatTraceEventString "FormatTraceEventA"
#define GetTraceGuidsString "GetTraceGuidsA"
#endif
//+---------------------------------------------------------------------------
//
// Function: void printUnicodeFromAddress
//
// Synopsis: Prints a UNICODE string given the address of the UNICODE_STRING
//
// Arguments: ul64Address The Address of the UNICODE_STRING structure
//
// Returns: <VOID>
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
void printUnicodeFromAddress (TARGET_ADDRESS ul64Address)
{
TARGET_ADDRESS ul64TarBuffer;
ULONG bufferOffset;
ULONG lengthRead;
ULONG ulInfo;
USHORT usLength;
PWCHAR buffer;
ul64TarBuffer = 0;
bufferOffset = 0;
usLength = 0;
buffer = NULL;
GetFieldOffset ("UNICODE_STRING", "Buffer", &bufferOffset);
ReadPtr (ul64Address + bufferOffset, &ul64TarBuffer);
GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
buffer = LocalAlloc (LPTR, usLength + sizeof (UNICODE_NULL));
if (buffer == NULL) {
dprintf ("<Failed to Allocate Unicode String Buffer>");
return;
}
if (usLength > 0) {
lengthRead = 0;
ulInfo = ReadMemory (ul64TarBuffer, buffer, usLength, &lengthRead);
if ((!ulInfo) || (lengthRead != usLength)) {
dprintf ("<Failed to Read Entire Unicode String>");
}
}
buffer [usLength / 2] = 0;
dprintf ("%ws", buffer);
LocalFree(buffer);
return;
}
//+---------------------------------------------------------------------------
//
// Function: ULONG lengthUnicodeFromAddress
//
// Synopsis: Get the Length (in bytes) of a UNICODE_STRING (NULL not included)
//
// Arguments: ul64Address The Address of the UNICODE_STRING structure
//
// Returns: Length of String in Bytes
//
// History: 03-27-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG lengthUnicodeFromAddress (TARGET_ADDRESS ul64Address)
{
USHORT usLength;
usLength = 0;
GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
return ((ULONG) (usLength));
}
//+---------------------------------------------------------------------------
//
// Function: void printUnicodeFromStruct
//
// Synopsis: Prints a UNICODE string from an element in a structure
//
// Arguments: Address The Address of the structure containing the US
// Type The Type of the structure containing the US
// Field The name of the field in the structure
// This must be a UNICODE_STRING substructure
//
// Returns: <VOID>
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
void printUnicodeFromStruct (TARGET_ADDRESS Address, PCHAR Type, PCHAR Field)
{
ULONG ulUnicodeOffset;
GetFieldOffset (Type, Field, &ulUnicodeOffset);
printUnicodeFromAddress (Address + ulUnicodeOffset);
return;
}
//+---------------------------------------------------------------------------
//
// Function: ULONG GetWmiTraceAlignment
//
// Synopsis: Determines the Alignment modulus for events on the target
//
// Arguments: <NONE>
//
// Returns: The Alignment (normally 8 bytes)
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG GetWmiTraceAlignment (void)
{
ULONG ulInfo;
ULONG ulBytesRead;
UCHAR alignment;
TARGET_ADDRESS tarAddress;
alignment = 8; // Set Default
tarAddress = GetExpression ("NT!WmiTraceAlignment");
ulInfo = ReadMemory (tarAddress, &alignment, sizeof (UCHAR), &ulBytesRead);
if ((!ulInfo) || (ulBytesRead != sizeof (UCHAR))) {
dprintf ("Failed to Read Alignment.\n");
}
return ((ULONG) alignment);
}
//+---------------------------------------------------------------------------
//
// Function: TARGET_ADDRESS FindLoggerContextArray
//
// Synopsis: Determines the location and size of the LoggerContext Array
//
// Arguments: -> ElementCount The number of elements in the array put here
//
// Returns: Target Address of the LoggerContext Array
//
// History: 04-05-2000 glennp Created
//
// Notes: Returns 0 on error
//
//----------------------------------------------------------------------------
TARGET_ADDRESS FindLoggerContextArray (PULONG ElementCount)
{
TARGET_ADDRESS address;
ULONG pointerSize;
ULONG arraySize;
address = 0;
pointerSize = GetTypeSize ("PVOID");
if ((arraySize = GetTypeSize ("NT!WmipLoggerContext") / pointerSize) != 0) {
// Post Windows 2000 Version
address = GetExpression ("NT!WmipLoggerContext");
} else {
// Windows 2000 and Before
ULONG ulOffset;
address = GetExpression ("NT!WmipServiceDeviceObject");
ReadPtr (address, &address);
GetFieldOffset ("DEVICE_OBJECT", "DeviceExtension", &ulOffset);
ReadPtr (address + ulOffset, &address);
GetFieldOffset ("WMISERVDEVEXT", "LoggerContextTable", &ulOffset);
// ulOffset = 0x50;
address += ulOffset;
arraySize = GetTypeSize ("WMISERVDEVEXT.LoggerContextTable") / pointerSize;
// arraySize = 32;
}
*ElementCount = arraySize;
return (address);
}
//+---------------------------------------------------------------------------
//
// Function: TARGET_ADDRESS FindLoggerContext
//
// Synopsis: Finds the Address of a specific LoggerContext
//
// Arguments: ulLoggerId Ordinal of the specific LoggerContext
//
// Returns: Target Address of the LoggerContext
//
// History: 04-05-2000 glennp Created
//
// Notes: Returns 0 on error
//
//----------------------------------------------------------------------------
TARGET_ADDRESS FindLoggerContext (ULONG ulLoggerId)
{
TARGET_ADDRESS tarAddress;
ULONG ulMaxLoggerId;
tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
if (tarAddress == 0) {
dprintf (" Unable to Access Logger Context Array\n");
} else {
if (ulLoggerId >= ulMaxLoggerId) {
dprintf (" Logger Id TOO LARGE\n");
} else {
// tarAddress += GetTypeSize ("PWMI_LOGGER_CONTEXT") * ulLoggerId; //BUGBUG
tarAddress += GetTypeSize ("PVOID") * ulLoggerId;
ReadPointer (tarAddress, &tarAddress);
if (tarAddress == 0) {
dprintf (" LOGGER ID %2d NOT RUNNING PRESENTLY\n", ulLoggerId);
}
}
}
return (tarAddress);
}
//+---------------------------------------------------------------------------
//
// Function: wmiDefaultFilter
//
// Synopsis: Filter procedure for wmiTracing. Returns Key
//
// Arguments: Context Arbitrary context: not used
// pstEvent -> to EventTrace
//
// Returns: Key
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONGLONG __cdecl wmiDefaultFilter (
PVOID Context,
const PEVENT_TRACE pstEvent
)
{
union {
LARGE_INTEGER TimeStamp;
ULONGLONG Key;
} Union;
Union.TimeStamp = pstEvent->Header.TimeStamp;
if (Union.Key == 0) Union.Key = 1;
return (Union.Key);
}
//+---------------------------------------------------------------------------
//
// Function: wmiDefaultCompare
//
// Synopsis: Performs comparision of three keys
//
// Arguments: SortElement1 -> to "Left" sort element to compare
// SortElement2 -> to "Right" sort element to compare
//
// Returns: -3,-2,-1, 0, +1,+2,+3 for LessThan, Equal, GreaterThan (Left X Right)
//
// History: 04-05-2000 glennp Created
//
// Notes: The first key, "SequenceNo", is compared in a manor that allows
// wrapping around the 32 bit limit.
// The last key, "Ordinal", cannot have equal values and the code
// takes advantage of that fact. This implies that 0 can never be returned.
//
//----------------------------------------------------------------------------
int __cdecl wmiDefaultCompare (
const WMITRACING_KD_SORTENTRY *SortElementL,
const WMITRACING_KD_SORTENTRY *SortElementR
)
{
int iResult;
ULONG SequenceNoL;
ULONG SequenceNoR;
SequenceNoL = SortElementL->SequenceNo;
SequenceNoR = SortElementR->SequenceNo;
if (SequenceNoL == SequenceNoR) {
if (SortElementL->Keyll == SortElementR->Keyll) {
iResult = (SortElementL->Ordinal < SortElementR->Ordinal) ? -1 : +1;
} else {
iResult = (SortElementL->Keyll < SortElementR->Keyll) ? -2 : +2;
}
} else {
iResult = ((SequenceNoL - SequenceNoR) > 0x80000000) ? -3 : +3; // See Notes
}
return (iResult);
}
//+---------------------------------------------------------------------------
//
// Function: wmiDefaultOutput
//
// Synopsis: Output procedure for wmiTracing. Performs simple dprintf
//
// Arguments: Context Arbitrary context: point to head of MOF list
// SortElement -> sort element describing this event. Not used.
// pstEvent -> to EventTrace
//
// Returns: <void>
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
void __cdecl wmiDefaultOutput (
PVOID UserContext,
PLIST_ENTRY GuidListHeadPtr,
const WMITRACING_KD_SORTENTRY *SortEntry,
const PEVENT_TRACE pstHeader
)
{
WCHAR wcaOutputLine[4096];
wcaOutputLine[0] = 0;
if(g_fpFormatTraceEvent == NULL) {
g_fpFormatTraceEvent = GetAddr(FormatTraceEventString);
}
if(g_fpFormatTraceEvent != NULL) {
g_fpFormatTraceEvent (GuidListHeadPtr, (PEVENT_TRACE) pstHeader,
(TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
(TCHAR *) NULL);
} else {
return;
}
dprintf ("%s\n", wcaOutputLine);
return;
}
//+---------------------------------------------------------------------------
//
// Function: wmiKdProcessLinkList
//
// Synopsis: Calls supplied Procedure for each element in a linked list
//
// Arguments: TarLinklistHeadAddress Target Address of Linklist Head
// Procedure Procedure to call for each Buffer
// Context Procedure Context (passthrough)
// Length Size of the Buffer
// Alignment Entry alignment in bytes
// Source Enum specifying type of buffer
// Offset Offset of LL entry in Buffer
// Print Flag passed to Procedure
//
// Returns: Count of Buffers Processed
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG wmiKdProcessLinkList (
TARGET_ADDRESS TarLinklistHeadAddress,
WMITRACING_KD_LISTENTRY_PROC Procedure,
PVOID Context,
ULONG Length,
ULONG Alignment,
WMI_BUFFER_SOURCE Source,
ULONG Offset,
ULONG Print
)
{
ULONG ulBufferCount;
TARGET_ADDRESS tarLinklistEntryAddress;
ulBufferCount = 0;
tarLinklistEntryAddress = TarLinklistHeadAddress;
while (ReadPtr (tarLinklistEntryAddress, &tarLinklistEntryAddress), // NOTE COMMA!
tarLinklistEntryAddress != TarLinklistHeadAddress) {
if (CheckControlC()) break;
++ulBufferCount;
if (Print) { dprintf ("%4d\b\b\b\b", ulBufferCount); }
Procedure (Context, tarLinklistEntryAddress - Offset, Length, ~0, Alignment, Source);
}
return ulBufferCount;
}
//+---------------------------------------------------------------------------
//
// Function: VOID wmiDumpProc
//
// Synopsis: Procedure passed to wmiKdProcessBuffers() when dumping the
// Buffers to the screen. Performs Buffer Header fixup and
// then records sort keys for those entries that are selected.
//
// Arguments: Context -> to struct sttTraceContext. Used for 'static' memory
// Buffer Target Address of WMI Event buffer to analyze
// Length Length of the buffer (previous parameter)
// Alignment Alignment used by WMI on target machine
// Source Enum of: free, flush, transition, current buffer source
//
// Returns: <VOID>
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID wmiDumpProc
( PVOID Context
, TARGET_ADDRESS Buffer
, ULONG Length
, ULONG CpuNo
, ULONG Alignment
, WMI_BUFFER_SOURCE Source
)
{
ULONG size;
ULONG offset;
ULONG ulInfo;
ULONG ulLengthRead;
PUCHAR pBuffer;
WMI_HEADER_TYPE headerType;
WMIBUFFERINFO stBufferInfo;
WMITRACING_KD_SORTENTRY* pstSortEntries = NULL;
struct sttTraceContext *pstContext;
// Cast Context
pstContext = (struct sttTraceContext *) Context;
// Allocate Buffer
pBuffer = LocalAlloc (LPTR, Length);
if (pBuffer == NULL) {
dprintf ("Failed to Allocate Buffer.\n");
return;
}
// Copy Buffer from Target machine
ulLengthRead = 0;
ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
if ((!ulInfo) || (ulLengthRead != Length)) {
dprintf ("Failed to Read (Entire?) Buffer.\n");
}
// Get Initial Offset and Fixup Header
memset (&stBufferInfo, 0, sizeof (stBufferInfo));
stBufferInfo.BufferSource = Source;
stBufferInfo.Buffer = pBuffer;
stBufferInfo.BufferSize = Length;
stBufferInfo.Alignment = Alignment;
stBufferInfo.ProcessorNumber = CpuNo;
offset = WmiGetFirstTraceOffset (&stBufferInfo);
// Inspect Each Event
while ((headerType = WmiGetTraceHeader (pBuffer, offset, &size)) != WMIHT_NONE) {
ULONGLONG ullKey;
union {
EVENT_TRACE stEvent;
CHAR caEvent[4096];
} u;
if (CheckControlC()) break;
// Get a consistant header
ulInfo = WmiParseTraceEvent (pBuffer, offset, headerType, &u, sizeof (u));
// Filter and maybe Add to Sort Q
if ((ullKey = pstContext->Filter (pstContext, &u.stEvent)) != 0) {
ULONG CurIndex;
PWMI_CLIENT_CONTEXT pstClientContext;
struct sttSortControl *pstSortControl;
PWMITRACING_KD_SORTENTRY pstSortEntry;
pstClientContext = (PWMI_CLIENT_CONTEXT) &u.stEvent.Header.ClientContext;
pstSortControl = pstContext->pstSortControl;
CurIndex = pstSortControl->CurEntries;
if (CurIndex >= pstSortControl->MaxEntries) {
pstSortControl->MaxEntries = pstSortControl->MaxEntries * 2 + 64;
pstSortEntries =
realloc (pstSortControl->pstSortEntries,
sizeof (WMITRACING_KD_SORTENTRY) * (pstSortControl->MaxEntries));
if (pstSortEntries == NULL) {
dprintf ("Memory Allocation Failure\n");
goto error;
}
pstSortControl->pstSortEntries = pstSortEntries;
}
pstSortEntry = &pstSortControl->pstSortEntries[CurIndex];
memset (pstSortEntry, 0, sizeof (*pstSortEntry));
pstSortEntry->Address = Buffer;
pstSortEntry->Keyll = ullKey;
{ //BUGBUG: This code should be replaced after Ian/Melur supply a way to access SequenceNo
PULONG pulEntry;
pulEntry = (PULONG) &pBuffer[offset];
if (((pulEntry[0] & 0xFF000000) == 0x90000000) &&
( pulEntry[1] & 0x00010000)) {
pstSortEntry->SequenceNo = pulEntry[2];
} else {
pstSortEntry->SequenceNo = 0;
}
}
pstSortEntry->Ordinal = pstContext->Ordinal++;
pstSortEntry->Offset = offset;
pstSortEntry->Length = size;
pstSortEntry->BufferSource = Source;
pstSortEntry->HeaderType = headerType;
pstSortEntry->CpuNo = (USHORT) CpuNo;
pstSortControl->CurEntries++;
} // If passes Filtering
size = ((size + (Alignment-1)) / Alignment) * Alignment; //BUGBUG: Need fix in GetTraceHeader or WmiFlush. Then remove this line.
offset += size; // Move to next entry.
}
error:
LocalFree (pBuffer);
return;
}
//+---------------------------------------------------------------------------
//
// Function: ULONG wmiKdWriteFileHeader
//
// Synopsis: Write the file header when performing a Save command.
//
// Arguments: SaveFile Handle to a file where we will write the header
// LoggerId Ordinal of the Stream we are writing the header for
// TarLoggerContext TargetAddress of the LoggerContext
//
// Returns: <VOID>
//
// History: 04-05-2000 glennp Created
//
// Notes: This code should really be in wmi somewhere. It's here due to
// the difficulty of creating a simply parameterized procedure.
//
//----------------------------------------------------------------------------
ULONG
wmiKdWriteFileHeader
( FILE *SaveFile
, ULONG LoggerId
, TARGET_ADDRESS TarLoggerContext
)
{
ULONG ulInfo;
ULONG ulBytesRead;
ULONG ulAlignment;
ULONG ulBufferSize;
ULONG ulBufferCount;
ULONG ulPointerSize;
ULONG ulHeaderWritten;
ULONG ulInstanceGuidOffset;
UCHAR MajorVersion;
UCHAR MinorVersion;
PROCESSORINFO ProcessorInfo;
PCHAR pcEnd;
struct sttFileHeader {
WMI_BUFFER_HEADER Buffer;
SYSTEM_TRACE_HEADER Event;
TRACE_LOGFILE_HEADER Header;
WCHAR LogName[256]; //BUGBUG: Size??
WCHAR FileName[256]; //BUGBUG: Size??
} stFileHeader;
ZeroMemory (&stFileHeader, sizeof (stFileHeader));
ulAlignment = GetWmiTraceAlignment ();
ulPointerSize = GetTypeSize ("PVOID");
GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "InstanceGuid", &ulInstanceGuidOffset);
// Get ProcessorInfo and Kernel-User Shared Data
Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
// Get Version Info
if (!HaveDebuggerData ()) {
dprintf ("No Version Information Available.");
MajorVersion = MinorVersion = 0;
} else {
MajorVersion = (UCHAR) KernelVersionPacket.MajorVersion;
MinorVersion = (UCHAR) KernelVersionPacket.MinorVersion;
}
// Get Infomation from LoggerContext on Target
InitTypeRead (TarLoggerContext, NT!_WMI_LOGGER_CONTEXT);
ulBufferSize = (ULONG) ReadField (BufferSize);
ulBufferCount = (ULONG) ReadField (NumberOfBuffers);
stFileHeader.Buffer.Wnode.BufferSize = ulBufferSize;
stFileHeader.Buffer.ClientContext.LoggerId =
(USHORT) ((LoggerId) ? LoggerId : KERNEL_LOGGER_ID);
stFileHeader.Buffer.ClientContext.Alignment = (UCHAR) ulAlignment;
ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
&stFileHeader.Buffer.Wnode.Guid,
sizeof (stFileHeader.Buffer.Wnode.Guid),
&ulBytesRead);
if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.Wnode.Guid))) {
dprintf ("Unable to Read Wnode.Guid\n");
}
stFileHeader.Buffer.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
&stFileHeader.Buffer.InstanceGuid,
sizeof (stFileHeader.Buffer.InstanceGuid),
&ulBytesRead);
if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.InstanceGuid))) {
dprintf ("Unable to Read InstanceGuid\n");
}
// Single Event (File Header)
stFileHeader.Event.Marker = TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE |
((ulPointerSize > 4) ? (TRACE_HEADER_TYPE_SYSTEM64 << 16)
: (TRACE_HEADER_TYPE_SYSTEM32 << 16));
stFileHeader.Event.Packet.Group = (UCHAR) EVENT_TRACE_GROUP_HEADER >> 8;
stFileHeader.Event.Packet.Type = EVENT_TRACE_TYPE_INFO;
stFileHeader.Header.StartTime.QuadPart = ReadField (StartTime);
stFileHeader.Header.BufferSize = ulBufferSize;
stFileHeader.Header.VersionDetail.MajorVersion = MajorVersion;
stFileHeader.Header.VersionDetail.MinorVersion = MinorVersion;
//
// The following #if 0's show fields in the header difficult to access from the debugger.
//
#if 0
stFileHeader.Header.VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
stFileHeader.Header.VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
stFileHeader.Header.ProviderVersion = NtBuildNumber;
#endif
stFileHeader.Header.StartBuffers = 1;
#if 0
stFileHeader.Header.BootTime = KeBootTime;
stFileHeader.Header.LogFileMode = LocLoggerContext.LogFileMode &
(~(EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_FILE_MODE_CIRCULAR));
#endif
stFileHeader.Header.NumberOfProcessors = ProcessorInfo.NumberProcessors;
stFileHeader.Header.MaximumFileSize = (ULONG) ReadField (MaximumFileSize);
#if 0
KeQueryPerformanceCounter (&stFileHeader.Header.PerfFreq);
if (WmiUsePerfClock) {
stFileHeader.Header.ReservedFlags = 1;
}
stFileHeader.Header.TimerResolution = KeMaximumIncrement; // DO NOT CHANGE KDDEBUGGER_DATA32!!
#endif
#if 0
stFileHeader.Header.LoggerName = (PWCHAR) ( ( (PUCHAR) ( &stFileHeader.Header ) ) +
sizeof(TRACE_LOGFILE_HEADER) );
stFileHeader.Header.LogFileName = (PWCHAR) ( (PUCHAR)stFileHeader.Header.LoggerName +
LocLoggerContext.LoggerName.Length +
sizeof(UNICODE_NULL));
if (!ReadTargetMemory (LocLoggerContext.LoggerName.Buffer,
stFileHeader.Header.LoggerName,
LocLoggerContext.LoggerName.Length + sizeof(UNICODE_NULL)) ) {
dprintf ("Can't access LoggerName (LoggerContext.LoggerName.Buffer) memory.\n");
}
MultiByteToWideChar (
CP_OEMCP, 0,
pszSaveFileName, -1,
stFileHeader.Header.LogFileName, countof (stFileHeader.FileName));
#if 0
RtlQueryTimeZoneInformation(&stFileHeader.Header.TimeZone);
stFileHeader.Header.EndTime;
#endif
#endif
stFileHeader.Header.PointerSize = ulPointerSize;
pcEnd = (PCHAR) &stFileHeader.LogName; //BUGBUG: Use Calculation Just Below
#if 0
pcEnd = ((PCHAR) stFileHeader.Header.LogFileName) +
((strlen (pszSaveFileName) + 1) * sizeof (WCHAR));
stFileHeader.Buffer.Offset = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
#endif
stFileHeader.Event.Packet.Size = (USHORT) (pcEnd - ((PCHAR) &stFileHeader.Event));
//
// Fixup Lengths; Write out Header, 0xFF to length of buffer
//
ulHeaderWritten = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
stFileHeader.Buffer.Offset = ulHeaderWritten;
stFileHeader.Buffer.SavedOffset = ulHeaderWritten;
stFileHeader.Buffer.CurrentOffset = ulHeaderWritten;
fwrite (&stFileHeader, ulHeaderWritten, 1, SaveFile);
while (ulHeaderWritten < ulBufferSize) {
ULONG ulAllOnes;
ULONG ulByteCount;
ulAllOnes = ~((ULONG) 0);
ulByteCount = ulBufferSize - ulHeaderWritten;
if (ulByteCount > sizeof (ulAllOnes)) ulByteCount = sizeof (ulAllOnes);
fwrite (&ulAllOnes, ulByteCount, 1, SaveFile);
ulHeaderWritten += sizeof (ulAllOnes);
}
return (0);
}
//+---------------------------------------------------------------------------
//
// Function: VOID wmiSaveProc
//
// Synopsis: Procedure passed to wmiKdProcessBuffers() when saving the
// Buffers to a file for later processing. Performs buffer
// Header fixup and then writes the buffer to the file.
//
// Arguments: Context -> to struct sttSaveContext. Used for 'static' memory
// Buffer Target Address of WMI Event buffer to save
// Length Length of the buffer (previous parameter)
// Alignment Alignment used by WMI on target machine
// Source Enum of: free, flush, transition, current: buffer source
//
// Returns: <VOID>
//
// History: 04-05-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID wmiSaveProc
( PVOID Context
, TARGET_ADDRESS Buffer
, ULONG Length
, ULONG CpuNo
, ULONG Alignment
, WMI_BUFFER_SOURCE Source
)
{
ULONG ulInfo;
ULONG ulLengthRead;
PCHAR pBuffer;
struct sttSaveContext *pstContext;
WMIBUFFERINFO stBufferInfo;
pstContext = (struct sttSaveContext *) Context;
// Allocate Buffer
pBuffer = LocalAlloc (LPTR, Length);
if (pBuffer == NULL) {
dprintf ("Failed to Allocate Buffer.\n");
return;
}
// Read Buffer
ulLengthRead = 0;
ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
if ((!ulInfo) || (ulLengthRead != Length)) {
dprintf ("Failed to Read (Entire?) Buffer.\n");
}
// Fixup Buffer Header
memset (&stBufferInfo, 0, sizeof (stBufferInfo));
stBufferInfo.BufferSource = Source;
stBufferInfo.Buffer = pBuffer;
stBufferInfo.BufferSize = Length;
stBufferInfo.ProcessorNumber = CpuNo;
stBufferInfo.Alignment = Alignment;
WmiGetFirstTraceOffset (&stBufferInfo);
// Write to Log File
ulInfo = fwrite (pBuffer, 1, Length, pstContext->pfSaveFile);
if (ulInfo != Length) {
dprintf ("Failed to Write Buffer.\n");
}
// Free Buffer, Return
LocalFree (pBuffer);
return;
}
//+---------------------------------------------------------------------------
//
// Function: ULONG wmiKdProcessNonblockingBuffers
//
// Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
// Lists as specified by 'Sources'. Walks lists, Enumerates
// CPU's buffers, and handles 'Transition Buffer' logic.
//
// Arguments: LoggerId
// LoggerContext
// Procedure
// Context
// Sources
//
// Returns: ULONG: Number of Buffers Processed
//
// History: 04-05-2000 glennp Created
//
// Notes: Sources also controls informational printing
//
//----------------------------------------------------------------------------
ULONG
wmiKdProcessNonblockingBuffers(
ULONG LoggerId,
TARGET_ADDRESS LoggerContext,
WMITRACING_KD_LISTENTRY_PROC Procedure,
PVOID Context,
WMITRACING_BUFFER_SOURCES Sources
)
{
TARGET_ADDRESS tarAddress;
TARGET_ADDRESS tarBufferListPointer;
ULONG pointerSize;
PROCESSORINFO ProcessorInfo;
ULONG ulOrdinal;
ULONG ulAlignment;
ULONG ulBufferSize;
ULONG ulLoopCount;
ULONG ulBufferCount;
ULONG ulBufferNumber;
ULONG tarBufferListOffset;
// Get Pointer to Context Structure
tarAddress = LoggerContext;
if (tarAddress == 0) return (0);
// Initialize Locals
ulBufferNumber = 0;
ulBufferCount = 0;
ulLoopCount = 0;
// Get Sizes, Offsets, Alignments from Target
pointerSize = GetTypeSize ("PVOID");
ulAlignment = GetWmiTraceAlignment ();
GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "GlobalEntry", &tarBufferListOffset);
// Optionally Print LoggerId, Context Address, Logger name
if (Sources.PrintInformation) {
dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
}
// Setup ReadField's Context, Find Buffer Size
InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
ulBufferSize = (ULONG) ReadField (BufferSize);
// Optionally Print a few interesting numbers
if (Sources.PrintInformation) {
dprintf (" Alignment = %ld\n", ulAlignment);
dprintf (" BufferSize = %ld\n", ulBufferSize);
dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
}
dprintf (" Processing Global List: 0");
tarBufferListPointer = 0;
GetFieldValue (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "GlobalList.Next", tarBufferListPointer);
while (tarBufferListPointer != 0) {
WMI_BUFFER_SOURCE source;
ULONG ulCpuNumber;
int iBufferUses;
int iProcessBuffer;
TARGET_ADDRESS tarBufferPointer;
ULONG ulFree, ulInUse, ulFlush;
iBufferUses = 0;
ulCpuNumber = ~((ULONG) 0);
iProcessBuffer = FALSE;
source = WMIBS_TRANSITION_LIST;
tarBufferPointer = tarBufferListPointer - tarBufferListOffset;
dprintf ("\b\b\b%3d", ++ulLoopCount);
InitTypeRead (tarBufferPointer, NT!_WMI_BUFFER_HEADER);
ulFree = (ULONG) ReadField (State.Free);
ulInUse = (ULONG) ReadField (State.InUse);
ulFlush = (ULONG) ReadField (State.Flush);
// Decide on Buffer Processing based on Use Flags and 'Sources'
if (ulFree ) iBufferUses += 1;
if (ulInUse) iBufferUses += 2;
if (ulFlush) iBufferUses += 4;
switch (iBufferUses) {
case 0: { // No bits set, never used.
break;
}
case 1: { // Free
iProcessBuffer = Sources.FreeBuffers;
source = WMIBS_FREE_LIST;
break;
}
case 2: { // InUse
iProcessBuffer = Sources.ActiveBuffers;
source = WMIBS_CURRENT_LIST;
//source = WMIBS_FLUSH_LIST;
break;
}
case 3: { // MULTIPLE BITS SET, ERROR
dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse) Set.***\n");
break;
}
case 4: { // Flush
iProcessBuffer = Sources.FlushBuffers;
source = WMIBS_FLUSH_LIST;
break;
}
case 5: {
dprintf ("\n***Error, Inconsistent Flags Bits (Free,Flush) Set.***\n");
break;
}
case 6: {
dprintf ("\n***Error, Inconsistent Flags Bits (InUse,Flush) Set.***\n");
break;
}
case 7: {
dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse,Flush) Set.***\n");
break;
}
}
// ProcessBuffer as Decided Above
if (iProcessBuffer) {
ulBufferCount++;
Procedure (Context, tarBufferPointer, ulBufferSize, ulCpuNumber, ulAlignment, source);
}
if (GetFieldValue (tarBufferPointer,
"NT!_WMI_BUFFER_HEADER", "GlobalEntry",
tarBufferListPointer) != 0) {
dprintf ("\n***Error Following Global List.***\n");
tarBufferListPointer = 0;
}
}
dprintf (" Buffers\n");
// Return w/ BufferCount
return (ulBufferCount);
} // wmiKdProcessNonblockingBuffers
//+---------------------------------------------------------------------------
//
// Function: ULONG wmiKdProcessBlockingBuffers
//
// Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
// Lists as specified by 'Sources'. Walks lists, Enumerates
// CPU's buffers, and handles 'Transition Buffer' logic.
//
// Arguments: LoggerId
// LoggerContext
// Procedure
// Context
// Sources
//
// Returns: ULONG: Number of Buffers Processed
//
// History: 04-05-2000 glennp Created
//
// Notes: Sources also controls informational printing
//
//----------------------------------------------------------------------------
ULONG
wmiKdProcessBlockingBuffers(
ULONG LoggerId,
TARGET_ADDRESS LoggerContext,
WMITRACING_KD_LISTENTRY_PROC Procedure,
PVOID Context,
WMITRACING_BUFFER_SOURCES Sources
)
{
TARGET_ADDRESS tarAddress;
ULONG pointerSize;
PROCESSORINFO ProcessorInfo;
ULONG ulOrdinal;
ULONG ulAlignment;
ULONG ulBufferSize;
ULONG ulBufferCount;
ULONG ulBufferNumber;
ULONG ulBufferCountTotal;
ULONG tarFlushListOffset;
ULONG tarBufferListOffset;
// Get Pointer to Context Structure
tarAddress = LoggerContext;
if (tarAddress == 0) return (0);
// Initialize Locals
ulBufferNumber = 0;
ulBufferCount = 0;
ulBufferCountTotal = 0;
// Get Sizes, Offsets, Alignments from Target
pointerSize = GetTypeSize ("PVOID");
ulAlignment = GetWmiTraceAlignment ();
GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "Entry", &tarBufferListOffset);
GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "FlushList", &tarFlushListOffset);
// Optionally Print LoggerId, Context Address, Logger name
if (Sources.PrintInformation) {
dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
}
// Setup ReadField's Context, Find Buffer Size
InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
ulBufferSize = (ULONG) ReadField (BufferSize);
// Optionally Print a few interesting numbers
if (Sources.PrintInformation) {
dprintf (" Alignment = %ld\n", ulAlignment);
dprintf (" BufferSize = %ld\n", ulBufferSize);
dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
}
// Setup for Checks against TransitionBuffer Address IF REQUESTED
TransitionBuffer = 0;
if (Sources.TransitionBuffer) {
TARGET_ADDRESS tarTransitionBuffer;
tarTransitionBuffer = ReadField (TransitionBuffer);
if ((tarTransitionBuffer != 0) &&
(tarTransitionBuffer != (tarAddress + tarFlushListOffset))) {
ULONG tarTransitionBufferOffset;
GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "Entry", &tarTransitionBufferOffset);
tarTransitionBuffer = tarAddress - tarTransitionBufferOffset;
TransitionBuffer = tarTransitionBuffer;
}
}
// Access the Free Queue Buffers IF REQUESTED
if (Sources.FreeBuffers) {
ULONG tarFreeListOffset;
GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "FreeList", &tarFreeListOffset);
dprintf (" Processing FreeQueue: ");
ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFreeListOffset,
Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FREE_LIST,
tarBufferListOffset, Sources.PrintProgressIndicator);
dprintf ("%ld Buffers\n", ulBufferCount);
ulBufferCountTotal += ulBufferCount;
}
// Access the Flush Queue Buffers IF REQUESTED
if (Sources.FlushBuffers) {
dprintf (" Processing FlushQueue: ");
ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFlushListOffset,
Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FLUSH_LIST,
tarBufferListOffset, Sources.PrintProgressIndicator);
dprintf ("%ld Buffers\n", ulBufferCount);
ulBufferCountTotal += ulBufferCount;
}
// Access the 'Live' buffers (one per cpu) IF REQUESTED
if (Sources.ActiveBuffers) {
TARGET_ADDRESS tarProcessorArrayAddress;
GetFieldValue (tarAddress,"NT!_WMI_LOGGER_CONTEXT", "ProcessorBuffers", tarProcessorArrayAddress);
Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
for (ProcessorInfo.Processor = 0;
ProcessorInfo.Processor < ProcessorInfo.NumberProcessors;
++ProcessorInfo.Processor) {
TARGET_ADDRESS tarProcessorPointer;
ReadPtr (tarProcessorArrayAddress + ProcessorInfo.Processor * pointerSize,
&tarProcessorPointer);
dprintf (" Cpu %d Buffer Header @ 0x%P ",
ProcessorInfo.Processor, tarProcessorPointer);
Procedure (Context, tarProcessorPointer, ulBufferSize,
ProcessorInfo.Processor, ulAlignment, WMIBS_CURRENT_LIST);
ulBufferCountTotal += 1;
dprintf (" \b\n");
} // Cpu Loop
}
// Process the Transition Entry (if any). Note 'IF REQUESTED' test above in Setup
if (TransitionBuffer != 0) {
dprintf (" Transition Buffer @ 0x%P ", TransitionBuffer);
Procedure (Context, TransitionBuffer, ulBufferSize, ~0, ulAlignment, WMIBS_TRANSITION_LIST);
ulBufferCountTotal += 1;
}
// Return w/ BufferCount
return (ulBufferCountTotal);
} // wmiKdProcessBlockingBuffers
//+---------------------------------------------------------------------------
//
// Function: ULONG wmiKdProcessBuffers
//
// Synopsis: Decides if the target system is using doubly-linked (blocking)
// or singly-linked (non-blocking) lists of buffers. Then it
// calls the appropriate Buffer-Walking routine. They:
// Call Caller-Supplied Procedure for each Buffer in Locations/
// Lists as specified by 'Sources'. Walk lists, Enumerates
// CPU's buffers, and handles 'Transition Buffer' logic.
//
// Arguments: LoggerId
// LoggerContext
// Procedure
// Context
// Sources
//
// Returns: ULONG: Number of Buffers Processed
//
// History: 04-05-2000 glennp Created
//
// Notes: Sources also controls informational printing
//
//----------------------------------------------------------------------------
ULONG
wmiKdProcessBuffers(
ULONG LoggerId,
TARGET_ADDRESS LoggerContext,
WMITRACING_KD_LISTENTRY_PROC Procedure,
PVOID Context,
WMITRACING_BUFFER_SOURCES Sources
)
{
ULONG ulBufferCountTotal;
int iBufferMechanism;
ULONG tarGlobalListOffset;
ULONG tarTransitionBufferOffset;
iBufferMechanism = 0;
ulBufferCountTotal = 0;
if ((GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "GlobalList", &tarGlobalListOffset) == 0) &&
(tarGlobalListOffset != 0)) {
iBufferMechanism += 1;
}
if ((GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "TransitionBuffer", &tarTransitionBufferOffset) == 0) &&
(tarTransitionBufferOffset != 0)) {
iBufferMechanism += 2;
}
switch (iBufferMechanism) {
case 0: { // Neither, ???
dprintf ("Unable to determine buffer mechanism. "
"Check for complete symbol availability.\n");
break;
}
case 1: { // Global, no Transition
ulBufferCountTotal = wmiKdProcessNonblockingBuffers (LoggerId, LoggerContext,
Procedure, Context, Sources);
break;
}
case 2: { // Transition, no Global
ulBufferCountTotal = wmiKdProcessBlockingBuffers (LoggerId, LoggerContext,
Procedure, Context, Sources);
break;
}
case 3: { // Both, ???
dprintf ("Unable to determine buffer mechanism. "
"Check for new wmiTrace debugger extension. GO = %d, TB = %d\n",
tarGlobalListOffset, tarTransitionBufferOffset);
break;
}
}
// Return w/ BufferCount
return (ulBufferCountTotal);
} // wmiKdProcessBuffers
//+---------------------------------------------------------------------------
//
// Function: VOID wmiLogDump
//
// Synopsis: callable procedure to dump the in-memory part of a tracelog.
// Caller can supply three procedures to:
// 1. Filter and Select the Sort Key for VMI Events,
// 2. Compare the Sort Keys, and
// 3. Print the Output for each Selected Event.
// this procedure is called by the built-in extension logdump.
//
// Arguments: LoggerId -> the Id of the logger stream to process
// Context <OMITTED>
// GuidListHeadPtr -> to a list of MOF Guids from GetTraceGuids
// Filter -> to a replacement Filter procedure
// Compare -> to a replacement Compare (for Sort) procedure
// Output -> to a replacement Output procedure
//
// Returns: VOID
//
// History: 04-05-2000 glennp Created
//
//----------------------------------------------------------------------------
VOID wmiLogDump(
ULONG LoggerId,
PVOID UserContext,
PLIST_ENTRY GuidListHeadPtr,
WMITRACING_KD_FILTER Filter,
WMITRACING_KD_COMPARE Compare,
WMITRACING_KD_OUTPUT Output
)
{
ULONG ulOrdinal;
ULONG ulSortIndex;
ULONG ulBufferSize;
ULONG ulBufferCountTotal;
ULONG ulAlignment;
TARGET_ADDRESS tarAddress;
PCHAR locBufferAddress;
TARGET_ADDRESS lastBufferAddress;
struct sttSortControl stSortControl;
struct sttTraceContext stTraceContext;
WMITRACING_BUFFER_SOURCES stSources;
// Replace NULL procedures w/ defaults
if (Filter == NULL) Filter = wmiDefaultFilter;
if (Compare == NULL) Compare = wmiDefaultCompare;
if (Output == NULL) Output = wmiDefaultOutput;
// Initialize Locals
memset (&stSortControl, 0, sizeof (stSortControl));
memset (&stTraceContext, 0, sizeof (stTraceContext));
stTraceContext.pstSortControl = &stSortControl;
stTraceContext.UserContext = UserContext;
//stTraceContext.Ordinal = 0;
stTraceContext.Filter = Filter;
// Select (All) Sources
stSources.FreeBuffers = 1;
stSources.FlushBuffers = 1;
stSources.ActiveBuffers = 1;
stSources.TransitionBuffer = 1;
// Print Summary and ProgressIndicator
stSources.PrintInformation = 1;
stSources.PrintProgressIndicator = 1;
// Print Intro Message
dprintf ("(WmiTrace)LogDump for Log Id %ld\n", LoggerId);
// Get Pointer to Logger Context
tarAddress = FindLoggerContext (LoggerId);
ulAlignment = GetWmiTraceAlignment ();
// Filter and Gather all Messages we want
ulBufferCountTotal = wmiKdProcessBuffers (LoggerId, tarAddress,
wmiDumpProc, &stTraceContext, stSources);
// Sort the Entries just Gathered
qsort (stSortControl.pstSortEntries, stSortControl.CurEntries,
sizeof (stSortControl.pstSortEntries[0]), Compare);
if (stSortControl.CurEntries > 0) {
dprintf ("LOGGED MESSAGES (%ld):\n", stSortControl.CurEntries);
}
// Allocate Buffer
GetFieldValue (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "BufferSize", ulBufferSize);
lastBufferAddress = 0; // For the buffer 'cache' (one item for now)
locBufferAddress = LocalAlloc (LPTR, ulBufferSize);
if (locBufferAddress == NULL) {
dprintf ("FAILED TO ALLOCATE NEEDED BUFFER!\n");
goto Cleanup;
}
// Print each (Sorted) Entry
for (ulSortIndex = 0; ulSortIndex < stSortControl.CurEntries; ++ulSortIndex) {
const WMITRACING_KD_SORTENTRY *sortEntry;
union {
EVENT_TRACE stEvent;
CHAR caEvent[4096];
} u;
if (CheckControlC()) break;
sortEntry = &stSortControl.pstSortEntries[ulSortIndex];
// Read the entire buffer if not same as last
if (lastBufferAddress != sortEntry->Address) {
{
ULONG ulInfo;
ULONG ulBytesRead;
// Read Buffer
ulBytesRead = 0;
lastBufferAddress = sortEntry->Address;
ulInfo =
ReadMemory (lastBufferAddress, locBufferAddress, ulBufferSize, &ulBytesRead);
if ((!ulInfo) || (ulBytesRead != ulBufferSize)) {
dprintf ("Failed to (Re)Read Buffer @ %P.\n", lastBufferAddress);
continue; // Try for others
}
}
{
WMIBUFFERINFO stBufferInfo;
// Perform Fixup
memset (&stBufferInfo, 0, sizeof (stBufferInfo));
stBufferInfo.BufferSource = sortEntry->BufferSource;
stBufferInfo.Buffer = locBufferAddress;
stBufferInfo.BufferSize = ulBufferSize;
stBufferInfo.ProcessorNumber = sortEntry->CpuNo;
stBufferInfo.Alignment = ulAlignment;
WmiGetFirstTraceOffset (&stBufferInfo);
}
}
// Get a consistant header
WmiParseTraceEvent (locBufferAddress, sortEntry->Offset, sortEntry->HeaderType,
&u, sizeof (u));
// Output the Entry
Output (UserContext, GuidListHeadPtr, sortEntry, &u.stEvent);
}
Cleanup:
// Free Buffer
LocalFree (locBufferAddress);
// Print Summary
dprintf ("Total of %ld Messages from %ld Buffers\n",
stSortControl.CurEntries,
ulBufferCountTotal);
// Free the sort elements (pointers + keys)
free (stSortControl.pstSortEntries);
return;
} // wmiLogDump
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(help)
//
// Synopsis: list available functions and syntax
//
// Arguments: <NONE>
//
// Returns: <VOID>
//
// History: 2-17-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( help )
{
dprintf("WMI Tracing Kernel Debugger Extensions\n");
dprintf(" logdump <LoggerId> [<guid file name>] - Dump the in-memory portion of a log file\n");
dprintf(" logsave <LoggerId> <Save file name> - Save the in-memory portion of a log file in binary form\n");
dprintf(" strdump [<LoggerId>] - Dump the Wmi Trace Event Structures\n");
dprintf(" searchpath <Path> - Set the trace format search path\n");
dprintf(" guidfile <filename> - Set the guid file name (default is 'default.tmf')\n");
dprintf(" dynamicprint <0|1> - Turn live tracing messages on (1) or off (0). Default is on.\n");
//dprintf(" kdtracing <LoggerId> <0|1> - Turn live tracing messages on (1) or off (0) for a particular logger.\n");
}
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(logdump)
//
// Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
//
// Arguments: <Stream Number> [<MofData.Guid File Name>]
//
// Returns: <VOID>
//
// History: 2-17-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( logdump )
{
ULONG_PTR ulStatus = 0;
// TARGET_ADDRESS tarAddress = NULL;
ULONG ulLoggerId;
const CHAR *argPtr = NULL;
size_t sztLen = 0;
// Defaults
ulLoggerId = 1;
// LoggerId ?
if (args && args[0]) {
ulLoggerId = (ULONG) GetExpression (args);
}
// LoggerId ?
argPtr = args + strspn (args, " \t\n");
sztLen = strspn (argPtr, "0123456789");
if (sztLen > 0) {
// ulLoggerId = atol (argPtr);
argPtr += sztLen;
}
// Guid Definition File
argPtr = argPtr + strspn (argPtr, " \t\n,");
if (strlen (argPtr)) {
//only change name if it is different from what is already stored
if(_stricmp(argPtr, g_pszGuidFileName)){
sztLen = strcspn (argPtr, " \t\n,");
//make sure name will not overrun buffer
if(sztLen >= MAX_PATH) {
sztLen = MAX_PATH - 1;
}
// lpFileName = (LPTSTR)malloc((sztLen + 1) * sizeof(TCHAR));
memcpy(g_pszGuidFileName, argPtr, sztLen);
g_pszGuidFileName[sztLen] = '\000';
if(g_GuidListHeadPtr != NULL) {
if(g_fpCleanupTraceEventList == NULL) {
g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
}
if(g_fpCleanupTraceEventList != NULL) {
g_fpCleanupTraceEventList (g_GuidListHeadPtr);
g_GuidListHeadPtr = NULL;
} else {
dprintf ("ERROR: Failed to clean up Guid list.\n");
return;
}
}
}
}
// Show LoggerId, FileName
dprintf ("WMI Generic Trace Dump: Debugger Extension. LoggerId = %ld, Guidfile = '%s'\n",
ulLoggerId, g_pszGuidFileName);
// Open Guid File, Dump Log, Cleanup
if(g_GuidListHeadPtr == NULL) {
if(g_fpGetTraceGuids == NULL) {
g_fpGetTraceGuids = GetAddr(GetTraceGuidsString);
}
if(g_fpGetTraceGuids != NULL) {
ulStatus = g_fpGetTraceGuids ((TCHAR *) g_pszGuidFileName, &g_GuidListHeadPtr);
}
if (ulStatus == 0) {
dprintf ("Failed to open Guid file '%hs'\n", g_pszGuidFileName);
return;
}
}
dprintf ("Opened Guid File '%hs' with %d Entries.\n",
g_pszGuidFileName, ulStatus);
wmiLogDump (ulLoggerId, NULL, g_GuidListHeadPtr, NULL, NULL, NULL);
/*if(g_fpCleanupTraceEventList == NULL) {
g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
}
if(g_fpCleanupTraceEventList != NULL) {
g_fpCleanupTraceEventList (g_GuidListHeadPtr);
g_GuidListHeadPtr = NULL;
}*/
return;
} // logdump
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(logsave)
//
// Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
//
// Arguments: <Stream Number> [<MofData.Guid File Name>]
//
// Returns: <VOID>
//
// History: 2-17-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( logsave )
{
ULONG ulStatus;
TARGET_ADDRESS tarAddress;
ULONG ulLoggerId;
LPSTR pszSaveFileName;
const CHAR *argPtr;
size_t sztLen;
CHAR caFileName[256];
// Defaults
ulLoggerId = 1;
pszSaveFileName = "LogData.elg";
// LoggerId ?
if (args && args[0]) {
ulLoggerId = (ULONG) GetExpression (args);
}
// Point beyond LoggerId
argPtr = args + strspn (args, " \t\n");
argPtr += strspn (argPtr, "0123456789");
// Save File
argPtr = argPtr + strspn (argPtr, " \t\n,");
if (strlen (argPtr)) {
sztLen = strcspn (argPtr, " \t\n,");
memcpy (caFileName, argPtr, sztLen);
caFileName[sztLen] = '\000';
pszSaveFileName = caFileName;
}
// Show LoggerId, FileName
dprintf ("WMI Trace Save: Debugger Extension. LoggerId = %ld, Save File = '%s'\n",
ulLoggerId, pszSaveFileName);
// Get Pointer to Logger Context
tarAddress = FindLoggerContext (ulLoggerId);
// Check if LoggerId Good
if (tarAddress == 0) {
dprintf ("Failed to Find Logger\n");
} else {
FILE *pfSaveFile;
// Open Guid File, Dump Log, Cleanup
pfSaveFile = fopen (pszSaveFileName, "ab");
if (pfSaveFile == NULL) {
dprintf ("Failed to Open Save File '%hs'\n", pszSaveFileName);
} else {
WMITRACING_BUFFER_SOURCES stSources;
struct sttSaveContext stSaveContext;
ULONG ulTotalBufferCount;
ULONG ulRealTime;
// See if we are in "RealTime" mode (if so, we'll save FreeBuffers too)
if (GetFieldValue (tarAddress,
"NT!_WMI_LOGGER_CONTEXT",
"LoggerModeFlags.RealTime",
ulRealTime)) {
dprintf ("Unable to Retrieve 'RealTime' Flag. Assuming Realtime Mode.\n");
ulRealTime = 1; // Better to get too many than too few.
}
//Write Header
wmiKdWriteFileHeader (pfSaveFile, ulLoggerId, tarAddress);
// Select Sources
stSources.FreeBuffers = (ulRealTime) ? 1 : 0;
stSources.FlushBuffers = 1;
stSources.ActiveBuffers = 1;
stSources.TransitionBuffer = 1;
stSources.PrintInformation = 1;
stSources.PrintProgressIndicator = 1;
// Setup SaveContext
stSaveContext.pfSaveFile = pfSaveFile;
// Write Buffers
ulTotalBufferCount = wmiKdProcessBuffers (ulLoggerId, tarAddress,
wmiSaveProc, &stSaveContext, stSources);
dprintf ("Saved %d Buffers\n", ulTotalBufferCount);
// Close
fclose (pfSaveFile);
}
}
return;
} // logdump
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(strdump)
//
// Synopsis: STRucture DUMP: dumps generic info (no arg) or stream info (arg)
//
// Arguments: [<Stream Number>]
//
// Returns: <VOID>
//
// History: 2-17-2000 glennp Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( strdump )
/*
* dump the structures for trace logging
* strdump [<LoggerId>]
* If <LoggerId> present, dump structs for that Id
* Else dump generic structs
*/
{
TARGET_ADDRESS tarAddress;
DWORD dwRead, Flags;
ULONG ulLoggerId;
ULONG ulMaxLoggerId;
ULONG pointerSize;
// Defaults
ulLoggerId = ~0;
pointerSize = GetTypeSize ("PVOID");
// LoggerId ?
if (args && args[0]) {
ulLoggerId = (ULONG) GetExpression (args);
}
if (ulLoggerId == ~0) {
dprintf ("(WmiTracing)StrDump Generic\n");
tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
dprintf (" LoggerContext Array @ 0x%P [%d Elements]\n",
tarAddress, ulMaxLoggerId);
if (tarAddress) {
for (ulLoggerId = 0; ulLoggerId < ulMaxLoggerId; ++ulLoggerId) {
TARGET_ADDRESS contextAddress;
contextAddress = tarAddress + pointerSize * ulLoggerId;
/*if (*/ReadPointer (contextAddress, &contextAddress)/*) {*/;
//dprintf ("UNABLE TO READ POINTER in ARRAY of POINTERS!, Addr = 0x%P\n", contextAddress);
/*} else*/ if (contextAddress != 0) {
dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, contextAddress);
printUnicodeFromStruct (contextAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
}
}
}
} else {
dprintf ("(WmiTracing)StrDump for Log Id %ld\n", ulLoggerId);
tarAddress = FindLoggerContext (ulLoggerId);
if (tarAddress != 0) {
dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, tarAddress);
printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
dprintf (" BufferSize = %ld\n", (ULONG) ReadField (BufferSize));
dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
dprintf (" LoggerId = 0x%02lX\n", (ULONG) ReadField (LoggerId));
dprintf (" CollectionOn = %ld\n", (ULONG) ReadField (CollectionOn));
dprintf (" KernelTraceOn = %ld\n", (ULONG) ReadField (KernelTraceOn));
dprintf (" EnableFlags = 0x%08lX\n", (ULONG) ReadField (EnableFlags));
dprintf (" MaximumFileSize = %ld\n", (ULONG) ReadField (MaximumFileSize));
dprintf (" LogFileMode = 0x%08lX\n", (ULONG) ReadField (LogFileMode));
dprintf (" LoggerMode = 0x%08lX\n", (ULONG) ReadField (LoggerMode));
dprintf (" FlushTimer = %I64u\n", ReadField (FlushTimer));
dprintf (" FirstBufferOffset = %I64u\n", ReadField (FirstBufferOffset));
dprintf (" ByteOffset = %I64u\n", ReadField (ByteOffset));
dprintf (" BufferAgeLimit = %I64d\n", ReadField (BufferAgeLimit));
dprintf (" LoggerName = '");
printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ( "'\n");
dprintf (" LogFileName = '");
printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LogFileName");
dprintf ( "'\n");
}
}
return;
}
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(searchpath)
//
// Synopsis: LOG DUMP: Sets the trace format search path
//
// Arguments: <Path>
//
// Returns: <VOID>
//
// History: 7-03-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( searchpath )
{
const CHAR *argPtr;
size_t sztLen;
LPTSTR lppath;
LPWSTR lppathW;
int len, waslen = 0;
// Defaults
lppath = NULL;
lppathW = NULL;
// Path ?
if (args) {
argPtr = args + strspn (args, " \t\n");
if (strlen (argPtr)) {
sztLen = strcspn (argPtr, " \t\n,");
lppath = (LPTSTR)malloc((sztLen + 1) * sizeof(TCHAR));
if(lppath != NULL) {
memcpy (lppath, argPtr, sztLen);
lppath[sztLen] = '\000';
}
}
}
if(lppath != NULL) {
//Convert to Unicode
while (((len = MultiByteToWideChar(CP_ACP, 0, lppath, sztLen, lppathW, waslen)) - waslen) > 0) {
if (len - waslen > 0 ) {
if (lppathW != NULL) {
free(lppathW);
}
lppathW = (LPWSTR)malloc((len + 1) * sizeof(wchar_t)) ;
if ( !lppathW ) {
dprintf("Memory allocation failed.\n");
return;
}
waslen = len;
}
}
if(lppathW != NULL) {
lppathW[len] = L'\000';
}
if(g_fpSetTraceFormatParameter == NULL) {
g_fpSetTraceFormatParameter = GetAddr("SetTraceFormatParameter");
}
if(g_fpSetTraceFormatParameter != NULL) {
g_fpSetTraceFormatParameter(ParameterTraceFormatSearchPath, lppathW);
}
free(lppath);
if(lppathW != NULL){
free(lppathW);
}
}
lppathW = NULL;
if(g_fpGetTraceFormatSearchPath == NULL) {
g_fpGetTraceFormatSearchPath = GetAddr("GetTraceFormatSearchPath");
}
if(g_fpGetTraceFormatSearchPath != NULL) {
lppathW = (LPWSTR)g_fpGetTraceFormatSearchPath();
}
// Show new search path
dprintf ("WMI Set Trace Format Search Path: Debugger Extension. Path = '%S'\n", lppathW);
return;
}
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(guidfile)
//
// Synopsis: LOG DUMP: Sets guid file name (if not set, the default is "default.tmf")
//
// Arguments: <Path>
//
// Returns: <VOID>
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( guidfile )
{
const CHAR *argPtr;
size_t sztLen;
if (args) {
argPtr = args + strspn (args, " \t\n");
if (strlen (argPtr)) {
//only change name if it is different from what is already stored
if(_stricmp(argPtr, g_pszGuidFileName)){
sztLen = strcspn (argPtr, " \t\n,");
//make sure string length will not overrun buffer
if(sztLen >= MAX_PATH) {
sztLen = MAX_PATH - 1;
}
memcpy (g_pszGuidFileName, argPtr, sztLen);
g_pszGuidFileName[sztLen] = '\000';
if(g_GuidListHeadPtr != NULL) {
if(g_fpCleanupTraceEventList == NULL) {
g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
}
if(g_fpCleanupTraceEventList != NULL) {
g_fpCleanupTraceEventList (g_GuidListHeadPtr);
} else {
dprintf ("ERROR: Failed to clean up Guid list.\n");
}
g_GuidListHeadPtr = NULL;
}
}
}
}
dprintf("WMI Set Trace Guid File Name: Debugger Extension. File = '%s'\n", g_pszGuidFileName);
}
//+---------------------------------------------------------------------------
//
// Function: DECLARE_API(dynamicprint)
//
// Synopsis: LOG DUMP: Determines if dynamic tracing messaged are processed and printed, or just thrown away
//
// Arguments: <Path>
//
// Returns: <VOID>
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
DECLARE_API( dynamicprint )
{
const CHAR *argPtr;
LPSTR lpValue = NULL;
if (args) {
argPtr = args + strspn (args, " \t\n");
} else {
dprintf("Invalid parameters\n");
return;
}
if(!_stricmp(argPtr, "1") ){
lpValue = "ON";
g_ulPrintDynamicMessages = 1;
} else if(!_stricmp(argPtr, "0")) {
lpValue = "OFF";
g_ulPrintDynamicMessages = 0;
} else {
dprintf("'%s' is not a valid value. The valid values are 1 and 0 (on and off, respectively)\n", argPtr);
}
if(lpValue != NULL) {
dprintf("WMI Set Trace Dynamic Print: Debugger Extension. Printing is now '%s'\n", lpValue);
}
}
DECLARE_API( kdtracing )
{
ULONG ulStatus = 0;
ULONG ulLoggerId;
LPSTR lpValue = NULL;
ULONG ulTracingOn = 0;
TARGET_ADDRESS LoggerContext;
ULONG LoggerMode;
ULONG Offset;
ULONG ulBytesWritten;
TARGET_ADDRESS PhysAddr;
PVOID BufferCallback;
PVOID fpKdReportTraceData;
const CHAR *argPtr;
size_t sztLen;
// Defaults
ulLoggerId = 1;
// LoggerId ?
if (args && args[0]) {
ulLoggerId = (ULONG) GetExpression (args);
}
argPtr = args + strspn (args, " \t\n");
sztLen = strspn (argPtr, "0123456789");
if (sztLen > 0) {
argPtr += sztLen;
}
// Guid Definition File
argPtr = argPtr + strspn (argPtr, " \t\n,");
if(!_stricmp(argPtr, "1") ) {
lpValue = "ON";
ulTracingOn = 1;
} else if(!_stricmp(argPtr, "0")) {
lpValue = "OFF";
ulTracingOn = 0;
} else {
dprintf("'%s' is not a valid value. The valid values are 1 and 0 (on and off, respectively)\n", argPtr);
}
if(lpValue != NULL) {
LoggerContext = FindLoggerContext(ulLoggerId);
if(LoggerContext != 0) {
// Setup ReadField's Context, Find Buffer Size
InitTypeRead (LoggerContext, NT!_WMI_LOGGER_CONTEXT);
LoggerMode = (ULONG)ReadField(LoggerMode);
BufferCallback = (PVOID)ReadField(BufferCallback);
if(GetTypeSize("KdReportTraceData") != 0){
fpKdReportTraceData = (PVOID)GetExpression("KdReportTraceData");
} else {
dprintf("ERROR: Could not find proper callback function in symbol file\n");
return;
}
if(ulTracingOn) {
LoggerMode |= EVENT_TRACE_KD_FILTER_MODE;
BufferCallback = fpKdReportTraceData;
} else {
LoggerMode &= ~EVENT_TRACE_KD_FILTER_MODE;
if(BufferCallback == fpKdReportTraceData) {
BufferCallback = NULL;
}
}
//Get the address of the LoggerMode by finding the offset into the structure
//so it can be written to
if(GetFieldOffset("NT!_WMI_LOGGER_CONTEXT", "LoggerMode", &Offset) == 0) {
//Add offset to base address and convert to physical
if(TranslateVirtualToPhysical(LoggerContext + (TARGET_ADDRESS)Offset, &PhysAddr)){
WritePhysical(PhysAddr, &LoggerMode, sizeof(ULONG), &ulBytesWritten);
}
} else {
dprintf("ERROR: Could not change tracing mode for logger %d\n", ulLoggerId);
return;
}
//Do the same for the BufferCallback as above
if(GetFieldOffset("NT!_WMI_LOGGER_CONTEXT", "BufferCallback", &Offset) == 0) {
if(TranslateVirtualToPhysical(LoggerContext + (TARGET_ADDRESS)Offset, &PhysAddr)){
WritePhysical(PhysAddr, &BufferCallback, sizeof(PVOID), &ulBytesWritten);
}
} else {
dprintf("ERROR: Could not change tracing mode for logger &d\n", ulLoggerId);
return;
}
dprintf("WMI KD Tracing: Debugger Extension. KD tracing is now '%s' for logger %d\n", lpValue, ulLoggerId);
}
}
}
VOID
wmiDynamicDumpProc(
PDEBUG_CONTROL Ctrl,
ULONG Mask,
PLIST_ENTRY g_GuidListHeadPtr,
PVOID pBuffer,
ULONG ulBufferLen
)
//+---------------------------------------------------------------------------
//
// Function: wmiDynamicDumpProc
//
// Synopsis: Called by WmiFormatTraceData to process the buffers as the come in through a live
// debugging session
//
// Arguments: Ctrl -> used for the Output function
// Mask -> passed directly to the Output function
// g_GuidListHeadPtr
// pBuffer -> buffer to be processed
// ulBufferLen -> size of buffer
//
// Returns: <VOID>
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
{
WMIBUFFERINFO stBufferInfo;
ULONG size;
ULONG offset;
WMI_HEADER_TYPE headerType;
ULONG Alignment;
WCHAR wcaOutputLine[4096];
//Need to determine alignment based on architecture of target machine
//I believe alignment is always 8 ??
Alignment = 8;
memset (&stBufferInfo, 0, sizeof (stBufferInfo));
stBufferInfo.BufferSource = WMIBS_TRANSITION_LIST;
stBufferInfo.Buffer = pBuffer;
stBufferInfo.BufferSize = ulBufferLen;
stBufferInfo.Alignment = Alignment;
stBufferInfo.ProcessorNumber = ~((ULONG)0);
offset = WmiGetFirstTraceOffset (&stBufferInfo);
// Inspect Each Event
while ((headerType = WmiGetTraceHeader (pBuffer, offset, &size)) != WMIHT_NONE) {
ULONG ulInfo;
union {
EVENT_TRACE stEvent;
CHAR caEvent[4096];
} u;
if (CheckControlC()) break;
// Get a consistant header
ulInfo = WmiParseTraceEvent (pBuffer, offset, headerType, &u, sizeof (u));
wcaOutputLine[0] = 0;
if(g_fpFormatTraceEvent == NULL) {
g_fpFormatTraceEvent = GetAddr(FormatTraceEventString);
}
if(g_fpFormatTraceEvent != NULL) {
g_fpFormatTraceEvent (g_GuidListHeadPtr, (PEVENT_TRACE) &u.stEvent,
(TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
(TCHAR *) NULL);
} else {
return;
}
Ctrl->lpVtbl->Output(Ctrl, Mask, "%s\n", wcaOutputLine);
size = ((size + (Alignment-1)) / Alignment) * Alignment; //BUGBUG: Need fix in GetTraceHeader or WmiFlush. Then remove this line.
offset += size; // Move to next entry.
if(offset > ulBufferLen) {
Ctrl->lpVtbl->Output(Ctrl, Mask, "Past buffer end.\n");
break;
}
}
}
ULONG
WmiFormatTraceData(
PDEBUG_CONTROL Ctrl,
ULONG Mask,
ULONG DataLen,
PVOID Data
)
//+---------------------------------------------------------------------------
//
// Function: WmiFormatTraceData
//
// Synopsis: Implementation of function called by debugger when kd tracing is enabled through
// tracelog.
//
// Arguments: Ctrl
// Mask
// DataLen -> size of buffer
// Data -> buffer to be processed
//
// Returns: 0 (has no meaning for now..)
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
{
int i = 1;
ULONG_PTR ulStatus = 0;
if(g_ulPrintDynamicMessages) {
if(g_GuidListHeadPtr == NULL) {
if(g_fpGetTraceGuids == NULL) {
g_fpGetTraceGuids = GetAddr(GetTraceGuidsString);
}
if(g_fpGetTraceGuids != NULL) {
ulStatus = g_fpGetTraceGuids ((TCHAR *) g_pszGuidFileName, &g_GuidListHeadPtr);
}
if (ulStatus == 0) {
dprintf ("Failed to open Guid file '%hs'\n", g_pszGuidFileName);
return 0;
}
}
wmiDynamicDumpProc (Ctrl, Mask, g_GuidListHeadPtr, Data, DataLen);
}
return 0;
}
FARPROC GetAddr(
LPCSTR lpProcName
)
//+---------------------------------------------------------------------------
//
// Function: GetAddr
//
// Synopsis: Used to get the proc addr of a function in TracePrt. Prints error message when
// needed.
//
// Arguments: lpProcName -> name of procedure to be fetched
//
// Returns: <VOID>
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
{
FARPROC addr = NULL;
//See if the handle to TracePrt has already been fetched
if(g_hmTracePrtHandle == NULL) {
g_hmTracePrtHandle = getTracePrtHandle();
}
//If TracePrt handle exists, GetProcAddress
if(g_hmTracePrtHandle != NULL) {
addr = GetProcAddress(g_hmTracePrtHandle, lpProcName);
}
//Error if addr is null
if(addr == NULL) {
dprintf("ERROR: Could not properly load traceprt.dll\n", lpProcName);
}
return addr;
}
HMODULE getTracePrtHandle(
)
//+---------------------------------------------------------------------------
//
// Function: getTracePrtHandle
//
// Synopsis: Used to get a handle to the TracePrt dll. First looks in the directory that wmitrace
// is in, and if it cannot find it there, it looks in the default location (no path given).
//
// Arguments: lpProcName -> name of procedure to be fetched
//
// Returns: Handle to TracePrt dll, if found
//
// History: 7-10-2000 t-dbloom Created
//
// Notes:
//
//----------------------------------------------------------------------------
{
HMODULE handle = NULL;
TCHAR drive[10];
TCHAR filename[MAX_PATH];
TCHAR path[MAX_PATH];
TCHAR file[MAX_PATH];
TCHAR ext[MAX_PATH];
if(g_hmWmiTraceHandle == NULL) {
g_hmWmiTraceHandle = GetModuleHandle("wmiTrace.dll");
}
if (GetModuleFileName(g_hmWmiTraceHandle, filename, MAX_PATH) == MAX_PATH) {
filename[MAX_PATH-1] = '\0' ;
}
_splitpath( filename, drive, path, file, ext );
strcpy(file, "traceprt");
_makepath( filename, drive, path, file, ext );
//Try to get a handle to traceprt using full path as obtained above using path of wmitrace
handle = LoadLibrary(filename);
//If this didn't work, just try traceprt.dll without a path
if(handle == NULL) {
handle = LoadLibrary("traceprt.dll");
}
return handle;
}
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
EtwpInitializeDll();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
EtwpDeinitializeDll(); // Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}