Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1792 lines
60 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 "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;
//+---------------------------------------------------------------------------
//
// 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;
FormatTraceEvent (GuidListHeadPtr, (PEVENT_TRACE) pstHeader,
(TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
(TCHAR *) NULL);
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;
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) {
ULONG ulInfo;
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;
pstSortControl->pstSortEntries =
realloc (pstSortControl->pstSortEntries,
sizeof (WMITRACING_KD_SORTENTRY) * (pstSortControl->MaxEntries));
if (pstSortControl->pstSortEntries == NULL) {
dprintf ("Memory Allocation Failure\n");
return;
}
}
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.
}
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 ("_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, _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 ("_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, "_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
}
// Setup ReadField's Context, Find Buffer Size
InitTypeRead (tarAddress, _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, "_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, _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,
"_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 ("_WMI_BUFFER_HEADER", "Entry", &tarBufferListOffset);
GetFieldOffset ("_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, "_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
}
// Setup ReadField's Context, Find Buffer Size
InitTypeRead (tarAddress, _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 ("_WMI_BUFFER_HEADER", "Entry", &tarTransitionBufferOffset);
tarTransitionBuffer = tarAddress - tarTransitionBufferOffset;
TransitionBuffer = tarTransitionBuffer;
}
}
// Access the Free Queue Buffers IF REQUESTED
if (Sources.FreeBuffers) {
ULONG tarFreeListOffset;
GetFieldOffset ("_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,"_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 ("_WMI_LOGGER_CONTEXT", "GlobalList", &tarGlobalListOffset) == 0) &&
(tarGlobalListOffset != 0)) {
iBufferMechanism += 1;
}
if ((GetFieldOffset ("_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, "_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");
}
//+---------------------------------------------------------------------------
//
// 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 ulStatus;
TARGET_ADDRESS tarAddress;
ULONG ulLoggerId;
LPSTR pszGuidFileName;
PLIST_ENTRY GuidListHeadPtr;
const CHAR *argPtr;
size_t sztLen;
CHAR caFileName[256];
// Defaults
ulLoggerId = 1;
GuidListHeadPtr = NULL;
pszGuidFileName = "FmtData.txt";
// 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)) {
sztLen = strcspn (argPtr, " \t\n,");
memcpy (caFileName, argPtr, sztLen);
caFileName[sztLen] = '\000';
pszGuidFileName = caFileName;
}
// Show LoggerId, FileName
dprintf ("WMI Generic Trace Dump: Debugger Extension. LoggerId = %ld, Guidfile = '%s'\n",
ulLoggerId, pszGuidFileName);
// Open Guid File, Dump Log, Cleanup
GuidListHeadPtr = NULL;
ulStatus = GetTraceGuids ((TCHAR *) pszGuidFileName, &GuidListHeadPtr);
if (ulStatus == 0) {
dprintf ("Failed to open Guid file '%hs'\n", pszGuidFileName);
} else {
dprintf ("Opened Guid File '%hs' with %d Entries.\n",
pszGuidFileName, ulStatus);
wmiLogDump (ulLoggerId, NULL, GuidListHeadPtr, NULL, NULL, NULL);
CleanupTraceEventList (GuidListHeadPtr);
}
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,
"_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, "_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, "_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ("'\n");
InitTypeRead (tarAddress, _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 (" 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, "_WMI_LOGGER_CONTEXT", "LoggerName");
dprintf ( "'\n");
dprintf (" LogFileName = '");
printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LogFileName");
dprintf ( "'\n");
}
}
return;
}