1793 lines
60 KiB
C
1793 lines
60 KiB
C
//+---------------------------------------------------------------------------
|
||
//
|
||
// 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;
|
||
}
|
||
|