6912 lines
228 KiB
C++
6912 lines
228 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
callbacks.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Setting up and handling the callbacks for the events from the
|
||
|
trace file.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Melur Raghuraman (mraghu) 03-Oct-1997
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Insung Park (insungp) 05-Jan-2001
|
||
|
|
||
|
Updated DumpEvent() so that by default, it searches WBEM namespace
|
||
|
for the event data layout information.
|
||
|
Functions added/modified: GetArraySize, GetItemType,
|
||
|
GetPropertiesFromWBEM, GetGuidsWbem, GetGuidsFile, and GetGuids.
|
||
|
|
||
|
Insung Park (insungp) 16-Jan-2001
|
||
|
|
||
|
Changes enabling tracerpt to handle an invalid type name array in the WBEM namespace.
|
||
|
Bug fixes for memory corruption (GetPropertiesFromWBEM and GetGuidsWBEM).
|
||
|
|
||
|
|
||
|
--*/
|
||
|
#ifdef __cplusplus
|
||
|
extern "C"{
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "cpdata.h"
|
||
|
#include <wbemidl.h>
|
||
|
#include "tracectr.h"
|
||
|
#include "item.h"
|
||
|
#include "guids.h"
|
||
|
|
||
|
#define BUFFER_SIZE 64*1024
|
||
|
#define MAX_BUFFER_SIZE 10*1024*1024
|
||
|
|
||
|
#define MOFWSTR 16360
|
||
|
#define MOFSTR 32720
|
||
|
#define MAXTYPE 256
|
||
|
#define MAXGUIDSTR 128
|
||
|
#define UC(x) ( (UINT)((x) & 0xFF) )
|
||
|
#define NTOHS(x) ( (UC(x) * 256) + UC((x) >> 8) )
|
||
|
|
||
|
//
|
||
|
// IRP Flags from ntos\inc\io.h for Io event processing.
|
||
|
//
|
||
|
|
||
|
#define IRP_NOCACHE 0x00000001
|
||
|
#define IRP_PAGING_IO 0x00000002
|
||
|
#define IRP_SYNCHRONOUS_API 0x00000004
|
||
|
#define IRP_ASSOCIATED_IRP 0x00000008
|
||
|
#define IRP_BUFFERED_IO 0x00000010
|
||
|
#define IRP_DEALLOCATE_BUFFER 0x00000020
|
||
|
#define IRP_SYNCHRONOUS_PAGING_IO 0x00000040
|
||
|
#define IRP_CREATE_OPERATION 0x00000080
|
||
|
#define IRP_READ_OPERATION 0x00000100
|
||
|
#define IRP_WRITE_OPERATION 0x00000200
|
||
|
#define IRP_CLOSE_OPERATION 0x00000400
|
||
|
#define IRP_DEFER_IO_COMPLETION 0x00000800
|
||
|
#define IRP_OB_QUERY_NAME 0x00001000
|
||
|
#define IRP_HOLD_DEVICE_QUEUE 0x00002000
|
||
|
|
||
|
int IdleEndCount = 0;
|
||
|
ULONG PageFaultCount = 0;
|
||
|
ULONG EventCount = 0;
|
||
|
|
||
|
extern PTRACE_CONTEXT_BLOCK TraceContext;
|
||
|
extern ULONG TotalBuffersRead;
|
||
|
extern BOOLEAN XPorHigher;
|
||
|
|
||
|
ULONG HPFReadCount = 0;
|
||
|
ULONG HPFWriteCount = 0;
|
||
|
|
||
|
ULONG TotalEventsLost = 0;
|
||
|
ULONG TotalEventCount = 0;
|
||
|
ULONG TimerResolution = 10;
|
||
|
__int64 ElapseTime;
|
||
|
|
||
|
PCHAR MofData = NULL;
|
||
|
size_t MofLength = 0;
|
||
|
BOOLEAN fIgnorePerfClock = FALSE;
|
||
|
BOOLEAN fRealTimeCircular = FALSE;
|
||
|
ULONG PointerSize = 0;
|
||
|
|
||
|
BOOL g_bUserMode = FALSE;
|
||
|
|
||
|
static ULONG NumProc = 0;
|
||
|
ULONGLONG BogusThreads[64];
|
||
|
ULONG BogusCount=0;
|
||
|
ULONG IdleThreadCount=0;
|
||
|
BOOLEAN bCaptureBogusThreads=TRUE;
|
||
|
|
||
|
BOOLEAN bIISEvents = FALSE;
|
||
|
ULONG IISRequestsDiscarded = 0;
|
||
|
ULONG IISEventsDiscarded = 0;
|
||
|
|
||
|
IWbemServices *pWbemServices = NULL;
|
||
|
LIST_ENTRY g_ValueMapTable;
|
||
|
|
||
|
void AnsiToUnicode(PCHAR str, PWCHAR wstr);
|
||
|
|
||
|
ULONG ahextoi( WCHAR *s);
|
||
|
|
||
|
ULONG StringToNumber( LPWSTR sz );
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuids( GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent );
|
||
|
|
||
|
HRESULT
|
||
|
WbemConnect( IWbemServices** pWbemServices );
|
||
|
|
||
|
ULONG GetArraySize(
|
||
|
IN IWbemQualifierSet *pQualSet
|
||
|
);
|
||
|
|
||
|
ITEM_TYPE
|
||
|
GetItemType(
|
||
|
IN CIMTYPE_ENUMERATION CimType,
|
||
|
IN IWbemQualifierSet *pQualSet
|
||
|
);
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetPropertiesFromWBEM(
|
||
|
IWbemClassObject *pTraceSubClasses,
|
||
|
GUID Guid,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel,
|
||
|
SHORT nType,
|
||
|
BOOL bKernelEvent
|
||
|
);
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsWBEM (
|
||
|
GUID Guid,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel,
|
||
|
SHORT nType,
|
||
|
BOOL bKernelEvent
|
||
|
);
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsMofFiles(
|
||
|
GUID Guid,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel,
|
||
|
SHORT nType,
|
||
|
BOOL bKernelEvent
|
||
|
);
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsFile(
|
||
|
FILE *f,
|
||
|
GUID Guid,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel,
|
||
|
SHORT nType,
|
||
|
BOOL bKernelEvent
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
EventCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
AddMofInfo(
|
||
|
PLIST_ENTRY List,
|
||
|
LPWSTR strType,
|
||
|
SHORT nType,
|
||
|
UINT ArraySize,
|
||
|
PVALUEMAP pValueMap
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
UpdateThreadPrintData(
|
||
|
PPRINT_JOB_RECORD pJob,
|
||
|
PEVENT_TRACE_HEADER pHeader,
|
||
|
PTHREAD_RECORD pThread
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PrintJobCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
UpdateThreadIisData(
|
||
|
PHTTP_REQUEST_RECORD pReq,
|
||
|
PEVENT_TRACE_HEADER pHeader,
|
||
|
PTHREAD_RECORD pThread
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
SumUpCPUTime(
|
||
|
PHTTP_REQUEST_RECORD pReq
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
IISEventCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
);
|
||
|
|
||
|
void
|
||
|
WINAPI
|
||
|
DumpEvent(
|
||
|
PEVENT_TRACE pEvent
|
||
|
);
|
||
|
|
||
|
void
|
||
|
DumpMofVersionItem(
|
||
|
PMOF_VERSION pMofVersion
|
||
|
);
|
||
|
|
||
|
void
|
||
|
DumpMofList();
|
||
|
|
||
|
extern PWCHAR CpdiGuidToString(PWCHAR s, ULONG len, LPGUID piid);
|
||
|
|
||
|
|
||
|
ULONG Interpolate(ULONGLONG timeStart, ULONG deltaStart,
|
||
|
ULONGLONG timeEnd, ULONG deltaEnd,
|
||
|
ULONGLONG timeMiddle)
|
||
|
{
|
||
|
return deltaStart
|
||
|
+ (deltaEnd - deltaStart) * ((ULONG) (timeMiddle - timeStart))
|
||
|
/ ((ULONG) (timeEnd - timeStart));
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
InTimeWindow(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header;
|
||
|
BOOLEAN fResult = (pThread) ? (TRUE) : (FALSE);
|
||
|
|
||
|
if (fResult && fDSOnly)
|
||
|
{
|
||
|
if ( ((ULONGLONG) pHeader->TimeStamp.QuadPart < DSStartTime)
|
||
|
|| ((ULONGLONG) pHeader->TimeStamp.QuadPart > DSEndTime))
|
||
|
{
|
||
|
fResult = FALSE;
|
||
|
}
|
||
|
}
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AdjustThreadTime(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header;
|
||
|
|
||
|
if (IsEqualGUID(&pHeader->Guid, &EventTraceGuid))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
else if (!pThread || pThread->DeadFlag)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
else if (fDSOnly)
|
||
|
{
|
||
|
if ( ((ULONGLONG) pHeader->TimeStamp.QuadPart >= DSStartTime)
|
||
|
&& ((ULONGLONG) pHeader->TimeStamp.QuadPart <= DSEndTime))
|
||
|
{
|
||
|
if (pThread->TimeStart < DSStartTime)
|
||
|
{
|
||
|
pThread->TimeStart = DSStartTime;
|
||
|
pThread->KCPUStart = Interpolate(
|
||
|
pThread->TimeEnd, pThread->KCPUStart,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->KernelTime,
|
||
|
DSStartTime);
|
||
|
pThread->UCPUStart = Interpolate(
|
||
|
pThread->TimeEnd, pThread->UCPUStart,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->UserTime,
|
||
|
DSStartTime);
|
||
|
}
|
||
|
|
||
|
pThread->KCPUEnd = pHeader->KernelTime;
|
||
|
pThread->UCPUEnd = pHeader->UserTime;
|
||
|
pThread->TimeEnd = (ULONGLONG)pHeader->TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if ((ULONGLONG) pHeader->TimeStamp.QuadPart < DSStartTime)
|
||
|
{
|
||
|
pThread->TimeStart = pThread->TimeEnd
|
||
|
= (ULONGLONG) pHeader->TimeStamp.QuadPart;
|
||
|
pThread->KCPUStart = pThread->KCPUEnd = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pThread->UCPUEnd = pHeader->UserTime;
|
||
|
}
|
||
|
else if ((ULONGLONG) pHeader->TimeStamp.QuadPart > DSEndTime)
|
||
|
{
|
||
|
if (pThread->TimeEnd < DSEndTime)
|
||
|
{
|
||
|
if (pThread->TimeEnd < DSStartTime)
|
||
|
{
|
||
|
pThread->KCPUStart = Interpolate(
|
||
|
pThread->TimeEnd, pThread->KCPUStart,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->KernelTime,
|
||
|
DSStartTime);
|
||
|
pThread->UCPUStart = Interpolate(
|
||
|
pThread->TimeEnd, pThread->UCPUStart,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->UserTime,
|
||
|
DSStartTime);
|
||
|
pThread->TimeStart = DSStartTime;
|
||
|
}
|
||
|
pThread->KCPUEnd = Interpolate(
|
||
|
pThread->TimeEnd, pThread->KCPUEnd,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->KernelTime,
|
||
|
DSEndTime);
|
||
|
pThread->UCPUEnd = Interpolate(
|
||
|
pThread->TimeEnd, pThread->UCPUEnd,
|
||
|
pHeader->TimeStamp.QuadPart, pHeader->UserTime,
|
||
|
DSEndTime);
|
||
|
pThread->TimeEnd = DSEndTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pThread->TimeEnd = pHeader->TimeStamp.QuadPart;
|
||
|
if (pThread->KCPUEnd <= pHeader->KernelTime)
|
||
|
pThread->KCPUEnd = pHeader->KernelTime;
|
||
|
if (pThread->UCPUEnd <= pHeader->UserTime)
|
||
|
pThread->UCPUEnd = pHeader->UserTime;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This routine allocates a new MOF_VERSION entry for
|
||
|
// the given type, version and Level.
|
||
|
//
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetNewMofVersion( SHORT nType, SHORT nVersion, CHAR nLevel )
|
||
|
{
|
||
|
PMOF_VERSION pMofVersion = NULL;
|
||
|
|
||
|
pMofVersion = (PMOF_VERSION)malloc(sizeof(MOF_VERSION));
|
||
|
|
||
|
if( NULL == pMofVersion ){
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory(pMofVersion, sizeof(MOF_VERSION));
|
||
|
|
||
|
InitializeListHead(&pMofVersion->ItemHeader);
|
||
|
|
||
|
pMofVersion->TypeIndex = nType;
|
||
|
pMofVersion->Level = nLevel;
|
||
|
pMofVersion->Version = nVersion;
|
||
|
|
||
|
return pMofVersion;
|
||
|
}
|
||
|
|
||
|
static void reduceA(char *Src)
|
||
|
{
|
||
|
char *Start = Src;
|
||
|
if (!Src)
|
||
|
return;
|
||
|
while (*Src)
|
||
|
{
|
||
|
if ('\t' == *Src)
|
||
|
*Src = ' ';
|
||
|
else if (',' == *Src)
|
||
|
*Src = ' ';
|
||
|
else if ('\n' == *Src)
|
||
|
*Src = ',';
|
||
|
else if ('\r' == *Src)
|
||
|
*Src = ' ';
|
||
|
++Src;
|
||
|
}
|
||
|
--Src;
|
||
|
while ((Start < Src) && ((' ' == *Src) || (',' == *Src)))
|
||
|
{
|
||
|
*Src = 0x00;
|
||
|
--Src;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void reduceW(WCHAR *Src)
|
||
|
{
|
||
|
WCHAR *Start = Src;
|
||
|
if (!Src)
|
||
|
return;
|
||
|
while (*Src)
|
||
|
{
|
||
|
if (L'\t' == *Src)
|
||
|
*Src = L' ';
|
||
|
else if (L',' == *Src)
|
||
|
*Src = L' ';
|
||
|
else if (L'\n' == *Src)
|
||
|
*Src = L',';
|
||
|
else if (L'\r' == *Src)
|
||
|
*Src = L' ';
|
||
|
++Src;
|
||
|
}
|
||
|
--Src;
|
||
|
while ((Start < Src) && ((L' ' == *Src) || (L',' == *Src)))
|
||
|
{
|
||
|
*Src = 0x00;
|
||
|
--Src;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void replaceNLW(WCHAR *Src)
|
||
|
{
|
||
|
WCHAR *Start = Src;
|
||
|
if (!Src)
|
||
|
return;
|
||
|
while (*Src)
|
||
|
{
|
||
|
if (L'\n' == *Src)
|
||
|
*Src = L' ';
|
||
|
else if (L'\r' == *Src)
|
||
|
*Src = L' ';
|
||
|
++Src;
|
||
|
}
|
||
|
--Src;
|
||
|
while ((Start < Src) && (L' ' == *Src))
|
||
|
{
|
||
|
*Src = 0x00;
|
||
|
--Src;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Given a GUID, return a MOF_INFO
|
||
|
//
|
||
|
|
||
|
PMOF_INFO
|
||
|
GetMofInfoHead(
|
||
|
LPCGUID pGuid
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PLIST_ENTRY EventListHead;
|
||
|
|
||
|
if (pGuid == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
// Search the eventList for this Guid and find the head
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Traverse the list and look for the Mof info head for this Guid.
|
||
|
|
||
|
EventListHead = &CurrentSystem.EventListHead;
|
||
|
Head = EventListHead;
|
||
|
Next = Head->Flink;
|
||
|
|
||
|
while (Head != Next) {
|
||
|
pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry);
|
||
|
if (IsEqualGUID(&pMofInfo->Guid, pGuid)) {
|
||
|
return pMofInfo;
|
||
|
}
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If not found, add a new entry for this GUID
|
||
|
//
|
||
|
|
||
|
pMofInfo = (PMOF_INFO)malloc(sizeof(MOF_INFO));
|
||
|
if (pMofInfo == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
RtlZeroMemory (pMofInfo, sizeof(MOF_INFO));
|
||
|
pMofInfo->Guid = *pGuid;
|
||
|
InitializeListHead(&pMofInfo->VersionHeader);
|
||
|
InitializeListHead(&pMofInfo->DataListHead);
|
||
|
|
||
|
InsertTailList(EventListHead, &pMofInfo->Entry);
|
||
|
return pMofInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Locate the mof version information for the given guid
|
||
|
//
|
||
|
PMOF_VERSION
|
||
|
GetMofVersion(
|
||
|
PMOF_INFO pMofInfo,
|
||
|
SHORT nType,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel
|
||
|
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
SHORT nMatchLevel = 0;
|
||
|
SHORT nMatchCheck = 0;
|
||
|
PMOF_VERSION pMofVersion = NULL;
|
||
|
PMOF_VERSION pBestMatch = NULL;
|
||
|
|
||
|
|
||
|
if (pMofInfo == NULL)
|
||
|
return NULL;
|
||
|
//
|
||
|
// Traverse the list and look for the Mof info head for this Guid.
|
||
|
|
||
|
Head = &pMofInfo->VersionHeader;
|
||
|
Next = Head->Flink;
|
||
|
|
||
|
while (Head != Next) {
|
||
|
|
||
|
nMatchCheck = 0;
|
||
|
pMofVersion = CONTAINING_RECORD(Next, MOF_VERSION, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
if( pMofVersion->TypeIndex == nType ){
|
||
|
nMatchCheck++;
|
||
|
}
|
||
|
if( pMofVersion->Level == nLevel ){
|
||
|
nMatchCheck++;
|
||
|
}
|
||
|
if( pMofVersion->Version == nVersion ){
|
||
|
nMatchCheck++;
|
||
|
}
|
||
|
|
||
|
if( nMatchCheck == 3 ){ // Exact Match
|
||
|
return pMofVersion;
|
||
|
}
|
||
|
|
||
|
if( nMatchCheck > nMatchLevel ){ // Close Match
|
||
|
|
||
|
nMatchLevel = nMatchCheck;
|
||
|
pBestMatch = pMofVersion;
|
||
|
}
|
||
|
|
||
|
if( pMofVersion->TypeIndex == EVENT_TYPE_DEFAULT && // Total Guess
|
||
|
pBestMatch == NULL ){
|
||
|
|
||
|
pBestMatch = pMofVersion;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (pBestMatch != NULL) {
|
||
|
return pBestMatch;
|
||
|
}
|
||
|
//
|
||
|
// If One does not exist, look it up.
|
||
|
//
|
||
|
pMofVersion = GetGuids( pMofInfo->Guid, nVersion, nLevel, nType, 0 );
|
||
|
|
||
|
// If still not found, create a unknown place holder
|
||
|
if( NULL == pMofVersion ){
|
||
|
pMofVersion = GetNewMofVersion( nType, nVersion, nLevel );
|
||
|
if( pMofVersion != NULL ){
|
||
|
InsertTailList( &pMofInfo->VersionHeader, &pMofVersion->Entry );
|
||
|
|
||
|
if (nType == EVENT_TRACE_TYPE_INFO) {
|
||
|
LPWSTR szHeader = L"Header";
|
||
|
pMofVersion->strType = (PWCHAR)malloc((lstrlenW(szHeader)+1)*sizeof(WCHAR));
|
||
|
if( pMofVersion->strType != NULL ){
|
||
|
StringCchCopyW( pMofVersion->strType, lstrlenW(szHeader)+1, szHeader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pMofVersion;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This routine adds a ITEM_DESC entry to all the MOF_VERSION
|
||
|
// structures in the List
|
||
|
//
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AddMofInfo(
|
||
|
PLIST_ENTRY List,
|
||
|
LPWSTR strType,
|
||
|
SHORT nType,
|
||
|
UINT ArraySize,
|
||
|
PVALUEMAP pValueMap
|
||
|
)
|
||
|
{
|
||
|
PITEM_DESC pItem;
|
||
|
PMOF_VERSION pMofVersion;
|
||
|
|
||
|
PLIST_ENTRY Head = List;
|
||
|
PLIST_ENTRY Next = Head->Flink;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Traverse through the list of MOF_VERSIONS
|
||
|
//
|
||
|
|
||
|
while (Head != Next) {
|
||
|
|
||
|
pMofVersion = CONTAINING_RECORD(Next, MOF_VERSION, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
if( NULL != pMofVersion ){
|
||
|
|
||
|
//
|
||
|
// ALLOCATE a new ITEM_DESC for the given type
|
||
|
//
|
||
|
|
||
|
pItem = (PITEM_DESC) malloc(sizeof(ITEM_DESC));
|
||
|
if( NULL == pItem ){
|
||
|
return;
|
||
|
}
|
||
|
ZeroMemory( pItem, sizeof(ITEM_DESC) );
|
||
|
pItem->ItemType = (ITEM_TYPE)nType;
|
||
|
pItem->ArraySize = ArraySize;
|
||
|
|
||
|
|
||
|
// All standard datatypes with fixed sizes will be filled here.
|
||
|
|
||
|
switch (nType) {
|
||
|
case ItemChar :
|
||
|
case ItemUChar : pItem->DataSize = sizeof (char); break;
|
||
|
case ItemCharHidden : pItem->DataSize = sizeof (char); break;
|
||
|
case ItemBool : pItem->DataSize = sizeof (BOOL); break;
|
||
|
case ItemWChar : pItem->DataSize = sizeof (WCHAR); break;
|
||
|
case ItemShort :
|
||
|
case ItemPort :
|
||
|
case ItemUShort : pItem->DataSize = sizeof (short); break;
|
||
|
case ItemSizeT :
|
||
|
case ItemPtr : pItem->DataSize = PointerSize / 8; break; // BUG when two files (Win64 & Win32) are used.
|
||
|
case ItemLong :
|
||
|
case ItemIPAddr :
|
||
|
case ItemCPUTime :
|
||
|
case ItemULong :
|
||
|
case ItemULongX : pItem->DataSize = sizeof (ULONG); break;
|
||
|
case ItemGuid : pItem->DataSize = sizeof(GUID); break;
|
||
|
case ItemLongLong :
|
||
|
case ItemULongLong : pItem->DataSize = sizeof (__int64); break;
|
||
|
case ItemChar4 : pItem->DataSize = sizeof(char) * 4; break;
|
||
|
// This is the maximum size for TDI address.
|
||
|
case ItemTDIAddr : pItem->DataSize = sizeof(USHORT) + sizeof(TDI_ADDRESS_IP6); break;
|
||
|
case ItemOptArgs :
|
||
|
default : pItem->DataSize = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
pItem->strDescription = (PWCHAR) malloc((lstrlenW(strType)+1)*sizeof(WCHAR));
|
||
|
|
||
|
if( NULL == pItem->strDescription ){
|
||
|
free( pItem );
|
||
|
return;
|
||
|
}
|
||
|
StringCchCopyW(pItem->strDescription, lstrlenW(strType)+1, strType);
|
||
|
|
||
|
if( NULL != pValueMap ){
|
||
|
|
||
|
pItem->pValueMap = pValueMap;
|
||
|
|
||
|
/*
|
||
|
if( NULL == pItem->pValueMap ){
|
||
|
free( pItem->strDescription );
|
||
|
free( pItem );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pItem->pValueMap->dwValueType = pValueMap->dwValueType;
|
||
|
SafeArrayCopy( pValueMap->saValueMap, &pItem->pValueMap->saValueMap );
|
||
|
SafeArrayCopy( pValueMap->saValues, &pItem->pValueMap->saValues );
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert the new entry into the ItemHeader list for
|
||
|
// this Version, Type, Level combination
|
||
|
//
|
||
|
|
||
|
InsertTailList( &(pMofVersion->ItemHeader), &pItem->Entry);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DeclareKernelEvents()
|
||
|
{
|
||
|
PMOF_VERSION pMofVersion;
|
||
|
|
||
|
pMofVersion = GetGuids(FileIoGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(DiskIoGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(PageFaultGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(ProcessGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(ImageLoadGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(ThreadGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(TcpIpGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(UdpIpGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(EventTraceConfigGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(RegistryGuid, EVENT_TYPE_DEFAULT, EVENT_VERSION_DEFAULT, EVENT_LEVEL_DEFAULT, TRUE);
|
||
|
pMofVersion = GetGuids(EventTraceGuid, 0, 0, EVENT_TRACE_TYPE_INFO, TRUE);
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
LogHeaderCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG BuildNumber;
|
||
|
PPROCESS_FILE_RECORD pFileRec;
|
||
|
PTRACE_LOGFILE_HEADER pEvmInfo;
|
||
|
ULONGLONG HeaderStartTime = 0;
|
||
|
|
||
|
if (pEvent == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
if ( (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_GUIDMAP) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_EXTENSION) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pEvmInfo = (PTRACE_LOGFILE_HEADER) pEvent->MofData;
|
||
|
BuildNumber = pEvmInfo->ProviderVersion;
|
||
|
BuildNumber &= (0xFAFFFFFF);
|
||
|
CurrentSystem.BuildNumber = BuildNumber;
|
||
|
|
||
|
CurrentSystem.TimerResolution = pEvmInfo->TimerResolution / 10000;
|
||
|
CurrentSystem.NumberOfProcessors = pEvmInfo->NumberOfProcessors;
|
||
|
CurrentSystem.CpuSpeed = pEvmInfo->CpuSpeedInMHz;
|
||
|
|
||
|
g_bUserMode = (pEvmInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE);
|
||
|
if(pEvmInfo->TimerResolution > 0){
|
||
|
TimerResolution = pEvmInfo->TimerResolution / 10000;
|
||
|
}
|
||
|
TotalEventsLost += pEvmInfo->EventsLost;
|
||
|
|
||
|
//
|
||
|
// If Multiple files are given, use the values from the first file.
|
||
|
//
|
||
|
|
||
|
if (NumProc == 0) {
|
||
|
NumProc = pEvmInfo->NumberOfProcessors;
|
||
|
RtlZeroMemory(&BogusThreads, 64*sizeof(ULONG));
|
||
|
}
|
||
|
|
||
|
if (PointerSize < pEvmInfo->PointerSize * 8) {
|
||
|
// We have multiple files with different pointer size. We cannot
|
||
|
// resolve this because event callback has no pointersize or origin
|
||
|
// file information.
|
||
|
|
||
|
// For now, we will assume that a larger pointer size. This needs to
|
||
|
// be fixed in longhorn.
|
||
|
|
||
|
PointerSize = pEvmInfo->PointerSize * 8;
|
||
|
}
|
||
|
if (PointerSize < 16){ // minimum is 16 bits
|
||
|
PointerSize = 32; // defaults = 32 bits
|
||
|
}
|
||
|
|
||
|
// When we pick up names and start time from individual files here, we don't use
|
||
|
// global pointersize for the reason mentioned above.
|
||
|
if (pEvmInfo->PointerSize == 4 && sizeof(PVOID) == 8) {
|
||
|
RtlCopyMemory(&HeaderStartTime, ((PUCHAR)(&(pEvmInfo->StartTime)) - 8), sizeof(ULONGLONG));
|
||
|
}
|
||
|
else if (pEvmInfo->PointerSize == 8 && sizeof(PVOID) == 4) {
|
||
|
RtlCopyMemory(&HeaderStartTime, ((PUCHAR)(&(pEvmInfo->StartTime)) + 8), sizeof(ULONGLONG));
|
||
|
}
|
||
|
else {
|
||
|
HeaderStartTime = (ULONGLONG)(pEvmInfo->StartTime.QuadPart);
|
||
|
}
|
||
|
//
|
||
|
// With Multiple LogFiles always take the largest time window
|
||
|
//
|
||
|
if ((CurrentSystem.StartTime == (ULONGLONG)0) ||
|
||
|
(CurrentSystem.StartTime > HeaderStartTime)) {
|
||
|
CurrentSystem.StartTime = HeaderStartTime;
|
||
|
}
|
||
|
|
||
|
if (DSStartTime == 0) {
|
||
|
DSStartTime = CurrentSystem.StartTime;
|
||
|
}
|
||
|
if (fDSOnly && CurrentSystem.StartTime < DSStartTime) {
|
||
|
CurrentSystem.StartTime = DSStartTime;
|
||
|
}
|
||
|
|
||
|
if ((CurrentSystem.EndTime == (ULONGLONG)0) ||
|
||
|
(CurrentSystem.EndTime < (ULONGLONG)pEvmInfo->EndTime.QuadPart)) {
|
||
|
CurrentSystem.EndTime = pEvmInfo->EndTime.QuadPart;
|
||
|
}
|
||
|
if (!(CurrentSystem.fNoEndTime)) {
|
||
|
CurrentSystem.fNoEndTime = ((ULONGLONG)pEvmInfo->EndTime.QuadPart == 0);
|
||
|
}
|
||
|
|
||
|
if (DSEndTime == 0) {
|
||
|
DSEndTime = CurrentSystem.EndTime;
|
||
|
}
|
||
|
if (fDSOnly && CurrentSystem.EndTime > DSEndTime) {
|
||
|
CurrentSystem.EndTime = DSEndTime;
|
||
|
}
|
||
|
|
||
|
if (TraceContext->Flags & TRACE_REDUCE) {
|
||
|
pFileRec = (PPROCESS_FILE_RECORD)malloc(sizeof(PROCESS_FILE_RECORD));
|
||
|
if( pFileRec != NULL ){
|
||
|
// Temporary... WMI Should dereference ->LogFileName
|
||
|
LPWSTR pName = (LPWSTR)pEvmInfo;
|
||
|
if (pEvmInfo->PointerSize == 4 && sizeof(PVOID) == 8) {
|
||
|
pName = (LPWSTR)((PCHAR)pName + sizeof( TRACE_LOGFILE_HEADER ) - 8);
|
||
|
}
|
||
|
else if (pEvmInfo->PointerSize == 8 && sizeof(PVOID) == 4) {
|
||
|
pName = (LPWSTR)((PCHAR)pName + sizeof( TRACE_LOGFILE_HEADER ) + 8);
|
||
|
}
|
||
|
else {
|
||
|
pName = (LPWSTR)((PCHAR)pName + sizeof( TRACE_LOGFILE_HEADER ));
|
||
|
}
|
||
|
pFileRec->TraceName = (LPWSTR)malloc( ( lstrlenW(pName)+1 )*sizeof(WCHAR) );
|
||
|
if( pFileRec->TraceName != NULL ){
|
||
|
StringCchCopyW( pFileRec->TraceName, lstrlenW(pName)+1, pName );
|
||
|
}
|
||
|
|
||
|
pName += lstrlenW( pName ) + 1;
|
||
|
pFileRec->FileName = (LPWSTR)malloc( ( lstrlenW(pName)+1 )*sizeof(WCHAR) );
|
||
|
if( pFileRec->FileName != NULL ){
|
||
|
StringCchCopyW( pFileRec->FileName, lstrlenW(pName)+1, pName );
|
||
|
}
|
||
|
pFileRec->StartTime = HeaderStartTime;
|
||
|
pFileRec->EndTime = pEvmInfo->EndTime.QuadPart;
|
||
|
InsertTailList( &CurrentSystem.ProcessFileListHead, &pFileRec->Entry );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
IoWriteCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
ULONG DiskNumber= 0;
|
||
|
ULONG BytesWrite=0;
|
||
|
PTDISK_RECORD Disk;
|
||
|
PPROCESS_RECORD pProcess, pDiskProcess;
|
||
|
PPROTO_PROCESS_RECORD pProto;
|
||
|
PFILE_OBJECT fileObj;
|
||
|
PFILE_RECORD pProcFile;
|
||
|
PVOID fDO = NULL;
|
||
|
ULONG IrpFlags = 0;
|
||
|
LONGLONG ByteOffset = 0;
|
||
|
ULONG pFlag = FALSE;
|
||
|
BOOLEAN fValidWrite = (BOOLEAN) (!fDSOnly ||
|
||
|
( ((ULONGLONG) pHeader->TimeStamp.QuadPart >= DSStartTime)
|
||
|
&& ((ULONGLONG) pHeader->TimeStamp.QuadPart <= DSEndTime)));
|
||
|
|
||
|
|
||
|
GetMofData(pEvent, L"DiskNumber", &DiskNumber, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"IrpFlags", &IrpFlags, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"TransferSize", &BytesWrite, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"FileObject", &fDO, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ByteOffset", &ByteOffset, sizeof(LONGLONG));
|
||
|
|
||
|
if (((IrpFlags & IRP_PAGING_IO) != 0) ||
|
||
|
((IrpFlags & IRP_SYNCHRONOUS_PAGING_IO) != 0)) {
|
||
|
pFlag = TRUE;
|
||
|
}
|
||
|
|
||
|
if ((Disk = FindGlobalDiskById(DiskNumber)) == NULL) {
|
||
|
if ( !AddDisk(DiskNumber, &Disk) ) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
BytesWrite /= 1024; // Convert to Kbytes.
|
||
|
|
||
|
if (fValidWrite)
|
||
|
{
|
||
|
Disk->WriteCount++;
|
||
|
Disk->WriteSize += BytesWrite;
|
||
|
}
|
||
|
|
||
|
if (pThread == NULL) {
|
||
|
|
||
|
//
|
||
|
// Logger Thread Creation is MISSED by the collector.
|
||
|
// So we must handle it here.
|
||
|
//
|
||
|
if (AddThread( pHeader->ThreadId, pEvent, &pThread )) {
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Thread %x added to charge IO Write event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
pThread->pProcess = FindProcessById(0, TRUE); // Charge it the system ???
|
||
|
pThread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
pThread->fOrphan = TRUE;
|
||
|
//
|
||
|
// Note: All ThreadStart record at the start of data collection
|
||
|
// have the same TID in the header and in the Aux Fields.
|
||
|
// Real ThreadStart events will have the Parent threadId in the
|
||
|
// header and the new ThreadId in the Aux Field.
|
||
|
//
|
||
|
pThread->KCPUStart = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pHeader->UserTime;
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
else {
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for IO Write Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else if (pThread->fOrphan)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): IO Write Event Thread %x Is Still Orphan.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
else if (pThread->DeadFlag)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): IO Write Event Thread %x Is Already Dead.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
if (fValidWrite)
|
||
|
{
|
||
|
if (pThread->pMofData != NULL) {
|
||
|
((PMOF_DATA)pThread->pMofData)->WriteCount++;
|
||
|
}
|
||
|
pThread->WriteIO++;
|
||
|
pThread->WriteIOSize += BytesWrite;
|
||
|
}
|
||
|
|
||
|
// 2. Disk->Process
|
||
|
//
|
||
|
|
||
|
pDiskProcess = FindDiskProcessById(Disk, pThread->pProcess->PID);
|
||
|
if (fValidWrite && pDiskProcess != NULL) {
|
||
|
if (pFlag) {
|
||
|
pDiskProcess->HPF++;
|
||
|
pDiskProcess->HPFSize += BytesWrite;
|
||
|
}
|
||
|
else {
|
||
|
pDiskProcess->WriteIO++;
|
||
|
pDiskProcess->WriteIOSize += BytesWrite;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add the I/O to the process that owns the causing thread.
|
||
|
//
|
||
|
pProcess = pThread->pProcess;
|
||
|
if (fValidWrite && (pProcess != NULL ) ) {
|
||
|
pProcess->WriteIO++;
|
||
|
pProcess->WriteIOSize += BytesWrite;
|
||
|
Disk = FindProcessDiskById(pProcess, DiskNumber);
|
||
|
if (Disk != NULL) {
|
||
|
|
||
|
Disk->WriteCount++;
|
||
|
Disk->WriteSize += BytesWrite;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Thread Local Disk.
|
||
|
//
|
||
|
Disk = FindLocalDiskById(&pThread->DiskListHead, DiskNumber);
|
||
|
if (fValidWrite && Disk != NULL) {
|
||
|
Disk->WriteCount++;
|
||
|
Disk->WriteSize += BytesWrite;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now add this I/O the file it came from
|
||
|
//
|
||
|
|
||
|
if (fValidWrite)
|
||
|
{
|
||
|
fileObj = FindFileInTable(fDO);
|
||
|
if (fileObj == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
fileObj->ThreadId = pEvent->Header.ThreadId;
|
||
|
fileObj->LastByteOffset = ByteOffset;
|
||
|
fileObj->DiskNumber = DiskNumber;
|
||
|
if (fileObj->fileRec != NULL) {
|
||
|
fileObj->fileRec->WriteCount++;
|
||
|
fileObj->fileRec->WriteSize += BytesWrite;
|
||
|
|
||
|
pProcFile = FindFileInProcess(pProcess, fileObj->fileRec->FileName);
|
||
|
if (pProcFile != NULL) {
|
||
|
pProcFile->WriteCount++;
|
||
|
pProcFile->WriteSize += BytesWrite;
|
||
|
}
|
||
|
pProto = FindProtoProcessRecord(fileObj->fileRec, pProcess);
|
||
|
if (pProto != NULL) {
|
||
|
pProto->WriteCount++;
|
||
|
pProto->WriteSize += BytesWrite;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// APC has not happened yet. So Make a copy of the pEvent.
|
||
|
// and Insert it in EventListHead;
|
||
|
|
||
|
AddEvent(fileObj, DiskNumber, BytesWrite, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pFlag || (IrpFlags & IRP_ASSOCIATED_IRP) != 0)
|
||
|
{
|
||
|
PHPF_FILE_RECORD pHPFFileRecord = NULL;
|
||
|
|
||
|
HPFWriteCount ++;
|
||
|
if ( fValidWrite
|
||
|
&& AddHPFFileRecord(& pHPFFileRecord, HPFWriteCount, IrpFlags,
|
||
|
DiskNumber, ByteOffset, BytesWrite, fDO))
|
||
|
{
|
||
|
EnterTracelibCritSection();
|
||
|
InsertHeadList(& pThread->HPFWriteListHead,
|
||
|
& pHPFFileRecord->Entry);
|
||
|
LeaveTracelibCritSection();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PsStartCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG ProcessId=0;
|
||
|
ULONG ReadId = 0;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PCHAR ImageName;
|
||
|
ULONG returnLength, requiredLength;
|
||
|
CHAR UserName[64];
|
||
|
CHAR Domain[64];
|
||
|
CHAR FullName[256];
|
||
|
ULONG RetLength;
|
||
|
DWORD asize = 0;
|
||
|
DWORD bsize = 0;
|
||
|
ULONG Sid[64];
|
||
|
PULONG pSid = &Sid[0];
|
||
|
SID_NAME_USE Se;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
RetLength = GetMofData(pEvent, L"ProcessId", &ReadId, sizeof(ULONG));
|
||
|
// if (RetLength == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
ProcessId = ReadId;
|
||
|
pProcess = FindProcessById(ProcessId, FALSE);
|
||
|
// if real thread events get fired first before process start,
|
||
|
// we may already have Process structure created.
|
||
|
if ( pProcess == NULL ) {
|
||
|
AddProcess(ProcessId, &pProcess);
|
||
|
}
|
||
|
else {
|
||
|
if ( pProcess->ImageName != NULL ) {
|
||
|
free(pProcess->ImageName);
|
||
|
pProcess->ImageName = NULL;
|
||
|
}
|
||
|
if ( pProcess->UserName != NULL ) {
|
||
|
free(pProcess->UserName);
|
||
|
pProcess->UserName = NULL;
|
||
|
}
|
||
|
}
|
||
|
if ( pProcess != NULL ) {
|
||
|
//
|
||
|
// If the Data Collection Start Time and the Process Start Time
|
||
|
// match, then the PsStart was created by the ProcessRunDown
|
||
|
// Code. So Keep the CPU Times to compute the difference at the
|
||
|
// end. Otherwise, zero the starting CPU Times.
|
||
|
//
|
||
|
pProcess->PID = ProcessId;
|
||
|
// try with 16 bytes for image name first.
|
||
|
ImageName = (PCHAR)malloc(16 * sizeof(CHAR));
|
||
|
if (ImageName == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
RtlZeroMemory(ImageName, 16 * sizeof(CHAR));
|
||
|
returnLength = 16 * sizeof(CHAR);
|
||
|
requiredLength = GetMofData(pEvent, L"ImageFileName", ImageName, returnLength);
|
||
|
if (requiredLength > returnLength) {
|
||
|
free(ImageName);
|
||
|
ImageName = (PCHAR)malloc(requiredLength);
|
||
|
if (ImageName == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
RtlZeroMemory(ImageName, requiredLength);
|
||
|
GetMofData(pEvent, L"ImageFileName", ImageName, requiredLength);
|
||
|
}
|
||
|
|
||
|
asize = lstrlenA(ImageName);
|
||
|
if (asize > 0) {
|
||
|
pProcess->ImageName = (LPWSTR)malloc((asize + 1) * sizeof(WCHAR));
|
||
|
if (pProcess->ImageName == NULL) {
|
||
|
free(ImageName);
|
||
|
return;
|
||
|
}
|
||
|
//
|
||
|
// Process hook has the image name as ASCII. So we need to
|
||
|
// convert it to unicode here.
|
||
|
//
|
||
|
AnsiToUnicode(ImageName, pProcess->ImageName);
|
||
|
}
|
||
|
else {
|
||
|
pProcess->ImageName = (LPWSTR)malloc(MAXSTR * sizeof(WCHAR));
|
||
|
if (pProcess->ImageName == NULL) {
|
||
|
free(ImageName);
|
||
|
return;
|
||
|
}
|
||
|
if (ProcessId == 0)
|
||
|
{
|
||
|
StringCchCopyW(pProcess->ImageName, MAXSTR, L"Idle");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringCchPrintfW(pProcess->ImageName,
|
||
|
MAXSTR,
|
||
|
L"Unknown(0x%08X)",
|
||
|
ProcessId);
|
||
|
}
|
||
|
}
|
||
|
free(ImageName);
|
||
|
|
||
|
GetMofData(pEvent, L"UserSID", pSid, 64);
|
||
|
|
||
|
asize = 64; bsize = 64;
|
||
|
if (LookupAccountSidA(NULL,
|
||
|
pSid,
|
||
|
&UserName[0],
|
||
|
&asize,
|
||
|
&Domain[0],
|
||
|
&bsize,
|
||
|
&Se)) {
|
||
|
char* pFullName = &FullName[0];
|
||
|
StringCchCopyA(pFullName, 256, "\\\\");
|
||
|
StringCchCatA(pFullName, 256, Domain);
|
||
|
StringCchCatA(pFullName, 256, "\\");
|
||
|
StringCchCatA(pFullName, 256, UserName);
|
||
|
asize = lstrlenA(pFullName);
|
||
|
if (asize > 0) {
|
||
|
pProcess->UserName = (LPWSTR)malloc((asize + 1) * sizeof(WCHAR));
|
||
|
if (pProcess->UserName != NULL) {
|
||
|
AnsiToUnicode(pFullName, pProcess->UserName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pProcess->UserName = (LPWSTR)malloc(7 * sizeof(WCHAR));
|
||
|
if (pProcess->UserName != NULL) {
|
||
|
StringCchCopyW(pProcess->UserName, 7, L"system");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PsEndCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG ProcessId;
|
||
|
ULONG ReadId = 0;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PCHAR ImageName;
|
||
|
ULONG returnLength, requiredLength;
|
||
|
CHAR UserName[64];
|
||
|
CHAR Domain[64];
|
||
|
CHAR FullName[256];
|
||
|
DWORD asize = 0;
|
||
|
DWORD bsize = 0;
|
||
|
ULONG RetLength;
|
||
|
|
||
|
ULONG Sid[64];
|
||
|
PULONG pSid = &Sid[0];
|
||
|
SID_NAME_USE Se;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
RetLength = GetMofData(pEvent, L"ProcessId", &ReadId, sizeof(ULONG));
|
||
|
// if (RetLength == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
ProcessId = ReadId;
|
||
|
|
||
|
if ( (pProcess = FindProcessById(ProcessId, TRUE)) != NULL )
|
||
|
{
|
||
|
if (pProcess->DeadFlag)
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): End Process %x Dead Already!\n",
|
||
|
EventCount, ProcessId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pProcess->DeadFlag = TRUE;
|
||
|
// try with 16 bytes for image name first.
|
||
|
ImageName = (PCHAR)malloc(16 * sizeof(CHAR));
|
||
|
if (ImageName == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
RtlZeroMemory(ImageName, 16 * sizeof(CHAR));
|
||
|
returnLength = 16 * sizeof(CHAR);
|
||
|
requiredLength = GetMofData(pEvent, L"ImageFileName", ImageName, returnLength);
|
||
|
if (requiredLength > returnLength) {
|
||
|
free(ImageName);
|
||
|
ImageName = (PCHAR)malloc(requiredLength);
|
||
|
if (ImageName == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
RtlZeroMemory(ImageName, requiredLength);
|
||
|
GetMofData(pEvent, L"ImageFileName", ImageName, requiredLength);
|
||
|
}
|
||
|
|
||
|
asize = lstrlenA(ImageName);
|
||
|
if (asize > 0)
|
||
|
{
|
||
|
if (pProcess->ImageName != NULL) {
|
||
|
free(pProcess->ImageName);
|
||
|
}
|
||
|
pProcess->ImageName = (LPWSTR)malloc((asize + 1) * sizeof(WCHAR));
|
||
|
if (pProcess->ImageName != NULL) {
|
||
|
AnsiToUnicode(ImageName, pProcess->ImageName);
|
||
|
}
|
||
|
}
|
||
|
free(ImageName);
|
||
|
|
||
|
GetMofData(pEvent, L"UserSID", pSid, 64);
|
||
|
|
||
|
asize = 64; bsize = 64;
|
||
|
if (LookupAccountSidA(NULL,
|
||
|
pSid,
|
||
|
&UserName[0],
|
||
|
&asize,
|
||
|
&Domain[0],
|
||
|
&bsize,
|
||
|
&Se)) {
|
||
|
char* pFullName = &FullName[0];
|
||
|
StringCchCopyA(pFullName, 256, "\\\\");
|
||
|
StringCchCatA(pFullName, 256, Domain);
|
||
|
StringCchCatA(pFullName, 256, "\\");
|
||
|
StringCchCatA(pFullName, 256, UserName);
|
||
|
asize = lstrlenA(pFullName);
|
||
|
if (asize > 0)
|
||
|
{
|
||
|
if (pProcess->UserName != NULL)
|
||
|
{
|
||
|
free(pProcess->UserName);
|
||
|
}
|
||
|
pProcess->UserName = (LPWSTR)malloc((asize + 1) * sizeof(WCHAR));
|
||
|
if (pProcess->UserName != NULL) {
|
||
|
AnsiToUnicode(pFullName, pProcess->UserName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pProcess->UserName != NULL)
|
||
|
{
|
||
|
free(pProcess->UserName);
|
||
|
}
|
||
|
pProcess->UserName = (LPWSTR)malloc(7 * sizeof(WCHAR));
|
||
|
if (pProcess->UserName != NULL) {
|
||
|
StringCchCopyW(pProcess->UserName, 7, L"system");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else {
|
||
|
DbgPrint("WARNING(%d): PsEnd for Unknown process %x Ignored!\n",
|
||
|
EventCount, ProcessId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ThStartCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG ProcessorId;
|
||
|
ULONG ProcessId, ThreadId;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PTHREAD_RECORD Thread;
|
||
|
|
||
|
ULONG ReadId = 0;
|
||
|
ULONG RetLength;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
RetLength = GetMofData(pEvent, L"TThreadId", &ReadId, sizeof(ULONG));
|
||
|
// if (RetLength == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
ProcessorId = pEvent->ClientContext & 0x000000FF;
|
||
|
ThreadId = ReadId;
|
||
|
RetLength = GetMofData(pEvent, L"ProcessId", &ReadId, sizeof(ULONG));
|
||
|
// if (RetLength == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
ProcessId = ReadId;
|
||
|
pProcess = FindProcessById(ProcessId, TRUE);
|
||
|
if (pProcess == NULL)
|
||
|
{
|
||
|
// This should not Happen. The PS hooks are supposed to guarantee
|
||
|
// that the process create happens before the thread creates
|
||
|
// for that process.
|
||
|
//
|
||
|
if (!AddProcess(ProcessId, &pProcess))
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Can not find Process Start Record Th %x PID %x\n",
|
||
|
EventCount, ThreadId, ProcessId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ThreadId == 0 && ProcessorId == 0)
|
||
|
{
|
||
|
pEvent->ClientContext += CurrentSystem.CurrentThread0 ++;
|
||
|
//ASSERT( CurrentSystem.CurrentThread0 <= CurrentSystem.NumberOfProcessors );
|
||
|
}
|
||
|
|
||
|
Thread = FindGlobalThreadById(ThreadId, pEvent);
|
||
|
if (ThreadId != 0 && Thread != NULL && !Thread->DeadFlag)
|
||
|
{
|
||
|
if (Thread->fOrphan)
|
||
|
{
|
||
|
Thread->fOrphan = FALSE;
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("INFO(%d): Attach orphan thread %x to process %x.\n",
|
||
|
EventCount, ThreadId, ProcessId);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EVENT_TRACE event;
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Two active thread have the same TID %x.\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
event.Header.TimeStamp.QuadPart = pHeader->TimeStamp.QuadPart;
|
||
|
event.Header.Class.Type = EVENT_TRACE_TYPE_END;
|
||
|
event.Header.ThreadId = ThreadId;
|
||
|
event.Header.UserTime = Thread->UCPUEnd;
|
||
|
event.Header.KernelTime = Thread->KCPUEnd;
|
||
|
|
||
|
//
|
||
|
// If a DCStart event with non-zero KCPU and UCPU is paired up with
|
||
|
// an end Event for the same ThreadId with less CPU Times, the delta
|
||
|
// can come out negative. We correct it here.
|
||
|
//
|
||
|
|
||
|
if (Thread->KCPUEnd < Thread->KCPUStart)
|
||
|
Thread->KCPUEnd = Thread->KCPUStart;
|
||
|
if (Thread->UCPUEnd < Thread->UCPUStart)
|
||
|
Thread->UCPUEnd = Thread->UCPUStart;
|
||
|
|
||
|
ThEndCallback(&event);
|
||
|
|
||
|
if (!AddThread(ThreadId, pEvent, &Thread))
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add global active thread TID %x.\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (!AddThread(ThreadId, pEvent, &Thread)) {
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add global active thread TID %x.\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Thread->pProcess = pProcess;
|
||
|
Thread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
|
||
|
// Note: All ThreadStart record at the start of data collection
|
||
|
// have the same TID in the header and in the Aux Fields.
|
||
|
// Real ThreadStart events will have the Parent threadId in the
|
||
|
// header and the new ThreadId in the Aux Field.
|
||
|
//
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START)
|
||
|
{
|
||
|
Thread->KCPUStart = pHeader->KernelTime;
|
||
|
Thread->UCPUStart = pHeader->UserTime;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Thread->KCPUStart = 0;
|
||
|
Thread->UCPUStart = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// For DCStart type, the TID in the pEvent and the new thread
|
||
|
// match. So we can adjust its ThreadTimes.
|
||
|
//
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START) {
|
||
|
AdjustThreadTime(pEvent, Thread);
|
||
|
}
|
||
|
else {
|
||
|
AdjustThreadTime(pEvent, NULL);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
Thread->KCPU_Trans = 0;
|
||
|
Thread->KCPU_NoTrans = 0;
|
||
|
Thread->UCPU_Trans = 0;
|
||
|
Thread->UCPU_NoTrans = 0;
|
||
|
Thread->TransLevel = 0;
|
||
|
Thread->KCPU_PrevTrans = Thread->KCPUStart;
|
||
|
Thread->UCPU_PrevTrans = Thread->UCPUStart;
|
||
|
}
|
||
|
|
||
|
if (Thread->TID == 0 && CurrentSystem.BuildNumber <= 1877)
|
||
|
{
|
||
|
CurrentSystem.NumberOfProcessors++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ShutdownThreads()
|
||
|
{
|
||
|
int i;
|
||
|
EVENT_TRACE event;
|
||
|
PLIST_ENTRY Head,Next;
|
||
|
PTHREAD_RECORD Thread;
|
||
|
|
||
|
RtlZeroMemory(&event, sizeof(EVENT_TRACE));
|
||
|
if (CurrentSystem.EndTime > CurrentSystem.LastEventTime) {
|
||
|
event.Header.TimeStamp.QuadPart = CurrentSystem.EndTime;
|
||
|
}
|
||
|
else {
|
||
|
event.Header.TimeStamp.QuadPart = CurrentSystem.LastEventTime;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move the Thread list from the HashTable to GlobalList
|
||
|
//
|
||
|
|
||
|
for (i=0; i < THREAD_HASH_TABLESIZE; i++) {
|
||
|
Head = &CurrentSystem.ThreadHashList[i];
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry );
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
if (!Thread->DeadFlag){
|
||
|
event.Header.Class.Type = EVENT_TRACE_TYPE_DC_END;
|
||
|
event.Header.ThreadId = Thread->TID;
|
||
|
event.Header.UserTime = Thread->UCPUEnd;
|
||
|
event.Header.KernelTime = Thread->KCPUEnd;
|
||
|
ThEndCallback( &event );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ShutdownProcesses()
|
||
|
{
|
||
|
PLIST_ENTRY pHead = &CurrentSystem.ProcessListHead;
|
||
|
PLIST_ENTRY pNext = pHead->Flink;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
|
||
|
while (pNext != pHead){
|
||
|
pProcess = CONTAINING_RECORD(pNext, PROCESS_RECORD, Entry);
|
||
|
pNext = pNext->Flink;
|
||
|
|
||
|
if (!pProcess->DeadFlag){
|
||
|
pProcess->DeadFlag = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
StopThreadTrans(
|
||
|
PLIST_ENTRY Head,
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PTRANS_RECORD pTrans;
|
||
|
PLIST_ENTRY Next = Head->Flink;
|
||
|
while( Head != Next ){
|
||
|
pTrans = CONTAINING_RECORD(Next, TRANS_RECORD, Entry);
|
||
|
Next = Next->Flink;
|
||
|
if( !StopThreadTrans( &pTrans->SubTransListHead, pEvent, pThread ) ){
|
||
|
return FALSE;
|
||
|
}
|
||
|
if( !pTrans->bStarted ){
|
||
|
continue;
|
||
|
}
|
||
|
RtlCopyMemory( &pEvent->Header.Guid, pTrans->pGuid, sizeof(GUID));
|
||
|
pEvent->Header.Class.Type = EVENT_TRACE_TYPE_END;
|
||
|
EventCallback( pEvent, pThread );
|
||
|
return FALSE; // stopping one will credit all running events
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ThEndCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG ThreadId;
|
||
|
PTHREAD_RECORD Thread;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
ThreadId = pHeader->ThreadId;
|
||
|
|
||
|
if (ThreadId == 0)
|
||
|
{
|
||
|
ULONG ProcessorId = pEvent->ClientContext & 0x000000FF;
|
||
|
if (ProcessorId == 0) {
|
||
|
pEvent->ClientContext += (CurrentSystem.NumberOfProcessors
|
||
|
- (CurrentSystem.CurrentThread0 --));
|
||
|
}
|
||
|
}
|
||
|
Thread = FindGlobalThreadById(ThreadId, pEvent);
|
||
|
|
||
|
if (Thread != NULL)
|
||
|
{
|
||
|
if (Thread->DeadFlag)
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Thread %x Dead Already\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Thread->fOrphan)
|
||
|
{
|
||
|
ULONG ReadId = 0;
|
||
|
ULONG ProcessId = 0;
|
||
|
PPROCESS_RECORD pProcess = NULL;
|
||
|
|
||
|
GetMofData(pEvent, L"ProcessId", &ReadId, sizeof(ULONG));
|
||
|
ProcessId = ReadId;
|
||
|
|
||
|
pProcess = FindProcessById(ProcessId, TRUE);
|
||
|
if (pProcess != NULL)
|
||
|
{
|
||
|
Thread->fOrphan = FALSE;
|
||
|
Thread->pProcess = pProcess;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("INFO(%d): ThEndCallback() attach orphan thread %X to process %X\n",
|
||
|
EventCount, ThreadId, ProcessId);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
//
|
||
|
// Charge any unstopped transactions
|
||
|
//
|
||
|
if ( Thread != NULL
|
||
|
&& pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_END)
|
||
|
{
|
||
|
StopThreadTrans(&Thread->TransListHead, pEvent, Thread );
|
||
|
}
|
||
|
|
||
|
Thread->DeadFlag = TRUE;
|
||
|
if (fDSOnly)
|
||
|
{
|
||
|
if ((ULONGLONG) pHeader->TimeStamp.QuadPart > DSEndTime)
|
||
|
{
|
||
|
Thread->TimeEnd = DSEndTime;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Thread->KCPUEnd = pHeader->KernelTime;
|
||
|
Thread->UCPUEnd = pHeader->UserTime;
|
||
|
Thread->TimeEnd = (ULONGLONG) pHeader->TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (Thread->UCPUEnd < pHeader->UserTime)
|
||
|
Thread->UCPUEnd = pHeader->UserTime;
|
||
|
if (Thread->KCPUEnd < pHeader->KernelTime)
|
||
|
Thread->KCPUEnd = pHeader->KernelTime;
|
||
|
Thread->TimeEnd = pHeader->TimeStamp.QuadPart;
|
||
|
}
|
||
|
|
||
|
if (Thread->TransLevel <= 0)
|
||
|
{
|
||
|
Thread->KCPU_NoTrans += Thread->KCPUEnd - Thread->KCPU_PrevTrans;
|
||
|
Thread->UCPU_NoTrans += Thread->UCPUEnd - Thread->UCPU_PrevTrans;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Thread->KCPU_Trans += Thread->KCPUEnd - Thread->KCPU_PrevTrans;
|
||
|
Thread->UCPU_Trans += Thread->UCPUEnd - Thread->UCPU_PrevTrans;
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Active Transactions in Dead Thread %x\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): No Thread Start for ThreadId %x\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
if (AddThread(ThreadId, pEvent, &Thread))
|
||
|
{
|
||
|
Thread->pProcess = FindProcessById(0, FALSE);
|
||
|
Thread->DeadFlag = TRUE;
|
||
|
Thread->fOrphan = TRUE;
|
||
|
Thread->TimeStart = Thread->TimeEnd = pHeader->TimeStamp.QuadPart;
|
||
|
Thread->KCPUStart = Thread->KCPUEnd = pHeader->KernelTime;
|
||
|
Thread->UCPUStart = Thread->UCPUEnd = pHeader->UserTime;
|
||
|
AdjustThreadTime(pEvent, Thread);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for ThreadEnd Event.\n",
|
||
|
EventCount, ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
IoReadCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader = (EVENT_TRACE_HEADER*)&pEvent->Header;
|
||
|
ULONG DiskNumber=0;
|
||
|
ULONG BytesRead=0;
|
||
|
ULONG IrpFlags=0;
|
||
|
PTDISK_RECORD Disk;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PPROTO_PROCESS_RECORD pProto;
|
||
|
PFILE_OBJECT fileObj;
|
||
|
PFILE_RECORD pProcFile;
|
||
|
PVOID fDO;
|
||
|
BOOLEAN pFlag = FALSE;
|
||
|
PPROCESS_RECORD pDiskProcess;
|
||
|
LONGLONG ByteOffset;
|
||
|
BOOLEAN fValidRead = (BOOLEAN) (!fDSOnly ||
|
||
|
( ((ULONGLONG) pHeader->TimeStamp.QuadPart >= DSStartTime)
|
||
|
&& ((ULONGLONG) pHeader->TimeStamp.QuadPart <= DSEndTime)));
|
||
|
|
||
|
GetMofData(pEvent, L"DiskNumber", &DiskNumber, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"IrpFlags", &IrpFlags, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"TransferSize", &BytesRead, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"FileObject", &fDO, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ByteOffset", &ByteOffset, sizeof(ULONGLONG));
|
||
|
|
||
|
BytesRead /= 1024; // Convert to Kbytes
|
||
|
|
||
|
if (((IrpFlags & IRP_PAGING_IO) != 0) ||
|
||
|
((IrpFlags & IRP_SYNCHRONOUS_PAGING_IO) != 0)) {
|
||
|
pFlag = TRUE;
|
||
|
}
|
||
|
//
|
||
|
// TODO: From DiskNumber and Offset get the Logical Disk
|
||
|
// ie., DiskNumber = MapDisk(DiskIndex, Offset);
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Add the I/O to the DISK
|
||
|
//
|
||
|
|
||
|
if ((Disk = FindGlobalDiskById(DiskNumber)) == NULL) {
|
||
|
if (!AddDisk(DiskNumber, &Disk) ) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fValidRead)
|
||
|
{
|
||
|
if (pFlag) {
|
||
|
Disk->HPF++;
|
||
|
Disk->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
Disk->ReadCount++;
|
||
|
Disk->ReadSize += BytesRead;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the I/O to the THREAD
|
||
|
//
|
||
|
|
||
|
if ( pThread == NULL) {
|
||
|
|
||
|
//
|
||
|
// NOTE: Logger Thread Creation is MISSED by the collector.
|
||
|
// So we must handle it here.
|
||
|
//
|
||
|
if (AddThread(pHeader->ThreadId, pEvent, &pThread )) {
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Thread %x added to charge IO Read event\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
pThread->pProcess = FindProcessById(0, TRUE); // Charge it the system ???
|
||
|
pThread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
pThread->fOrphan = TRUE;
|
||
|
//
|
||
|
// Note: All ThreadStart record at the start of data collection
|
||
|
// have the same TID in the header and in the Aux Fields.
|
||
|
// Real ThreadStart events will have the Parent threadId in the
|
||
|
// header and the new ThreadId in the Aux Field.
|
||
|
//
|
||
|
pThread->KCPUStart = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pHeader->UserTime;
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
else {
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for IO Read Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else if (pThread->fOrphan)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): IO Read Event Thread %x Is Still Orphan.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
else if (pThread->DeadFlag)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): IO Read Event Thread %x Is Already Dead.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
ASSERT(pThread != NULL);
|
||
|
|
||
|
if (fValidRead && pThread->pMofData != NULL) {
|
||
|
((PMOF_DATA)pThread->pMofData)->ReadCount++;
|
||
|
}
|
||
|
|
||
|
if (fValidRead)
|
||
|
{
|
||
|
if (pFlag) {
|
||
|
pThread->HPF++;
|
||
|
pThread->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
pThread->ReadIO++;
|
||
|
pThread->ReadIOSize += BytesRead;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 2. Disk->Process
|
||
|
//
|
||
|
|
||
|
pDiskProcess = FindDiskProcessById(Disk, pThread->pProcess->PID);
|
||
|
if (fValidRead && pDiskProcess != NULL) {
|
||
|
if (pFlag) {
|
||
|
pDiskProcess->HPF++;
|
||
|
pDiskProcess->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
pDiskProcess->ReadIO++;
|
||
|
pDiskProcess->ReadIOSize += BytesRead;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the I/O to the PROCESS
|
||
|
//
|
||
|
pProcess = pThread->pProcess;
|
||
|
if (fValidRead && (pProcess != NULL )) {
|
||
|
pProcess->ReadIO++;
|
||
|
pProcess->ReadIOSize += BytesRead;
|
||
|
|
||
|
Disk = FindProcessDiskById(pProcess, DiskNumber);
|
||
|
if (Disk != NULL) {
|
||
|
if (pFlag) {
|
||
|
Disk->HPF++;
|
||
|
Disk->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
Disk->ReadCount++;
|
||
|
Disk->ReadSize += BytesRead;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the I/O to the FILE
|
||
|
//
|
||
|
if (fValidRead)
|
||
|
{
|
||
|
fileObj = FindFileInTable(fDO);
|
||
|
if (fileObj == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
fileObj->ThreadId = pEvent->Header.ThreadId;
|
||
|
fileObj->LastByteOffset = ByteOffset;
|
||
|
fileObj->DiskNumber = DiskNumber;
|
||
|
if (fileObj->fileRec) {
|
||
|
fileObj->fileRec->ReadCount++;
|
||
|
fileObj->fileRec->ReadSize += BytesRead;
|
||
|
pProcFile = FindFileInProcess(pProcess, fileObj->fileRec->FileName);
|
||
|
if (pProcFile != NULL) {
|
||
|
#if 0
|
||
|
if (pFlag) {
|
||
|
pProcFile->HPF++;
|
||
|
pProcFile->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
#endif
|
||
|
pProcFile->ReadCount++;
|
||
|
pProcFile->ReadSize += BytesRead;
|
||
|
#if 0
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
pProto = FindProtoProcessRecord(fileObj->fileRec, pProcess);
|
||
|
if (pProto != NULL) {
|
||
|
#if 0
|
||
|
if (pFlag) {
|
||
|
pProto->HPF++;
|
||
|
pProto->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
#endif
|
||
|
pProto->ReadCount++;
|
||
|
pProto->ReadSize += BytesRead;
|
||
|
#if 0
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// APC has not happened yet. So Make a copy of the pEvent.
|
||
|
// and Insert it in EventListHead;
|
||
|
AddEvent(fileObj, DiskNumber, BytesRead, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do the Drill Down Calls Now. To Save on memory we need to be
|
||
|
// selective about which ones to create.
|
||
|
//
|
||
|
|
||
|
|
||
|
// 2. Thread->Disk
|
||
|
|
||
|
Disk = FindLocalDiskById(&pThread->DiskListHead, DiskNumber);
|
||
|
if (fValidRead && Disk != NULL) {
|
||
|
if (pFlag) {
|
||
|
Disk->HPF++;
|
||
|
Disk->HPFSize += BytesRead;
|
||
|
}
|
||
|
else {
|
||
|
Disk->ReadCount++;
|
||
|
Disk->ReadSize += BytesRead;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pFlag || (IrpFlags & IRP_ASSOCIATED_IRP) != 0)
|
||
|
{
|
||
|
PHPF_FILE_RECORD pHPFFileRecord = NULL;
|
||
|
|
||
|
HPFReadCount ++;
|
||
|
if ( fValidRead
|
||
|
&& AddHPFFileRecord(& pHPFFileRecord, HPFReadCount, IrpFlags,
|
||
|
DiskNumber, ByteOffset, BytesRead, fDO))
|
||
|
{
|
||
|
EnterTracelibCritSection();
|
||
|
InsertHeadList(& pThread->HPFReadListHead,
|
||
|
& pHPFFileRecord->Entry);
|
||
|
LeaveTracelibCritSection();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
LogDriveCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
ULONGLONG StartOffset = 0;
|
||
|
ULONGLONG PartitionSize = 0;
|
||
|
ULONG DiskNumber = 0;
|
||
|
ULONG Size = 0;
|
||
|
ULONG DriveType = 0;
|
||
|
WCHAR DriveLetter[MAXSTR];
|
||
|
ULONG RetLength;
|
||
|
|
||
|
if (pEvent == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
DriveLetter[0] = UNICODE_NULL;
|
||
|
|
||
|
GetMofData(pEvent, L"StartOffset", &StartOffset, sizeof(ULONGLONG));
|
||
|
GetMofData(pEvent, L"PartitionSize", &PartitionSize, sizeof(ULONGLONG));
|
||
|
GetMofData(pEvent, L"DiskNumber", &DiskNumber, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"Size", &Size, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"DriveType", &DriveType, sizeof(SHORT));
|
||
|
RetLength = GetMofData(pEvent, L"DriveLetterString", &DriveLetter[0], MAXSTR*sizeof(WCHAR));
|
||
|
if (RetLength != 0 && RetLength > MAXSTR*sizeof(WCHAR)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
AddLogicalDrive(
|
||
|
StartOffset,
|
||
|
PartitionSize,
|
||
|
DiskNumber,
|
||
|
Size,
|
||
|
DriveType,
|
||
|
DriveLetter
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CpuCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
ULONG MemSize = 0;
|
||
|
WCHAR ComputerName[256];
|
||
|
ULONG ComputerNameSize = 0;
|
||
|
ULONG RetLength;
|
||
|
|
||
|
ComputerName[0] = UNICODE_NULL;
|
||
|
|
||
|
GetMofData(pEvent, L"MemSize", &MemSize, sizeof(ULONG));
|
||
|
CurrentSystem.MemorySize = MemSize;
|
||
|
RetLength = GetMofData(pEvent, L"ComputerName", &ComputerName[0], 256*sizeof(WCHAR));
|
||
|
if (RetLength != 0 && RetLength > MAXSTR*sizeof(WCHAR)) {
|
||
|
return;
|
||
|
}
|
||
|
ComputerNameSize = wcslen(ComputerName);
|
||
|
if (ComputerNameSize > 0) {
|
||
|
CurrentSystem.ComputerName = (LPWSTR)malloc((ComputerNameSize + 1) * sizeof(WCHAR));
|
||
|
if (CurrentSystem.ComputerName != NULL) {
|
||
|
StringCchCopyW(CurrentSystem.ComputerName, ComputerNameSize + 1, ComputerName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HotFileCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
WCHAR FileName[MAXSTR]; // Not Sure if this is sufficient...
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PFILE_RECORD fileRec, pProcFile = NULL;
|
||
|
PLOGICAL_DRIVE_RECORD pLogDrive = NULL;
|
||
|
PPROTO_FILE_RECORD protoFileRec;
|
||
|
PFILE_OBJECT fileObj;
|
||
|
PVOID fDO = NULL;
|
||
|
PTHREAD_RECORD pThread = NULL;
|
||
|
PPROCESS_RECORD pProcess = NULL;
|
||
|
PPROTO_PROCESS_RECORD pProto = NULL;
|
||
|
ULONG RetLength;
|
||
|
|
||
|
if (pEvent == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
RtlZeroMemory(&FileName[0], MAXSTR * sizeof(WCHAR));
|
||
|
|
||
|
GetMofData(pEvent, L"FileObject", &fDO, sizeof(PVOID));
|
||
|
RetLength = GetMofData(pEvent, L"FileName", &FileName[0], MAXSTR*sizeof(WCHAR));
|
||
|
if (RetLength != 0 && RetLength > MAXSTR*sizeof(WCHAR)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the FileObject from the fileTable and update the information.
|
||
|
//
|
||
|
|
||
|
fileObj = FindFileInTable(fDO);
|
||
|
if (fileObj == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pLogDrive = FindLogicalDrive(fileObj->LastByteOffset, fileObj->DiskNumber);
|
||
|
// pLogDrive can be null, and it should be OK.
|
||
|
if ((fileRec = FindFileRecordByName(FileName, pLogDrive)) == NULL) {
|
||
|
AddFile(FileName, &fileRec, pLogDrive);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (fileObj->fileRec != NULL) {
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("BUG: APC for known file %ws\n", FileName);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
if ((pThread = FindGlobalThreadById(fileObj->ThreadId, pEvent)) != NULL) {
|
||
|
pProcess = pThread->pProcess;
|
||
|
if (pProcess != NULL) {
|
||
|
pProcFile = FindFileInProcess(pProcess, FileName);
|
||
|
pProto = FindProtoProcessRecord(fileRec, pProcess);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fileObj->fileRec = fileRec;
|
||
|
|
||
|
//
|
||
|
// Walk through the EventList and add it to this file record
|
||
|
//
|
||
|
Head = &fileObj->ProtoFileRecordListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
protoFileRec = CONTAINING_RECORD( Next, PROTO_FILE_RECORD, Entry );
|
||
|
fileRec->DiskNumber = protoFileRec->DiskNumber;
|
||
|
if (protoFileRec->ReadFlag) {
|
||
|
fileRec->ReadCount++;
|
||
|
fileRec->ReadSize += protoFileRec->IoSize;
|
||
|
if (pProcFile != NULL) {
|
||
|
pProcFile->ReadCount++;
|
||
|
pProcFile->ReadSize += protoFileRec->IoSize;
|
||
|
}
|
||
|
if (pProto != NULL) {
|
||
|
pProto->ReadCount++;
|
||
|
pProto->ReadSize += protoFileRec->IoSize;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
fileRec->WriteCount++;
|
||
|
fileRec->WriteSize += protoFileRec->IoSize;
|
||
|
if (pProcFile != NULL) {
|
||
|
pProcFile->WriteCount++;
|
||
|
pProcFile->WriteSize += protoFileRec->IoSize;
|
||
|
}
|
||
|
if (pProto != NULL) {
|
||
|
pProto->WriteCount++;
|
||
|
pProto->WriteSize += protoFileRec->IoSize;
|
||
|
}
|
||
|
}
|
||
|
Next = Next->Flink;
|
||
|
RemoveEntryList( &protoFileRec->Entry);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If DrillDown Records are appended, we need to handle those too
|
||
|
//
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ModuleLoadCallback(PEVENT_TRACE pEvent)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header;
|
||
|
ULONG lBaseAddress = 0;
|
||
|
ULONG lModuleSize = 0;
|
||
|
WCHAR strModulePath[256];
|
||
|
WCHAR * strModuleName;
|
||
|
ULONG rtnLength = sizeof(WCHAR) * 256;
|
||
|
|
||
|
PLIST_ENTRY pHead = &CurrentSystem.GlobalModuleListHead;
|
||
|
PLIST_ENTRY pNext = pHead->Flink;
|
||
|
PMODULE_RECORD pMatched = NULL;
|
||
|
PMODULE_RECORD pCurrent = NULL;
|
||
|
PTHREAD_RECORD pThread = NULL;
|
||
|
PPROCESS_RECORD pProcess = NULL;
|
||
|
|
||
|
RtlZeroMemory(strModulePath, 256 * sizeof(WCHAR) );
|
||
|
GetMofData(pEvent, L"ImageBase", & lBaseAddress, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ImageSize", & lModuleSize, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"FileName", &strModulePath[0], rtnLength);
|
||
|
|
||
|
strModuleName = wcsrchr(strModulePath, L'\\');
|
||
|
if (!strModuleName){
|
||
|
strModuleName = strModulePath;
|
||
|
}else{
|
||
|
strModuleName ++;
|
||
|
}
|
||
|
|
||
|
// Check if loaded image is already in SYSTEM_RECORD::GlobalModuleListHead.
|
||
|
// Otherwise, insert new MODULE_RECORD.
|
||
|
//
|
||
|
while (!pMatched && pNext != pHead){
|
||
|
pMatched = CONTAINING_RECORD(pNext, MODULE_RECORD, Entry);
|
||
|
if (_wcsicmp(strModuleName, pMatched->strModuleName)){
|
||
|
pMatched = NULL;
|
||
|
pNext = pNext->Flink;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!pMatched){
|
||
|
if (AddModuleRecord(& pMatched, lBaseAddress, lModuleSize, strModuleName)){
|
||
|
EnterTracelibCritSection();
|
||
|
InsertHeadList(
|
||
|
& CurrentSystem.GlobalModuleListHead,
|
||
|
& pMatched->Entry);
|
||
|
LeaveTracelibCritSection();
|
||
|
pMatched->pProcess = NULL;
|
||
|
pMatched->pGlobalPtr = NULL;
|
||
|
}else{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(pMatched);
|
||
|
|
||
|
// Insert loaded image in PROCESS_RECORD::ModuleListHead
|
||
|
//
|
||
|
if (AddModuleRecord(& pCurrent, lBaseAddress, lModuleSize, strModuleName)){
|
||
|
pCurrent->pGlobalPtr = pMatched;
|
||
|
|
||
|
pThread = FindGlobalThreadById(pHeader->ThreadId, pEvent);
|
||
|
ASSERT(pThread);
|
||
|
if (!pThread){
|
||
|
free( pCurrent );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pProcess = pThread->pProcess;
|
||
|
ASSERT(pProcess);
|
||
|
if (!pProcess){
|
||
|
free( pCurrent );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
EnterTracelibCritSection();
|
||
|
pCurrent->pProcess = pProcess;
|
||
|
InsertHeadList( & pProcess->ModuleListHead, & pCurrent->Entry);
|
||
|
LeaveTracelibCritSection();
|
||
|
}else{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
if (pEvent == NULL){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_START) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START)) {
|
||
|
PsStartCallback(pEvent);
|
||
|
}
|
||
|
else if ((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_END) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_END)) {
|
||
|
PsEndCallback(pEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ThreadCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
if (pEvent == NULL){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_START) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START)) {
|
||
|
ThStartCallback(pEvent);
|
||
|
}
|
||
|
else if ((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_END) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_END)) {
|
||
|
ThEndCallback(pEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PMODULE_RECORD
|
||
|
SearchModuleByAddr(
|
||
|
PLIST_ENTRY pModuleListHead,
|
||
|
ULONG lAddress
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY pNext = pModuleListHead->Flink;
|
||
|
PMODULE_RECORD pModule = NULL;
|
||
|
PMODULE_RECORD pCurrent;
|
||
|
|
||
|
while (pNext != pModuleListHead)
|
||
|
{
|
||
|
pCurrent = CONTAINING_RECORD(pNext, MODULE_RECORD, Entry);
|
||
|
pNext = pNext->Flink;
|
||
|
if ( (lAddress >= pCurrent->lBaseAddress)
|
||
|
&& (lAddress < pCurrent->lBaseAddress + pCurrent->lModuleSize))
|
||
|
{
|
||
|
pModule = pCurrent;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return pModule;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
UpdatePageFaultCount(
|
||
|
PPROCESS_RECORD pProcess,
|
||
|
PMODULE_RECORD pModule,
|
||
|
ULONG lFaultAddr,
|
||
|
UCHAR FaultType)
|
||
|
{
|
||
|
BOOLEAN fFaultInImage = (BOOLEAN) ((lFaultAddr >= pModule->lBaseAddress)
|
||
|
&& (lFaultAddr < pModule->lBaseAddress
|
||
|
+ pModule->lModuleSize));
|
||
|
switch(FaultType)
|
||
|
{
|
||
|
case EVENT_TRACE_TYPE_MM_HPF :
|
||
|
if (fFaultInImage)
|
||
|
{
|
||
|
pProcess->lCodeFaultHF ++;
|
||
|
pModule->lCodeFaultHF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lCodeFaultHF ++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pProcess->lDataFaultHF ++;
|
||
|
pModule->lDataFaultHF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lDataFaultHF ++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EVENT_TRACE_TYPE_MM_TF :
|
||
|
if (fFaultInImage)
|
||
|
{
|
||
|
pProcess->lCodeFaultTF ++;
|
||
|
pModule->lCodeFaultTF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lCodeFaultTF ++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pProcess->lDataFaultTF ++;
|
||
|
pModule->lDataFaultTF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lDataFaultTF ++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EVENT_TRACE_TYPE_MM_DZF :
|
||
|
if (fFaultInImage)
|
||
|
{
|
||
|
pProcess->lCodeFaultDZF ++;
|
||
|
pModule->lCodeFaultDZF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lCodeFaultDZF ++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pProcess->lDataFaultDZF ++;
|
||
|
pModule->lDataFaultDZF ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lDataFaultDZF ++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EVENT_TRACE_TYPE_MM_COW :
|
||
|
if (fFaultInImage)
|
||
|
{
|
||
|
pProcess->lCodeFaultCOW ++;
|
||
|
pModule->lCodeFaultCOW ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lCodeFaultCOW ++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pProcess->lDataFaultCOW ++;
|
||
|
pModule->lDataFaultCOW ++;
|
||
|
if (pModule->pGlobalPtr)
|
||
|
{
|
||
|
pModule->pGlobalPtr->lDataFaultCOW ++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default :
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PMODULE_RECORD
|
||
|
SearchSysModule(
|
||
|
PPROCESS_RECORD pProcess,
|
||
|
ULONG lPC,
|
||
|
BOOLEAN fActive
|
||
|
)
|
||
|
{
|
||
|
PMODULE_RECORD pModule = NULL;
|
||
|
PPROCESS_RECORD pSysProcess = FindProcessById(0, fActive);
|
||
|
PMODULE_RECORD pCurrent =
|
||
|
SearchModuleByAddr(& pSysProcess->ModuleListHead, lPC);
|
||
|
if (pCurrent)
|
||
|
{
|
||
|
if (AddModuleRecord(& pModule,
|
||
|
pCurrent->lBaseAddress,
|
||
|
pCurrent->lModuleSize,
|
||
|
pCurrent->strModuleName))
|
||
|
{
|
||
|
EnterTracelibCritSection();
|
||
|
InsertHeadList(
|
||
|
& pProcess->ModuleListHead,
|
||
|
& pModule->Entry);
|
||
|
LeaveTracelibCritSection();
|
||
|
|
||
|
pModule->pProcess = pProcess;
|
||
|
pModule->pGlobalPtr = pCurrent->pGlobalPtr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pModule;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PageFaultCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PMOF_DATA pMofData;
|
||
|
ULONG lFaultAddr = 0;
|
||
|
ULONG lPC = 0;
|
||
|
PVOID fDO = NULL;
|
||
|
LONG lByteCount = 0;
|
||
|
LONGLONG lByteOffset = 0;
|
||
|
WCHAR strHotFileName[1024];
|
||
|
ULONG rtnLength = sizeof(WCHAR) * 1024;
|
||
|
BOOLEAN fSpecialHPF = FALSE;
|
||
|
BOOLEAN fFound;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
|
||
|
if (!InTimeWindow(pEvent, pThread))
|
||
|
return;
|
||
|
|
||
|
GetMofData(pEvent, L"VirtualAddress", &lFaultAddr, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ProgramCounter", &lPC, sizeof(ULONG));
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
if ( pHeader->Class.Type == EVENT_TRACE_TYPE_MM_HPF
|
||
|
&& pEvent->MofLength > 2 * sizeof(ULONG))
|
||
|
{
|
||
|
fSpecialHPF = TRUE;
|
||
|
GetMofData(pEvent, L"FileObject", &fDO, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ByteCount", &lByteCount, sizeof(LONG));
|
||
|
GetMofData(pEvent, L"ByteOffset", &lByteOffset, sizeof(LONGLONG));
|
||
|
GetMofData(pEvent, L"FileName", &strHotFileName[0], rtnLength);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (pThread == NULL)
|
||
|
{
|
||
|
if (AddThread(pHeader->ThreadId, pEvent, &pThread ))
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Thread %x added to charge PageFault event\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
pThread->pProcess = FindProcessById(0, TRUE);
|
||
|
pThread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
pThread->fOrphan = TRUE;
|
||
|
|
||
|
pThread->KCPUStart = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pHeader->UserTime;
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for PageFault Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else if (pThread->fOrphan)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): PageFault Event Thread %x Is Still Orphan.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
else if (pThread->DeadFlag)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): PageFault Event Thread %x Is Already Dead.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
pMofData = (PMOF_DATA)pThread->pMofData;
|
||
|
|
||
|
if (pMofData && !fSpecialHPF)
|
||
|
{
|
||
|
switch(pHeader->Class.Type)
|
||
|
{
|
||
|
case EVENT_TRACE_TYPE_MM_TF : pMofData->MmTf++; break;
|
||
|
case EVENT_TRACE_TYPE_MM_DZF : pMofData->MmDzf++; break;
|
||
|
case EVENT_TRACE_TYPE_MM_COW : pMofData->MmCow++; break;
|
||
|
case EVENT_TRACE_TYPE_MM_GPF : pMofData->MmGpf++; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update loaded image MODULE_RECORD::lFaultCount
|
||
|
//
|
||
|
pProcess = pThread->pProcess;
|
||
|
|
||
|
if (pProcess != NULL)
|
||
|
{
|
||
|
PMODULE_RECORD pModule = SearchModuleByAddr(
|
||
|
& pProcess->ModuleListHead,
|
||
|
lPC);
|
||
|
|
||
|
fFound = FALSE;
|
||
|
if (fSpecialHPF)
|
||
|
{
|
||
|
PHPF_RECORD pHPFRecord = NULL;
|
||
|
|
||
|
PageFaultCount ++;
|
||
|
if (AddHPFRecord(& pHPFRecord, lFaultAddr,
|
||
|
fDO, lByteCount, lByteOffset))
|
||
|
{
|
||
|
PLIST_ENTRY pHead = & pThread->HPFReadListHead;
|
||
|
PLIST_ENTRY pNext = pHead->Flink;
|
||
|
PHPF_FILE_RECORD pHPFFileRecord;
|
||
|
PHPF_FILE_RECORD pHPFThreadRead;
|
||
|
LONG lTotalByte = 0;
|
||
|
BOOLEAN fAssociatedIrp = TRUE;
|
||
|
|
||
|
EnterTracelibCritSection();
|
||
|
pHPFRecord->RecordID = PageFaultCount;
|
||
|
InsertHeadList(& pProcess->HPFListHead, & pHPFRecord->Entry);
|
||
|
while (fAssociatedIrp && pNext != pHead)
|
||
|
{
|
||
|
pHPFThreadRead = CONTAINING_RECORD(pNext,
|
||
|
HPF_FILE_RECORD,
|
||
|
Entry);
|
||
|
pNext = pNext->Flink;
|
||
|
fAssociatedIrp = (BOOLEAN) ((pHPFThreadRead->IrpFlags
|
||
|
& IRP_ASSOCIATED_IRP) != 0);
|
||
|
|
||
|
if (!fAssociatedIrp && fDO != pHPFThreadRead->fDO)
|
||
|
{
|
||
|
fAssociatedIrp = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (AddHPFFileRecord(& pHPFFileRecord,
|
||
|
pHPFThreadRead->RecordID,
|
||
|
pHPFThreadRead->IrpFlags,
|
||
|
pHPFThreadRead->DiskNumber,
|
||
|
pHPFThreadRead->ByteOffset,
|
||
|
pHPFThreadRead->BytesCount,
|
||
|
pHPFThreadRead->fDO))
|
||
|
{
|
||
|
lTotalByte += pHPFThreadRead->BytesCount;
|
||
|
InsertHeadList(& pHPFRecord->HPFReadListHead,
|
||
|
& pHPFFileRecord->Entry);
|
||
|
}
|
||
|
RemoveEntryList(& pHPFThreadRead->Entry);
|
||
|
free(pHPFThreadRead);
|
||
|
}
|
||
|
LeaveTracelibCritSection();
|
||
|
}
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
else if (pHeader->Class.Type == EVENT_TRACE_TYPE_MM_HPF)
|
||
|
{
|
||
|
PLIST_ENTRY pHead = & pProcess->HPFListHead;
|
||
|
PLIST_ENTRY pNext = pHead->Flink;
|
||
|
PHPF_RECORD pHPFRecord;
|
||
|
|
||
|
while (pNext != pHead)
|
||
|
{
|
||
|
pHPFRecord = CONTAINING_RECORD(pNext, HPF_RECORD, Entry);
|
||
|
pNext = pNext->Flink;
|
||
|
if (pHPFRecord->lFaultAddress == lFaultAddr)
|
||
|
{
|
||
|
pHPFRecord->lProgramCounter = lPC;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pModule)
|
||
|
{
|
||
|
UpdatePageFaultCount(
|
||
|
pProcess, pModule, lFaultAddr, pHeader->Class.Type);
|
||
|
fFound = TRUE;
|
||
|
}
|
||
|
|
||
|
if (!fFound && pProcess->PID != 0)
|
||
|
{
|
||
|
PMODULE_RECORD pSysModule = SearchSysModule(pProcess, lPC, TRUE);
|
||
|
if (pSysModule)
|
||
|
{
|
||
|
UpdatePageFaultCount(
|
||
|
pProcess, pSysModule, lFaultAddr, pHeader->Class.Type);
|
||
|
fFound = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fFound)
|
||
|
{
|
||
|
PLIST_ENTRY pModuleHead = & pProcess->ModuleListHead;
|
||
|
PLIST_ENTRY pModuleNext = pModuleHead->Flink;
|
||
|
PMODULE_RECORD pTmpModule;
|
||
|
|
||
|
while (pModuleNext != pModuleHead)
|
||
|
{
|
||
|
pTmpModule = CONTAINING_RECORD(pModuleNext,
|
||
|
MODULE_RECORD,
|
||
|
Entry);
|
||
|
pModuleNext = pModuleNext->Flink;
|
||
|
if (!_wcsicmp(pTmpModule->strModuleName, L"other"))
|
||
|
{
|
||
|
if ( pTmpModule->lBaseAddress == 0
|
||
|
&& pTmpModule->lModuleSize == 0)
|
||
|
{
|
||
|
pTmpModule->lBaseAddress = lPC;
|
||
|
pTmpModule->lModuleSize = 1;
|
||
|
}
|
||
|
else if (pTmpModule->lBaseAddress > lPC)
|
||
|
{
|
||
|
pTmpModule->lModuleSize += pTmpModule->lBaseAddress - lPC;
|
||
|
pTmpModule->lBaseAddress = lPC;
|
||
|
}
|
||
|
else if ( pTmpModule->lModuleSize
|
||
|
< lPC - pTmpModule->lBaseAddress + 1)
|
||
|
{
|
||
|
pTmpModule->lModuleSize =
|
||
|
lPC - pTmpModule->lBaseAddress + 1;
|
||
|
}
|
||
|
UpdatePageFaultCount(
|
||
|
pProcess,
|
||
|
pTmpModule,
|
||
|
lFaultAddr,
|
||
|
pHeader->Class.Type);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
else
|
||
|
{
|
||
|
|
||
|
#if DBG
|
||
|
DbgPrint("ERROR - PageFaultCallback(0x%08I64x,0x%08I64x,0x%08x,0x%08x) cannot find process\n",
|
||
|
pHeader->ThreadId,
|
||
|
pThread->pProcess->PID,
|
||
|
lPC,
|
||
|
lFaultAddr);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
*/
|
||
|
Cleanup:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DiskIoCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IO_READ) {
|
||
|
IoReadCallback(pEvent, pThread);
|
||
|
}
|
||
|
else {
|
||
|
IoWriteCallback(pEvent, pThread);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
TcpIpCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
ULONG size = 0;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
pHeader = (EVENT_TRACE_HEADER*)&pEvent->Header;
|
||
|
|
||
|
if (!InTimeWindow(pEvent, pThread))
|
||
|
return;
|
||
|
|
||
|
if (pThread == NULL)
|
||
|
{
|
||
|
if (AddThread(pHeader->ThreadId, pEvent, &pThread ))
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Thread %x added to charge TCP/IP event\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
pThread->pProcess = FindProcessById(0, TRUE);
|
||
|
pThread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
pThread->fOrphan = TRUE;
|
||
|
|
||
|
pThread->KCPUStart = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pHeader->UserTime;
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for TCP/IP Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else if (pThread->fOrphan)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): TCP/IP Event Thread %x Is Still Orphan.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
else if (pThread->DeadFlag)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): TCP/IP Event Thread %x Is Already Dead.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
if (GetMofData(pEvent, L"size", &size, sizeof(ULONG)) > 0) {
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SEND ) {
|
||
|
|
||
|
pThread->SendCount++;
|
||
|
pThread->SendSize += size;
|
||
|
|
||
|
if (pThread->pMofData != NULL) {
|
||
|
((PMOF_DATA)pThread->pMofData)->SendCount++;
|
||
|
}
|
||
|
|
||
|
if ( (pProcess = pThread->pProcess) != NULL ) {
|
||
|
pProcess->SendCount++;
|
||
|
pProcess->SendSize += size;
|
||
|
}
|
||
|
|
||
|
} else if( pEvent->Header.Class.Type == EVENT_TRACE_TYPE_RECEIVE ) {
|
||
|
|
||
|
pThread->RecvCount++;
|
||
|
pThread->RecvSize += size;
|
||
|
|
||
|
if (pThread->pMofData != NULL) {
|
||
|
((PMOF_DATA)pThread->pMofData)->RecvCount++;
|
||
|
}
|
||
|
|
||
|
if ( (pProcess = pThread->pProcess) != NULL ) {
|
||
|
pProcess->RecvCount++;
|
||
|
pProcess->RecvSize += size;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PFILE_OBJECT
|
||
|
FindFileInTable (
|
||
|
IN PVOID fDO
|
||
|
)
|
||
|
{
|
||
|
PFILE_OBJECT thisFile, lastFile = NULL;
|
||
|
PFILE_OBJECT *fileTable;
|
||
|
UINT i;
|
||
|
fileTable = CurrentSystem.FileTable;
|
||
|
for (i = 0; i < MAX_FILE_TABLE_SIZE; i++) {
|
||
|
thisFile = fileTable[i];
|
||
|
fileTable[i] = lastFile;
|
||
|
lastFile = thisFile;
|
||
|
if ((thisFile != NULL) && (thisFile->fDO == fDO)) {
|
||
|
fileTable[0] = thisFile;
|
||
|
return thisFile;
|
||
|
}
|
||
|
}
|
||
|
if (lastFile == NULL) {
|
||
|
lastFile = (PFILE_OBJECT) malloc( sizeof(FILE_OBJECT));
|
||
|
if (lastFile == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
fileTable[0] = lastFile;
|
||
|
lastFile->fDO = fDO;
|
||
|
lastFile->fileRec = NULL;
|
||
|
InitializeListHead( &lastFile->ProtoFileRecordListHead );
|
||
|
return lastFile;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// TODO: Redo the EventList as FILE_RECORDS with Unknown Filenames
|
||
|
// The current implementation will create a proto record for
|
||
|
// evenry I/O and if the APC never arrives, it can choke the
|
||
|
// system!
|
||
|
//
|
||
|
|
||
|
VOID
|
||
|
AddEvent(
|
||
|
IN PFILE_OBJECT fileObject,
|
||
|
IN ULONG DiskNumber,
|
||
|
IN ULONG IoSize,
|
||
|
IN BOOLEAN ReadFlag
|
||
|
)
|
||
|
{
|
||
|
PPROTO_FILE_RECORD protoFileRec;
|
||
|
|
||
|
if (fileObject->fileRec != NULL) {
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("BUG: FileObject is NONNULL in AddEvent\n");
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
protoFileRec = (PPROTO_FILE_RECORD) malloc(sizeof(PROTO_FILE_RECORD));
|
||
|
if (protoFileRec == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
protoFileRec->ReadFlag = ReadFlag;
|
||
|
protoFileRec->IoSize = IoSize;
|
||
|
protoFileRec->DiskNumber = DiskNumber;
|
||
|
|
||
|
InsertHeadList( &fileObject->ProtoFileRecordListHead, &protoFileRec->Entry);
|
||
|
|
||
|
// Currently NOT Keeping track of the DrillDown data for the File
|
||
|
// if APC has not happened yet. Some Events may be lost.
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
GetMofData(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
WCHAR *strName,
|
||
|
PVOID ReturnValue,
|
||
|
ULONG ReturnLength
|
||
|
)
|
||
|
{
|
||
|
PITEM_DESC pAuxInfo;
|
||
|
PUCHAR pData;
|
||
|
ULONG RequiredLength = 0;
|
||
|
BOOLEAN AddNull = FALSE;
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PMOF_VERSION pMofVersion;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return 0;
|
||
|
|
||
|
pData = (PUCHAR) pEvent->MofData;
|
||
|
|
||
|
if (strName == NULL)
|
||
|
return 0;
|
||
|
if (lstrlenW(strName) <= 0)
|
||
|
return 0;
|
||
|
|
||
|
pMofInfo = GetMofInfoHead(&pEvent->Header.Guid);
|
||
|
if (pMofInfo == NULL)
|
||
|
return 0;
|
||
|
|
||
|
pMofVersion = GetMofVersion(pMofInfo,
|
||
|
pEvent->Header.Class.Type,
|
||
|
pEvent->Header.Class.Version,
|
||
|
pEvent->Header.Class.Level
|
||
|
);
|
||
|
|
||
|
if (pMofVersion == NULL)
|
||
|
return 0;
|
||
|
|
||
|
Head = &pMofVersion->ItemHeader;
|
||
|
Next = Head->Flink;
|
||
|
while (Head != Next) {
|
||
|
pAuxInfo = CONTAINING_RECORD(Next, ITEM_DESC, Entry);
|
||
|
if ( (ULONG) (pData-(PUCHAR)pEvent->MofData) >= pEvent->MofLength)
|
||
|
return 0;
|
||
|
|
||
|
switch (pAuxInfo->ItemType) {
|
||
|
case ItemChar:
|
||
|
case ItemUChar:
|
||
|
{
|
||
|
if (pAuxInfo->ArraySize > 0) {
|
||
|
RequiredLength = pAuxInfo->ArraySize;
|
||
|
}
|
||
|
else {
|
||
|
RequiredLength = sizeof(UCHAR);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ItemWChar:
|
||
|
{
|
||
|
if (pAuxInfo->ArraySize > 0) {
|
||
|
RequiredLength = pAuxInfo->ArraySize * sizeof(WCHAR);
|
||
|
}
|
||
|
else {
|
||
|
RequiredLength = sizeof(WCHAR);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ItemShort:
|
||
|
case ItemUShort:
|
||
|
{
|
||
|
RequiredLength = 2;
|
||
|
}
|
||
|
break;
|
||
|
case ItemULong:
|
||
|
case ItemULongX:
|
||
|
{
|
||
|
RequiredLength = 4;
|
||
|
}
|
||
|
break;
|
||
|
case ItemLongLong:
|
||
|
case ItemULongLong:
|
||
|
{
|
||
|
RequiredLength = 8;
|
||
|
}
|
||
|
break;
|
||
|
case ItemPString :
|
||
|
pData += sizeof(USHORT);
|
||
|
case ItemString :
|
||
|
RequiredLength = lstrlenA((PCHAR)pData) + 1;
|
||
|
break;
|
||
|
case ItemWString :
|
||
|
|
||
|
//
|
||
|
// FileNames etc are not NULL Terminated and only the buffer
|
||
|
// is copied. To find its length, we can't use wcslen.
|
||
|
// The Length is computed from the assumption that this string
|
||
|
// is the last item for this event and the size of the event
|
||
|
// should help determine the size of this string.
|
||
|
|
||
|
RequiredLength = pEvent->MofLength -
|
||
|
(ULONG) (pData - (PUCHAR) pEvent->MofData);
|
||
|
|
||
|
AddNull = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case ItemSid :
|
||
|
{
|
||
|
ULONG SidMarker;
|
||
|
RtlCopyMemory(&SidMarker, pData, sizeof(ULONG));
|
||
|
if (SidMarker == 0) {
|
||
|
RequiredLength = 4;
|
||
|
}
|
||
|
else {
|
||
|
if (PointerSize == 64) {
|
||
|
pData += 16; // skip the TOKEN_USER structure
|
||
|
}
|
||
|
else {
|
||
|
pData += 8; // skip the TOKEN_USER structure
|
||
|
}
|
||
|
RequiredLength = 8 + (4*pData[1]);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ItemSizeT:
|
||
|
case ItemPtr :
|
||
|
{
|
||
|
RequiredLength = PointerSize / 8;
|
||
|
if ( (RequiredLength != 4) && (RequiredLength != 8) ) {
|
||
|
RequiredLength = 4;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ItemTDIAddr :
|
||
|
{
|
||
|
// We assume the rest of the event is all TDIAddr
|
||
|
RequiredLength = pEvent->MofLength -
|
||
|
(ULONG) (pData - (PUCHAR) pEvent->MofData);
|
||
|
break;
|
||
|
}
|
||
|
default : RequiredLength = pAuxInfo->DataSize;
|
||
|
}
|
||
|
if (!wcscmp(pAuxInfo->strDescription, strName)) {
|
||
|
if (RequiredLength == 0) return 0;
|
||
|
//
|
||
|
// Make Sure there is enough room to copy
|
||
|
//
|
||
|
if (RequiredLength > ReturnLength) {
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("RequiredLength %d Space Available %d\n", RequiredLength, ReturnLength);
|
||
|
#endif
|
||
|
*/
|
||
|
return RequiredLength;
|
||
|
}
|
||
|
|
||
|
RtlCopyMemory(ReturnValue, pData, RequiredLength);
|
||
|
|
||
|
if (AddNull) {
|
||
|
WCHAR* ws;
|
||
|
ws = (WCHAR*) ReturnValue;
|
||
|
ws[(RequiredLength/2)] = 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
pData += RequiredLength;
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
return RequiredLength;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
GetDeltaWithTimeWindow(BOOLEAN fKCPU, PTHREAD_RECORD pThread,
|
||
|
ULONGLONG timeStart, ULONGLONG timeEnd,
|
||
|
ULONG DeltaStart, ULONG DeltaEnd)
|
||
|
{
|
||
|
ULONG lResult = 0;
|
||
|
ULONG lDeltaStart, lDeltaEnd;
|
||
|
|
||
|
UNREFERENCED_PARAMETER(pThread);
|
||
|
|
||
|
if (!fDSOnly)
|
||
|
{
|
||
|
lResult = (DeltaEnd > DeltaStart) ? (DeltaEnd - DeltaStart) : (0);
|
||
|
}
|
||
|
else if ((timeStart >= DSEndTime) || (timeEnd <= DSStartTime))
|
||
|
{
|
||
|
lResult = 0;
|
||
|
}
|
||
|
else if (fKCPU)
|
||
|
{
|
||
|
lDeltaStart = (timeStart < DSStartTime)
|
||
|
? Interpolate(timeStart, DeltaStart,
|
||
|
timeEnd, DeltaEnd,
|
||
|
DSStartTime)
|
||
|
: DeltaStart;
|
||
|
lDeltaEnd = (timeEnd > DSEndTime)
|
||
|
? Interpolate(timeStart, DeltaStart,
|
||
|
timeEnd, DeltaEnd,
|
||
|
DSEndTime)
|
||
|
: DeltaEnd;
|
||
|
lResult = (lDeltaEnd > lDeltaStart) ? (lDeltaEnd - lDeltaStart) : (0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lDeltaStart = (timeStart < DSStartTime)
|
||
|
? Interpolate(timeStart, DeltaStart,
|
||
|
timeEnd, DeltaEnd,
|
||
|
DSStartTime)
|
||
|
: DeltaStart;
|
||
|
lDeltaEnd = (timeEnd > DSEndTime)
|
||
|
? Interpolate(timeStart, DeltaStart,
|
||
|
timeEnd, DeltaEnd,
|
||
|
DSEndTime)
|
||
|
: DeltaEnd;
|
||
|
lResult = (lDeltaEnd > lDeltaStart) ? (lDeltaEnd - lDeltaStart) : (0);
|
||
|
}
|
||
|
return lResult;
|
||
|
}
|
||
|
|
||
|
// Generic Event Callback. Get the Transaction Response Time.
|
||
|
//
|
||
|
VOID
|
||
|
EventCallback(
|
||
|
PEVENT_TRACE pEvent,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PMOF_DATA pMofData;
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
PPROCESS_RECORD pProcess;
|
||
|
PTRANS_RECORD pThreadTrans = NULL;
|
||
|
ULONGLONG delta;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
//
|
||
|
// Ignore Process/Thread Start/End transactions. Only go after
|
||
|
// User Defined Transactions.
|
||
|
//
|
||
|
pMofInfo = GetMofInfoHead(&pHeader->Guid);
|
||
|
if (pMofInfo == NULL){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( pMofInfo->bKernelEvent ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID( &pMofInfo->Guid, &EventTraceGuid ) ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_GUIDMAP) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pThread == NULL) {
|
||
|
if (AddThread( pHeader->ThreadId, pEvent, &pThread )) {
|
||
|
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("WARNING(%d): Thread %x added to charge Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
pThread->pProcess = FindProcessById(0, TRUE); // Charge it the system ???
|
||
|
pThread->TimeStart = pHeader->TimeStamp.QuadPart;
|
||
|
pThread->KCPUStart = pHeader->KernelTime;
|
||
|
pThread->UCPUStart = pHeader->UserTime;
|
||
|
pThread->fOrphan = TRUE;
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("FATBUG(%d): Cannot add thread %x for Event.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
#if DBG
|
||
|
else if (pThread->fOrphan)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): Generic Event Thread %x Is Still Orphan.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
else if (pThread->DeadFlag)
|
||
|
{
|
||
|
DbgPrint("INFO(%d): Generic Event Thread %x Is Already Dead.\n",
|
||
|
EventCount, pHeader->ThreadId);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
if (pMofInfo->strSortField == NULL){
|
||
|
pMofData = FindMofData(pMofInfo, NULL);
|
||
|
}
|
||
|
else if ( (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_START)
|
||
|
|| (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START)){
|
||
|
WCHAR strSortKey[MAXSTR];
|
||
|
|
||
|
RtlZeroMemory(strSortKey, MAXSTR * sizeof(WCHAR) );
|
||
|
|
||
|
GetMofData(pEvent, pMofInfo->strSortField, &strSortKey[0], MAXSTR);
|
||
|
pMofData = FindMofData(pMofInfo, strSortKey );
|
||
|
// pThread->strSortKey is static array
|
||
|
StringCchCopyW(pThread->strSortKey, MAXSTR, strSortKey );
|
||
|
|
||
|
}else{
|
||
|
pMofData = FindMofData( pMofInfo, pThread->strSortKey );
|
||
|
}
|
||
|
|
||
|
pProcess = pThread->pProcess;
|
||
|
if ( (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_START)
|
||
|
|| (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START)){
|
||
|
pThreadTrans = FindTransByList(& pThread->TransListHead,
|
||
|
& pMofInfo->Guid,
|
||
|
pThread->TransLevel);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LONG i = pThread->TransLevel - 1;
|
||
|
|
||
|
while (i >= 0)
|
||
|
{
|
||
|
if (IsEqualGUID(& pHeader->Guid,
|
||
|
pThread->TransStack[i]->pGuid))
|
||
|
{
|
||
|
pThreadTrans = pThread->TransStack[i];
|
||
|
break;
|
||
|
}
|
||
|
i --;
|
||
|
}
|
||
|
if (i < 0)
|
||
|
{
|
||
|
pThreadTrans = FindTransByList(& pThread->TransListHead,
|
||
|
&pMofInfo->Guid,
|
||
|
(pThread->TransLevel >= 0) ? (pThread->TransLevel) : (0));
|
||
|
if (pThread->TransLevel < 0)
|
||
|
{
|
||
|
pThread->TransLevel = 0;
|
||
|
pThread->TransStack[pThread->TransLevel] = pThreadTrans;
|
||
|
pThread->TransLevel ++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pMofData == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pMofData->PrevClockTime == 0)
|
||
|
{
|
||
|
pMofData->PrevClockTime = pHeader->TimeStamp.QuadPart;
|
||
|
}
|
||
|
|
||
|
delta = (pHeader->TimeStamp.QuadPart - pMofData->PrevClockTime);
|
||
|
|
||
|
pMofData->TotalResponseTime += (delta * pMofData->InProgressCount) / 10000;
|
||
|
|
||
|
// Update the Clock
|
||
|
pMofData->PrevClockTime = pHeader->TimeStamp.QuadPart;
|
||
|
|
||
|
if ( (pHeader->Class.Type == EVENT_TRACE_TYPE_START)
|
||
|
|| (pHeader->Class.Type == EVENT_TRACE_TYPE_DC_START))
|
||
|
{
|
||
|
if (pThread->TransLevel < 0)
|
||
|
{
|
||
|
pThread->TransLevel = 0;
|
||
|
}
|
||
|
|
||
|
if (pThread->TransLevel == 0)
|
||
|
{
|
||
|
LONG lDelta;
|
||
|
|
||
|
lDelta = pHeader->KernelTime - pThread->KCPU_PrevTrans;
|
||
|
if (lDelta > 0)
|
||
|
{
|
||
|
pThread->KCPU_NoTrans += lDelta;
|
||
|
pThread->KCPU_PrevTrans = pHeader->KernelTime;
|
||
|
}
|
||
|
lDelta = pHeader->UserTime - pThread->UCPU_PrevTrans;
|
||
|
if (lDelta > 0)
|
||
|
{
|
||
|
pThread->UCPU_NoTrans += lDelta;
|
||
|
pThread->UCPU_PrevTrans = pHeader->UserTime;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PTRANS_RECORD pTransPrev =
|
||
|
pThread->TransStack[pThread->TransLevel - 1];
|
||
|
PMOF_INFO pMofInfoPrev = GetMofInfoHead(pTransPrev->pGuid);
|
||
|
PMOF_DATA pMofDataPrev = NULL;
|
||
|
ULONG DeltaCPU;
|
||
|
|
||
|
if (pMofInfoPrev != NULL)
|
||
|
{
|
||
|
pMofDataPrev = FindMofData(pMofInfoPrev, NULL);
|
||
|
}
|
||
|
|
||
|
if (pMofDataPrev)
|
||
|
{
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
TRUE,
|
||
|
pThread,
|
||
|
pThread->Time_PrevEvent,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pThread->KCPU_PrevEvent,
|
||
|
pHeader->KernelTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pTransPrev->KCpu += DeltaCPU;
|
||
|
pMofDataPrev->KernelCPU += DeltaCPU;
|
||
|
if (pMofDataPrev->MaxKCpu < 0)
|
||
|
{
|
||
|
pMofDataPrev->MaxKCpu = DeltaCPU;
|
||
|
pMofDataPrev->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofDataPrev->MaxKCpu)
|
||
|
{
|
||
|
pMofDataPrev->MaxKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU < (ULONG) pMofDataPrev->MinKCpu)
|
||
|
{
|
||
|
pMofDataPrev->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
FALSE,
|
||
|
pThread,
|
||
|
pThread->Time_PrevEvent,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pThread->UCPU_PrevEvent,
|
||
|
pHeader->UserTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pTransPrev->UCpu += DeltaCPU;
|
||
|
pMofDataPrev->UserCPU += DeltaCPU;
|
||
|
if (pMofDataPrev->MaxUCpu < 0)
|
||
|
{
|
||
|
pMofDataPrev->MaxUCpu = DeltaCPU;
|
||
|
pMofDataPrev->MinUCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofDataPrev->MaxUCpu)
|
||
|
{
|
||
|
pMofDataPrev->MaxUCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU < (ULONG) pMofDataPrev->MinUCpu)
|
||
|
{
|
||
|
pMofDataPrev->MinUCpu = DeltaCPU;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( pThreadTrans != NULL ){
|
||
|
if( ! pThreadTrans->bStarted ){
|
||
|
pThreadTrans->bStarted = TRUE;
|
||
|
|
||
|
pMofData->InProgressCount ++;
|
||
|
|
||
|
if (pHeader->Class.Type == EVENT_TRACE_TYPE_START) {
|
||
|
pThread->RefCount ++;
|
||
|
pThreadTrans->RefCount ++;
|
||
|
}
|
||
|
else {
|
||
|
pThreadTrans->RefCount1 ++;
|
||
|
}
|
||
|
|
||
|
pThread->pMofData = pMofData;
|
||
|
|
||
|
pThread->TransStack[pThread->TransLevel] = pThreadTrans;
|
||
|
pThread->TransLevel ++;
|
||
|
}
|
||
|
}
|
||
|
pThread->Time_PrevEvent = (ULONGLONG) pHeader->TimeStamp.QuadPart;
|
||
|
pThread->KCPU_PrevEvent = pHeader->KernelTime;
|
||
|
pThread->UCPU_PrevEvent = pHeader->UserTime;
|
||
|
|
||
|
pThread->DeltaReadIO = pThread->ReadIO;
|
||
|
pThread->DeltaWriteIO = pThread->WriteIO;
|
||
|
|
||
|
pThread->DeltaSend = pThread->SendCount;
|
||
|
pThread->DeltaRecv = pThread->RecvCount;
|
||
|
}
|
||
|
else if ( (pHeader->Class.Type == EVENT_TRACE_TYPE_END)
|
||
|
|| (pHeader->Class.Type == EVENT_TRACE_TYPE_DC_END))
|
||
|
{
|
||
|
ULONG DeltaCPU;
|
||
|
BOOLEAN fSwitch = TRUE;
|
||
|
if( pThreadTrans != NULL ){
|
||
|
|
||
|
if (pThreadTrans->bStarted){
|
||
|
|
||
|
PTRANS_RECORD pTransCurrent;
|
||
|
PMOF_INFO pMofInfoCurrent;
|
||
|
PMOF_DATA pMofDataCurrent;
|
||
|
BOOLEAN fCharged = FALSE;
|
||
|
|
||
|
if (pThread->TransLevel <= 0)
|
||
|
{
|
||
|
pThread->TransLevel = 0;
|
||
|
}
|
||
|
else {
|
||
|
do
|
||
|
{
|
||
|
pThread->TransLevel --;
|
||
|
pTransCurrent = pThread->TransStack[pThread->TransLevel];
|
||
|
if (pTransCurrent->bStarted)
|
||
|
{
|
||
|
pTransCurrent->bStarted = FALSE;
|
||
|
}
|
||
|
|
||
|
pMofInfoCurrent = GetMofInfoHead( pTransCurrent->pGuid );
|
||
|
pMofDataCurrent = NULL;
|
||
|
|
||
|
if (pMofInfoCurrent != NULL)
|
||
|
{
|
||
|
pMofDataCurrent = FindMofData(pMofInfoCurrent, NULL);
|
||
|
}
|
||
|
|
||
|
if (!pMofDataCurrent)
|
||
|
continue;
|
||
|
|
||
|
pMofDataCurrent->InProgressCount--;
|
||
|
|
||
|
if (pMofDataCurrent->InProgressCount < 0){
|
||
|
pMofDataCurrent->InProgressCount = 0;
|
||
|
}
|
||
|
pMofDataCurrent->CompleteCount++;
|
||
|
|
||
|
pMofDataCurrent->AverageResponseTime
|
||
|
= (pMofDataCurrent->CompleteCount > 0)
|
||
|
? ( (LONG) pMofDataCurrent->TotalResponseTime
|
||
|
/ pMofDataCurrent->CompleteCount)
|
||
|
: 0;
|
||
|
|
||
|
if (fCharged)
|
||
|
continue;
|
||
|
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
TRUE,
|
||
|
pThread,
|
||
|
pThread->Time_PrevEvent,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pThread->KCPU_PrevEvent,
|
||
|
pHeader->KernelTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pTransCurrent->KCpu += DeltaCPU;
|
||
|
pMofDataCurrent->KernelCPU += DeltaCPU;
|
||
|
if (pMofDataCurrent->MaxKCpu < 0)
|
||
|
{
|
||
|
pMofDataCurrent->MaxKCpu = DeltaCPU;
|
||
|
pMofDataCurrent->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofDataCurrent->MaxKCpu)
|
||
|
{
|
||
|
pMofDataCurrent->MaxKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU < (ULONG) pMofDataCurrent->MinKCpu)
|
||
|
{
|
||
|
pMofDataCurrent->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
FALSE,
|
||
|
pThread,
|
||
|
pThread->Time_PrevEvent,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pThread->UCPU_PrevEvent,
|
||
|
pHeader->UserTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pTransCurrent->UCpu += DeltaCPU;
|
||
|
pMofDataCurrent->UserCPU += DeltaCPU;
|
||
|
if(pMofDataCurrent->MaxUCpu < 0)
|
||
|
{
|
||
|
pMofDataCurrent->MaxUCpu = DeltaCPU;
|
||
|
pMofDataCurrent->MinUCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofDataCurrent->MaxUCpu)
|
||
|
{
|
||
|
pMofDataCurrent->MaxUCpu = DeltaCPU;
|
||
|
}
|
||
|
fCharged = TRUE;
|
||
|
}while ( pThread->TransLevel > 0 &&
|
||
|
!IsEqualGUID(& pHeader->Guid, pTransCurrent->pGuid));
|
||
|
}
|
||
|
|
||
|
pThread->Time_PrevEvent = (ULONGLONG) pHeader->TimeStamp.QuadPart;
|
||
|
pThread->KCPU_PrevEvent = pHeader->KernelTime;
|
||
|
pThread->UCPU_PrevEvent = pHeader->UserTime;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
TRUE,
|
||
|
pThread,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pHeader->KernelTime,
|
||
|
pHeader->KernelTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pThreadTrans->KCpu += DeltaCPU;
|
||
|
pMofData->KernelCPU += DeltaCPU;
|
||
|
if (pMofData->MaxKCpu < 0)
|
||
|
{
|
||
|
pMofData->MaxKCpu = DeltaCPU;
|
||
|
pMofData->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofData->MaxKCpu)
|
||
|
{
|
||
|
pMofData->MaxKCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU < (ULONG) pMofData->MinKCpu)
|
||
|
{
|
||
|
pMofData->MinKCpu = DeltaCPU;
|
||
|
}
|
||
|
|
||
|
DeltaCPU = GetDeltaWithTimeWindow(
|
||
|
FALSE,
|
||
|
pThread,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
(ULONGLONG) pHeader->TimeStamp.QuadPart,
|
||
|
pHeader->UserTime,
|
||
|
pHeader->UserTime);
|
||
|
DeltaCPU = DeltaCPU * CurrentSystem.TimerResolution;
|
||
|
|
||
|
pThreadTrans->UCpu += DeltaCPU;
|
||
|
pMofData->UserCPU += DeltaCPU;
|
||
|
if(pMofData->MaxUCpu < 0)
|
||
|
{
|
||
|
pMofData->MaxUCpu = DeltaCPU;
|
||
|
pMofData->MinUCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU > (ULONG) pMofData->MaxUCpu)
|
||
|
{
|
||
|
pMofData->MaxUCpu = DeltaCPU;
|
||
|
}
|
||
|
if (DeltaCPU < (ULONG) pMofData->MinUCpu)
|
||
|
{
|
||
|
pMofData->MinUCpu = DeltaCPU;
|
||
|
}
|
||
|
|
||
|
fSwitch = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pMofData->ReadCount += (pThread->ReadIO - pThread->DeltaReadIO);
|
||
|
pMofData->WriteCount += (pThread->WriteIO - pThread->DeltaWriteIO);
|
||
|
pMofData->SendCount += (pThread->SendCount - pThread->DeltaSend);
|
||
|
pMofData->RecvCount += (pThread->RecvCount - pThread->DeltaRecv);
|
||
|
pThread->pMofData = NULL;
|
||
|
|
||
|
if (fSwitch && pThread->TransLevel <= 0)
|
||
|
{
|
||
|
LONG lDelta;
|
||
|
|
||
|
if (pThread->TransLevel < 0)
|
||
|
{
|
||
|
pThread->TransLevel = 0;
|
||
|
}
|
||
|
lDelta = pHeader->KernelTime - pThread->KCPU_PrevTrans;
|
||
|
if (lDelta > 0)
|
||
|
{
|
||
|
pThread->KCPU_Trans += lDelta;
|
||
|
pThread->KCPU_PrevTrans = pHeader->KernelTime;
|
||
|
}
|
||
|
lDelta = pHeader->UserTime - pThread->UCPU_PrevTrans;
|
||
|
if (lDelta > 0)
|
||
|
{
|
||
|
pThread->UCPU_Trans += lDelta;
|
||
|
pThread->UCPU_PrevTrans = pHeader->UserTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This routine moves the temporary MOF_VERSION list
|
||
|
// into the VersionHeader list for this GUID (MofInfo)
|
||
|
//
|
||
|
|
||
|
void
|
||
|
FlushMofVersionList( PMOF_INFO pMofInfo, PLIST_ENTRY ListHead )
|
||
|
{
|
||
|
PMOF_VERSION pMofVersion;
|
||
|
PLIST_ENTRY Head = ListHead;
|
||
|
PLIST_ENTRY Next = Head->Flink;
|
||
|
|
||
|
while( Head != Next ){
|
||
|
pMofVersion = CONTAINING_RECORD(Next, MOF_VERSION, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
RemoveEntryList(&pMofVersion->Entry);
|
||
|
if (pMofInfo != NULL) {
|
||
|
InsertTailList( &pMofInfo->VersionHeader, &pMofVersion->Entry);
|
||
|
}
|
||
|
else {
|
||
|
free(pMofVersion);
|
||
|
//
|
||
|
// Really should not hit this case
|
||
|
//
|
||
|
/*
|
||
|
#if DBG
|
||
|
DbgPrint("TRACECTR: FlushMofVersionList. MofInfo ptr is NULL\n");
|
||
|
ASSERT (pMofInfo != NULL);
|
||
|
#endif
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
DumpMofVersionItem(
|
||
|
PMOF_VERSION pMofVersion
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Head = &pMofVersion->ItemHeader;
|
||
|
PLIST_ENTRY Next = Head->Flink;
|
||
|
PITEM_DESC pItem;
|
||
|
|
||
|
DbgPrint("MOF_VERSION: Version %d Level %d Type %d strType %ws\n",
|
||
|
pMofVersion->Version,
|
||
|
pMofVersion->Level,
|
||
|
pMofVersion->TypeIndex,
|
||
|
pMofVersion->strType);
|
||
|
|
||
|
|
||
|
while( Head != Next ){
|
||
|
pItem = CONTAINING_RECORD(Next, ITEM_DESC, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
|
||
|
DbgPrint("Name %ws Size %d ItemType %d\n", pItem->strDescription, pItem->DataSize, pItem->ItemType);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DumpMofList()
|
||
|
{
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PLIST_ENTRY Head = &CurrentSystem.EventListHead;
|
||
|
PLIST_ENTRY Next = Head->Flink;
|
||
|
|
||
|
while( Head != Next ){
|
||
|
pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Count the MOF Fields for this Guid and Type
|
||
|
//
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
DbgPrint("Name %ws KernelEvent %d\n", pMofInfo->strDescription,
|
||
|
pMofInfo->bKernelEvent);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuids( GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent )
|
||
|
{
|
||
|
if ( TraceContext->Flags & TRACE_USE_WBEM ){
|
||
|
return GetGuidsWBEM( Guid, nVersion, nLevel, nType, bKernelEvent );
|
||
|
}else{
|
||
|
return GetGuidsMofFiles( Guid, nVersion, nLevel, nType, bKernelEvent );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
WbemConnect( IWbemServices** pWbemServices )
|
||
|
{
|
||
|
IWbemLocator *pLocator = NULL;
|
||
|
|
||
|
BSTR bszNamespace = SysAllocString( L"root\\wmi" );
|
||
|
|
||
|
HRESULT hr = CoInitialize(0);
|
||
|
|
||
|
hr = CoCreateInstance(
|
||
|
CLSID_WbemLocator,
|
||
|
0,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IWbemLocator,
|
||
|
(LPVOID *) &pLocator
|
||
|
);
|
||
|
CHECK_HR( hr );
|
||
|
|
||
|
hr = pLocator->ConnectServer(
|
||
|
bszNamespace,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0L,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
pWbemServices
|
||
|
);
|
||
|
CHECK_HR( hr );
|
||
|
|
||
|
hr = CoSetProxyBlanket(
|
||
|
*pWbemServices,
|
||
|
RPC_C_AUTHN_WINNT,
|
||
|
RPC_C_AUTHZ_NONE,
|
||
|
NULL,
|
||
|
RPC_C_AUTHN_LEVEL_PKT,
|
||
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||
|
NULL,
|
||
|
EOAC_NONE
|
||
|
);
|
||
|
|
||
|
|
||
|
cleanup:
|
||
|
SysFreeString( bszNamespace );
|
||
|
|
||
|
if( pLocator ){
|
||
|
pLocator->Release();
|
||
|
pLocator = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
ULONG GetArraySize(
|
||
|
IN IWbemQualifierSet *pQualSet
|
||
|
)
|
||
|
{
|
||
|
ULONG ArraySize = 1;
|
||
|
VARIANT pVal;
|
||
|
BSTR bszMaxLen;
|
||
|
HRESULT hRes;
|
||
|
|
||
|
if (pQualSet == NULL){
|
||
|
return ArraySize;
|
||
|
}
|
||
|
|
||
|
bszMaxLen = SysAllocString(L"MAX");
|
||
|
VariantInit(&pVal);
|
||
|
hRes = pQualSet->Get(bszMaxLen,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszMaxLen);
|
||
|
if (ERROR_SUCCESS == hRes && pVal.vt == VT_I4 ){
|
||
|
ArraySize = pVal.lVal;
|
||
|
}
|
||
|
VariantClear(&pVal);
|
||
|
return ArraySize;
|
||
|
}
|
||
|
|
||
|
ITEM_TYPE
|
||
|
GetItemType(
|
||
|
IN CIMTYPE_ENUMERATION CimType,
|
||
|
IN IWbemQualifierSet *pQualSet
|
||
|
)
|
||
|
{
|
||
|
ITEM_TYPE Type = ItemUnknown;;
|
||
|
VARIANT pVal;
|
||
|
HRESULT hRes;
|
||
|
BSTR bszQualName;
|
||
|
WCHAR strFormat[10];
|
||
|
WCHAR strTermination[30];
|
||
|
WCHAR strTemp[30];
|
||
|
BOOLEAN IsPointer = FALSE;
|
||
|
|
||
|
strFormat[0] = '\0';
|
||
|
strTermination[0] = '\0';
|
||
|
strTemp[0] = '\0';
|
||
|
|
||
|
if (pQualSet == NULL)
|
||
|
return ItemUnknown;
|
||
|
|
||
|
bszQualName = SysAllocString(L"format");
|
||
|
VariantInit(&pVal);
|
||
|
hRes = pQualSet->Get(bszQualName,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszQualName);
|
||
|
if (ERROR_SUCCESS == hRes && NULL != pVal.bstrVal)
|
||
|
StringCchCopyW(strFormat, 10, pVal.bstrVal);
|
||
|
|
||
|
bszQualName = SysAllocString(L"StringTermination");
|
||
|
VariantClear(&pVal);
|
||
|
hRes = pQualSet->Get(bszQualName,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszQualName);
|
||
|
if (ERROR_SUCCESS == hRes && NULL != pVal.bstrVal)
|
||
|
StringCchCopyW(strTermination, 30, pVal.bstrVal);
|
||
|
|
||
|
bszQualName = SysAllocString(L"pointer");
|
||
|
VariantClear(&pVal);
|
||
|
hRes = pQualSet->Get(bszQualName,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszQualName);
|
||
|
if (ERROR_SUCCESS == hRes)
|
||
|
IsPointer = TRUE;
|
||
|
bszQualName = SysAllocString(L"PointerType");
|
||
|
VariantClear(&pVal);
|
||
|
hRes = pQualSet->Get(bszQualName,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszQualName);
|
||
|
if (ERROR_SUCCESS == hRes)
|
||
|
IsPointer = TRUE;
|
||
|
// Major fix required to get rid of temp
|
||
|
bszQualName = SysAllocString(L"extension");
|
||
|
VariantClear(&pVal);
|
||
|
hRes = pQualSet->Get(bszQualName,
|
||
|
0,
|
||
|
&pVal,
|
||
|
0);
|
||
|
SysFreeString(bszQualName);
|
||
|
if (ERROR_SUCCESS == hRes && NULL != pVal.bstrVal)
|
||
|
StringCchCopyW(strTemp, 30, pVal.bstrVal);
|
||
|
|
||
|
VariantClear(&pVal);
|
||
|
|
||
|
CimType = (CIMTYPE_ENUMERATION)(CimType & (~CIM_FLAG_ARRAY));
|
||
|
|
||
|
switch (CimType) {
|
||
|
case CIM_EMPTY:
|
||
|
Type = ItemUnknown;
|
||
|
break;
|
||
|
case CIM_SINT8:
|
||
|
Type = ItemCharShort;
|
||
|
if (!_wcsicmp(strFormat, L"c")){
|
||
|
Type = ItemChar;
|
||
|
}
|
||
|
break;
|
||
|
case CIM_UINT8:
|
||
|
Type = ItemUChar;
|
||
|
if (!_wcsicmp(strTemp, L"NoPrint")) {
|
||
|
Type = ItemCharHidden;
|
||
|
}
|
||
|
break;
|
||
|
case CIM_SINT16:
|
||
|
Type = ItemShort;
|
||
|
break;
|
||
|
case CIM_UINT16:
|
||
|
Type = ItemUShort;
|
||
|
if (!_wcsicmp(strTemp, L"TDIAddrType")) {
|
||
|
Type = ItemTDIAddr;
|
||
|
}
|
||
|
break;
|
||
|
case CIM_SINT32:
|
||
|
Type = ItemLong;
|
||
|
break;
|
||
|
case CIM_UINT32:
|
||
|
Type = ItemULong;
|
||
|
if (!_wcsicmp(strFormat, L"x")){
|
||
|
Type = ItemULongX;
|
||
|
}
|
||
|
break;
|
||
|
case CIM_SINT64:
|
||
|
Type = ItemLongLong;
|
||
|
break;
|
||
|
case CIM_UINT64:
|
||
|
Type = ItemULongLong;
|
||
|
break;
|
||
|
case CIM_BOOLEAN:
|
||
|
// ItemBool
|
||
|
Type = ItemBool;
|
||
|
break;
|
||
|
case CIM_STRING:
|
||
|
|
||
|
if (!_wcsicmp(strTermination, L"NullTerminated")) {
|
||
|
if (!_wcsicmp(strFormat, L"w"))
|
||
|
Type = ItemWString;
|
||
|
else
|
||
|
Type = ItemString;
|
||
|
}
|
||
|
else if (!_wcsicmp(strTermination, L"Counted")) {
|
||
|
if (!_wcsicmp(strFormat, L"w"))
|
||
|
Type = ItemPWString;
|
||
|
else
|
||
|
Type = ItemPString;
|
||
|
}
|
||
|
else if (!_wcsicmp(strTermination, L"ReverseCounted")) {
|
||
|
if (!_wcsicmp(strFormat, L"w"))
|
||
|
Type = ItemDSWString;
|
||
|
else
|
||
|
Type = ItemDSString;
|
||
|
}
|
||
|
else if (!_wcsicmp(strTermination, L"NotCounted")) {
|
||
|
Type = ItemNWString;
|
||
|
}else{
|
||
|
Type = ItemString;
|
||
|
}
|
||
|
break;
|
||
|
case CIM_CHAR16:
|
||
|
// ItemWChar
|
||
|
Type = ItemWChar;
|
||
|
break;
|
||
|
// Major fix required for executing methods from WBEM
|
||
|
case CIM_OBJECT :
|
||
|
if (!_wcsicmp(strTemp, L"Port"))
|
||
|
Type = ItemPort;
|
||
|
else if (!_wcsicmp(strTemp, L"SizeT"))
|
||
|
Type = ItemSizeT;
|
||
|
else if (!_wcsicmp(strTemp, L"RString"))
|
||
|
Type = ItemRString;
|
||
|
else if (!_wcsicmp(strTemp, L"RWString"))
|
||
|
Type = ItemRWString;
|
||
|
else if (!_wcsicmp(strTemp, L"IPAddr"))
|
||
|
Type = ItemIPAddr;
|
||
|
else if (!_wcsicmp(strTemp, L"Sid"))
|
||
|
Type = ItemSid;
|
||
|
else if (!_wcsicmp(strTemp, L"Guid"))
|
||
|
Type = ItemGuid;
|
||
|
else if (!_wcsicmp(strTemp, L"Variant"))
|
||
|
Type = ItemVariant;
|
||
|
else
|
||
|
Type = ItemUnknown;
|
||
|
break;
|
||
|
|
||
|
case CIM_REAL32:
|
||
|
case CIM_REAL64:
|
||
|
case CIM_DATETIME:
|
||
|
case CIM_REFERENCE:
|
||
|
case CIM_ILLEGAL:
|
||
|
default:
|
||
|
Type = ItemUnknown;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (IsPointer)
|
||
|
Type = ItemPtr;
|
||
|
return Type;
|
||
|
}
|
||
|
|
||
|
PVALUEMAP
|
||
|
GetValueMap( IWbemQualifierSet* pQualSet )
|
||
|
{
|
||
|
VARIANT var;
|
||
|
SAFEARRAY* saValues = NULL;
|
||
|
SAFEARRAY* saValueMap = NULL;
|
||
|
SAFEARRAY* saValueNumber = NULL;
|
||
|
PVALUEMAP pValueMap = NULL;
|
||
|
|
||
|
HRESULT hr;
|
||
|
DWORD dwValueType = VALUETYPE_INDEX;
|
||
|
|
||
|
if( pQualSet != NULL ){
|
||
|
hr = pQualSet->Get( L"ValueMap", 0, &var, NULL );
|
||
|
if( ERROR_SUCCESS == hr && (var.vt & VT_ARRAY) ){
|
||
|
saValueMap = var.parray;
|
||
|
}
|
||
|
|
||
|
hr = pQualSet->Get( L"Values", 0, &var, NULL );
|
||
|
if( SUCCEEDED(hr) && (var.vt & VT_ARRAY) ){
|
||
|
saValues = var.parray;
|
||
|
}
|
||
|
|
||
|
hr = pQualSet->Get( L"ValueType", 0, &var, NULL );
|
||
|
if( SUCCEEDED(hr) ){
|
||
|
if( _wcsicmp( var.bstrVal, L"index" ) == 0 ){
|
||
|
dwValueType = VALUETYPE_INDEX;
|
||
|
}
|
||
|
if( _wcsicmp( var.bstrVal, L"flag") == 0 ){
|
||
|
dwValueType = VALUETYPE_FLAG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( saValues != NULL && saValueMap != NULL ){
|
||
|
|
||
|
BSTR HUGEP *pValueMapData;
|
||
|
BSTR HUGEP *pValuesData;
|
||
|
LONG HUGEP *pValueNumberData;
|
||
|
|
||
|
LONG uMapBound, lMapBound;
|
||
|
LONG uValuesBound, lValuesBound;
|
||
|
|
||
|
SafeArrayGetUBound( saValueMap, 1, &uMapBound );
|
||
|
SafeArrayGetLBound( saValueMap, 1, &lMapBound );
|
||
|
SafeArrayAccessData( saValueMap, (void HUGEP **)&pValueMapData );
|
||
|
|
||
|
SafeArrayGetUBound( saValues, 1, &uValuesBound );
|
||
|
SafeArrayGetLBound( saValues, 1, &lValuesBound );
|
||
|
SafeArrayAccessData( saValues, (void HUGEP **)&pValuesData );
|
||
|
|
||
|
saValueNumber = SafeArrayCreateVector( VT_I4, 0, (uMapBound-lMapBound)+1 );
|
||
|
|
||
|
SafeArrayAccessData( saValueNumber, (void HUGEP **)&pValueNumberData );
|
||
|
|
||
|
for ( LONG i=lMapBound; i<=uMapBound; i++) {
|
||
|
|
||
|
if( i<lValuesBound || i>uValuesBound ){
|
||
|
pValueNumberData[i] = 0;
|
||
|
}else{
|
||
|
pValueNumberData[i] = StringToNumber( pValueMapData[i] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SafeArrayUnaccessData( saValueMap );
|
||
|
SafeArrayUnaccessData( saValues );
|
||
|
SafeArrayUnaccessData( saValueNumber );
|
||
|
|
||
|
pValueMap = (PVALUEMAP)malloc( sizeof(VALUEMAP) );
|
||
|
if( NULL == pValueMap ){
|
||
|
SafeArrayDestroy( saValueMap );
|
||
|
SafeArrayDestroy( saValues );
|
||
|
SafeArrayDestroy( saValueNumber );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
InsertTailList( &g_ValueMapTable, &pValueMap->Entry);
|
||
|
|
||
|
pValueMap->dwValueType = dwValueType;
|
||
|
pValueMap->saValueMap = saValueNumber;
|
||
|
pValueMap->saValues = saValues;
|
||
|
|
||
|
SafeArrayDestroy( saValueMap );
|
||
|
|
||
|
return pValueMap;
|
||
|
|
||
|
}else if( saValues != NULL ){
|
||
|
|
||
|
pValueMap = (PVALUEMAP)malloc( sizeof(VALUEMAP) );
|
||
|
|
||
|
if( NULL == pValueMap ){
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
InsertTailList( &g_ValueMapTable, &pValueMap->Entry);
|
||
|
|
||
|
pValueMap->dwValueType = VALUETYPE_INDEX;
|
||
|
pValueMap->saValueMap = NULL;
|
||
|
pValueMap->saValues = saValues;
|
||
|
|
||
|
return pValueMap;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetPropertiesFromWBEM(
|
||
|
IWbemClassObject *pTraceSubClasses,
|
||
|
GUID Guid,
|
||
|
SHORT nVersion,
|
||
|
CHAR nLevel,
|
||
|
SHORT nType,
|
||
|
BOOL bKernelEvent
|
||
|
)
|
||
|
{
|
||
|
IEnumWbemClassObject *pEnumTraceSubSubClasses = NULL;
|
||
|
IWbemClassObject *pTraceSubSubClasses = NULL;
|
||
|
IWbemQualifierSet *pQualSet = NULL;
|
||
|
|
||
|
PMOF_INFO pMofInfo = NULL;
|
||
|
PMOF_VERSION pMofLookup = NULL, pMofVersion = NULL;
|
||
|
|
||
|
BSTR bszClassName = NULL;
|
||
|
BSTR bszSubClassName = NULL;
|
||
|
BSTR bszWmiDataId = NULL;
|
||
|
BSTR bszEventType = NULL;
|
||
|
BSTR bszEventTypeName = NULL;
|
||
|
BSTR bszFriendlyName = NULL;
|
||
|
BSTR bszPropName = NULL;
|
||
|
|
||
|
WCHAR strClassName[MAXSTR];
|
||
|
WCHAR strType[MAXSTR];
|
||
|
LONG pVarType;
|
||
|
SHORT nEventType = EVENT_TYPE_DEFAULT;
|
||
|
|
||
|
LIST_ENTRY ListHead;
|
||
|
HRESULT hRes;
|
||
|
|
||
|
VARIANT pVal;
|
||
|
VARIANT pTypeVal;
|
||
|
VARIANT pTypeNameVal;
|
||
|
VARIANT pClassName;
|
||
|
ULONG lEventTypeWbem; // when types are in an array.
|
||
|
ULONG HUGEP *pTypeData;
|
||
|
BSTR HUGEP *pTypeNameData;
|
||
|
|
||
|
SAFEARRAY *PropArray = NULL;
|
||
|
SAFEARRAY *TypeArray = NULL;
|
||
|
SAFEARRAY *TypeNameArray = NULL;
|
||
|
|
||
|
long lLower, lUpper, lCount, IdIndex;
|
||
|
long lTypeLower, lTypeUpper;
|
||
|
long lTypeNameLower, lTypeNameUpper;
|
||
|
|
||
|
ULONG ArraySize;
|
||
|
|
||
|
ITEM_TYPE ItemType;
|
||
|
|
||
|
InitializeListHead(&ListHead);
|
||
|
|
||
|
VariantInit(&pVal);
|
||
|
VariantInit(&pTypeVal);
|
||
|
VariantInit(&pTypeNameVal);
|
||
|
VariantInit(&pClassName);
|
||
|
|
||
|
pMofInfo = GetMofInfoHead( &Guid );
|
||
|
if( NULL == pMofInfo ){
|
||
|
return NULL;
|
||
|
}
|
||
|
pMofInfo->bKernelEvent = bKernelEvent;
|
||
|
|
||
|
bszClassName = SysAllocString(L"__CLASS");
|
||
|
bszWmiDataId = SysAllocString(L"WmiDataId");
|
||
|
bszEventType = SysAllocString(L"EventType");
|
||
|
bszEventTypeName = SysAllocString(L"EventTypeName");
|
||
|
bszFriendlyName = SysAllocString(L"DisplayName");
|
||
|
|
||
|
hRes = pTraceSubClasses->Get(bszClassName, // property name
|
||
|
0L,
|
||
|
&pVal, // output to this variant
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (ERROR_SUCCESS == hRes){
|
||
|
if (pQualSet) {
|
||
|
pQualSet->Release();
|
||
|
pQualSet = NULL;
|
||
|
}
|
||
|
// Get Qualifier Set to obtain the friendly name.
|
||
|
pTraceSubClasses->GetQualifierSet(&pQualSet);
|
||
|
hRes = pQualSet->Get(bszFriendlyName,
|
||
|
0,
|
||
|
&pClassName,
|
||
|
0);
|
||
|
if (ERROR_SUCCESS == hRes && pClassName.bstrVal != NULL) {
|
||
|
StringCchCopyW(strClassName, MAXSTR, pClassName.bstrVal);
|
||
|
pMofInfo->strDescription = (LPWSTR)malloc((wcslen(strClassName) + 1) * sizeof(WCHAR));
|
||
|
if (NULL != pMofInfo->strDescription) {
|
||
|
StringCchCopyW(pMofInfo->strDescription, wcslen(strClassName) + 1, strClassName);
|
||
|
}
|
||
|
}else{
|
||
|
strClassName[0] = L'\0';
|
||
|
}
|
||
|
|
||
|
// Put Event Header
|
||
|
pMofVersion = GetNewMofVersion(
|
||
|
EVENT_TYPE_DEFAULT,
|
||
|
EVENT_VERSION_DEFAULT,
|
||
|
EVENT_LEVEL_DEFAULT
|
||
|
);
|
||
|
if (pMofVersion != NULL) {
|
||
|
pMofLookup = pMofVersion;
|
||
|
InsertTailList(&ListHead, &pMofVersion->Entry);
|
||
|
}
|
||
|
else{
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Create an enumerator to find derived classes.
|
||
|
bszSubClassName = SysAllocString(pVal.bstrVal);
|
||
|
hRes = pWbemServices->CreateClassEnum (
|
||
|
bszSubClassName, // class name
|
||
|
WBEM_FLAG_SHALLOW | WBEM_FLAG_USE_AMENDED_QUALIFIERS, // shallow search
|
||
|
NULL,
|
||
|
&pEnumTraceSubSubClasses
|
||
|
);
|
||
|
SysFreeString ( bszSubClassName );
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
ULONG uReturnedSub = 1;
|
||
|
|
||
|
while(uReturnedSub == 1){
|
||
|
// For each event in the subclass
|
||
|
pTraceSubSubClasses = NULL;
|
||
|
hRes = pEnumTraceSubSubClasses->Next((-1), // timeout in infinite seconds
|
||
|
1, // return just one instance
|
||
|
&pTraceSubSubClasses, // pointer to a Sub class
|
||
|
&uReturnedSub); // number obtained: one or zero
|
||
|
if (ERROR_SUCCESS == hRes && uReturnedSub == 1) {
|
||
|
if (pQualSet) {
|
||
|
pQualSet->Release();
|
||
|
pQualSet = NULL;
|
||
|
}
|
||
|
// Get Qualifier Set.
|
||
|
pTraceSubSubClasses->GetQualifierSet(&pQualSet);
|
||
|
// Get Type number among Qualifiers
|
||
|
VariantClear(&pTypeVal);
|
||
|
hRes = pQualSet->Get(bszEventType,
|
||
|
0,
|
||
|
&pTypeVal,
|
||
|
0);
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
TypeArray = NULL;
|
||
|
TypeNameArray = NULL;
|
||
|
if (pTypeVal.vt & VT_ARRAY) { // EventType is an array
|
||
|
TypeArray = pTypeVal.parray;
|
||
|
VariantClear(&pTypeNameVal);
|
||
|
hRes = pQualSet->Get(bszEventTypeName,
|
||
|
0,
|
||
|
&pTypeNameVal,
|
||
|
0);
|
||
|
if ((ERROR_SUCCESS == hRes) && (pTypeNameVal.vt & VT_ARRAY)) {
|
||
|
TypeNameArray = pTypeNameVal.parray;
|
||
|
}
|
||
|
if (TypeArray != NULL) {
|
||
|
hRes = SafeArrayGetLBound(TypeArray, 1, &lTypeLower);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
hRes = SafeArrayGetUBound(TypeArray, 1, &lTypeUpper);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
if (lTypeUpper < 0) {
|
||
|
break;
|
||
|
}
|
||
|
SafeArrayAccessData(TypeArray, (void HUGEP **)&pTypeData );
|
||
|
|
||
|
if (TypeNameArray != NULL) {
|
||
|
hRes = SafeArrayGetLBound(TypeNameArray, 1, &lTypeNameLower);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
hRes = SafeArrayGetUBound(TypeNameArray, 1, &lTypeNameUpper);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
if (lTypeNameUpper < 0)
|
||
|
break;
|
||
|
SafeArrayAccessData(TypeNameArray, (void HUGEP **)&pTypeNameData );
|
||
|
}
|
||
|
|
||
|
for (lCount = lTypeLower; lCount <= lTypeUpper; lCount++) {
|
||
|
lEventTypeWbem = pTypeData[lCount];
|
||
|
nEventType = (SHORT)lEventTypeWbem;
|
||
|
pMofVersion = GetNewMofVersion(nEventType, nVersion, nLevel);
|
||
|
if (pMofVersion != NULL) {
|
||
|
InsertTailList(&ListHead, &pMofVersion->Entry);
|
||
|
if (nType == nEventType) {
|
||
|
// Type matched
|
||
|
pMofLookup = pMofVersion;
|
||
|
}
|
||
|
if (TypeNameArray != NULL) {
|
||
|
if ((lCount >= lTypeNameLower) && (lCount <= lTypeNameUpper)) {
|
||
|
pMofVersion->strType = (LPWSTR)malloc((wcslen(pTypeNameData[lCount]) + 1) * sizeof(WCHAR));
|
||
|
if (pMofVersion->strType != NULL){
|
||
|
StringCchCopyW(pMofVersion->strType, wcslen(pTypeNameData[lCount]) + 1, (LPWSTR)(pTypeNameData[lCount]));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
SafeArrayUnaccessData(TypeArray);
|
||
|
SafeArrayDestroy(TypeArray);
|
||
|
VariantInit(&pTypeVal);
|
||
|
if (TypeNameArray != NULL) {
|
||
|
SafeArrayUnaccessData(TypeNameArray);
|
||
|
SafeArrayDestroy(TypeNameArray);
|
||
|
VariantInit(&pTypeNameVal);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// If the Types or TypeName is not found, then bail
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else { // EventType is scalar
|
||
|
hRes = VariantChangeType(&pTypeVal, &pTypeVal, 0, VT_I2);
|
||
|
if (ERROR_SUCCESS == hRes)
|
||
|
nEventType = (SHORT)V_I2(&pTypeVal);
|
||
|
else
|
||
|
nEventType = (SHORT)V_I4(&pTypeVal);
|
||
|
|
||
|
VariantClear(&pTypeNameVal);
|
||
|
hRes = pQualSet->Get(bszEventTypeName,
|
||
|
0,
|
||
|
&pTypeNameVal,
|
||
|
0);
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
StringCchCopyW(strType, MAXSTR, pTypeNameVal.bstrVal);
|
||
|
}
|
||
|
else{
|
||
|
strType[0] = '\0';
|
||
|
}
|
||
|
|
||
|
pMofVersion = GetNewMofVersion(nEventType, nVersion, nLevel);
|
||
|
if (pMofVersion != NULL) {
|
||
|
InsertTailList(&ListHead, &pMofVersion->Entry);
|
||
|
if (nType == nEventType) {
|
||
|
// Type matched
|
||
|
pMofLookup = pMofVersion;
|
||
|
}
|
||
|
pMofVersion->strType = (LPWSTR)malloc((wcslen(strType) + 1) * sizeof(WCHAR));
|
||
|
if (pMofVersion->strType != NULL){
|
||
|
StringCchCopyW(pMofVersion->strType, wcslen(strType) + 1, strType);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get event layout
|
||
|
VariantClear(&pVal);
|
||
|
IdIndex = 1;
|
||
|
V_VT(&pVal) = VT_I4;
|
||
|
V_I4(&pVal) = IdIndex;
|
||
|
// For each property
|
||
|
PropArray = NULL;
|
||
|
while (pTraceSubSubClasses->GetNames(bszWmiDataId, // only properties with WmiDataId qualifier
|
||
|
WBEM_FLAG_ONLY_IF_IDENTICAL,
|
||
|
&pVal, // WmiDataId number starting from 1
|
||
|
&PropArray) == WBEM_NO_ERROR) {
|
||
|
|
||
|
hRes = SafeArrayGetLBound(PropArray, 1, &lLower);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
hRes = SafeArrayGetUBound(PropArray, 1, &lUpper);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
if (lUpper < 0)
|
||
|
break;
|
||
|
// This loop will iterate just once.
|
||
|
for (lCount = lLower; lCount <= lUpper; lCount++) {
|
||
|
hRes = SafeArrayGetElement(PropArray, &lCount, &bszPropName);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
hRes = pTraceSubSubClasses->Get(bszPropName, // Property name
|
||
|
0L,
|
||
|
NULL,
|
||
|
&pVarType, // CIMTYPE of the property
|
||
|
NULL);
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Get the Qualifier set for the property
|
||
|
if (pQualSet) {
|
||
|
pQualSet->Release();
|
||
|
pQualSet = NULL;
|
||
|
}
|
||
|
hRes = pTraceSubSubClasses->GetPropertyQualifierSet(bszPropName,
|
||
|
&pQualSet);
|
||
|
|
||
|
if (ERROR_SUCCESS != hRes) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ItemType = GetItemType((CIMTYPE_ENUMERATION)pVarType, pQualSet);
|
||
|
|
||
|
if( pVarType & CIM_FLAG_ARRAY ){
|
||
|
ArraySize = GetArraySize(pQualSet);
|
||
|
}else{
|
||
|
ArraySize = 1;
|
||
|
}
|
||
|
|
||
|
PVALUEMAP pValueMap = NULL;
|
||
|
|
||
|
pValueMap = GetValueMap( pQualSet );
|
||
|
|
||
|
AddMofInfo(&ListHead,
|
||
|
bszPropName,
|
||
|
ItemType,
|
||
|
ArraySize,
|
||
|
pValueMap );
|
||
|
}
|
||
|
|
||
|
SafeArrayDestroy(PropArray);
|
||
|
PropArray = NULL;
|
||
|
V_I4(&pVal) = ++IdIndex;
|
||
|
} // end enumerating through WmiDataId
|
||
|
|
||
|
FlushMofVersionList(pMofInfo, &ListHead);
|
||
|
} // if getting event type was successful
|
||
|
} // if enumeration returned a subclass successfully
|
||
|
} // end enumerating subclasses
|
||
|
} // if enumeration was created successfully
|
||
|
} // if getting class name was successful
|
||
|
|
||
|
cleanup:
|
||
|
VariantClear(&pVal);
|
||
|
VariantClear(&pTypeVal);
|
||
|
VariantClear(&pClassName);
|
||
|
|
||
|
SysFreeString(bszClassName);
|
||
|
SysFreeString(bszWmiDataId);
|
||
|
SysFreeString(bszEventType);
|
||
|
SysFreeString(bszEventTypeName);
|
||
|
SysFreeString(bszFriendlyName);
|
||
|
// Should not free bszPropName becuase it is already freed by SafeArrayDestroy
|
||
|
|
||
|
FlushMofVersionList(pMofInfo, &ListHead);
|
||
|
|
||
|
return pMofLookup;
|
||
|
}
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsWBEM ( GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent )
|
||
|
{
|
||
|
IEnumWbemClassObject *pEnumTraceSubClasses = NULL, *pEnumTraceSubSubClasses = NULL;
|
||
|
IWbemClassObject *pTraceSubClasses = NULL, *pTraceSubSubClasses = NULL;
|
||
|
IWbemQualifierSet *pQualSet = NULL;
|
||
|
|
||
|
BSTR bszInstance = NULL;
|
||
|
BSTR bszPropertyName = NULL;
|
||
|
BSTR bszSubClassName = NULL;
|
||
|
BSTR bszGuid = NULL;
|
||
|
BSTR bszVersion = NULL;
|
||
|
|
||
|
WCHAR strGuid[MAXGUIDSTR], strTargetGuid[MAXGUIDSTR];
|
||
|
|
||
|
HRESULT hRes;
|
||
|
|
||
|
VARIANT pVal;
|
||
|
VARIANT pGuidVal;
|
||
|
VARIANT pVersionVal;
|
||
|
|
||
|
UINT nCounter=0;
|
||
|
BOOLEAN MatchFound;
|
||
|
SHORT nEventVersion = EVENT_VERSION_DEFAULT;
|
||
|
|
||
|
PMOF_VERSION pMofLookup = NULL;
|
||
|
|
||
|
VariantInit(&pVal);
|
||
|
VariantInit(&pGuidVal);
|
||
|
VariantInit(&pVersionVal);
|
||
|
|
||
|
if (NULL == pWbemServices) {
|
||
|
hRes = WbemConnect( &pWbemServices );
|
||
|
CHECK_HR( hRes );
|
||
|
}
|
||
|
|
||
|
// Convert traget GUID to string for later comparison
|
||
|
CpdiGuidToString(strTargetGuid, MAXGUIDSTR, &Guid);
|
||
|
|
||
|
bszInstance = SysAllocString(L"EventTrace");
|
||
|
bszPropertyName = SysAllocString(L"__CLASS");
|
||
|
bszGuid = SysAllocString(L"Guid");
|
||
|
bszVersion = SysAllocString(L"EventVersion");
|
||
|
pEnumTraceSubClasses = NULL;
|
||
|
|
||
|
// Get an enumerator for all classes under "EventTace".
|
||
|
hRes = pWbemServices->CreateClassEnum (
|
||
|
bszInstance,
|
||
|
WBEM_FLAG_SHALLOW | WBEM_FLAG_USE_AMENDED_QUALIFIERS,
|
||
|
NULL,
|
||
|
&pEnumTraceSubClasses );
|
||
|
SysFreeString (bszInstance);
|
||
|
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
ULONG uReturned = 1;
|
||
|
MatchFound = FALSE;
|
||
|
while (uReturned == 1) {
|
||
|
pTraceSubClasses = NULL;
|
||
|
// Get the next ClassObject.
|
||
|
hRes = pEnumTraceSubClasses->Next((-1), // timeout in infinite seconds
|
||
|
1, // return just one instance
|
||
|
&pTraceSubClasses, // pointer to Event Trace Sub Class
|
||
|
&uReturned); // number obtained: one or zero
|
||
|
if (ERROR_SUCCESS == hRes && (uReturned == 1)) {
|
||
|
// Get the class name
|
||
|
hRes = pTraceSubClasses->Get(bszPropertyName, // property name
|
||
|
0L,
|
||
|
&pVal, // output to this variant
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (ERROR_SUCCESS == hRes){
|
||
|
|
||
|
bszSubClassName = SysAllocString(pVal.bstrVal);
|
||
|
// Create an enumerator to find derived classes.
|
||
|
hRes = pWbemServices->CreateClassEnum (
|
||
|
bszSubClassName,
|
||
|
WBEM_FLAG_SHALLOW | WBEM_FLAG_USE_AMENDED_QUALIFIERS,
|
||
|
NULL,
|
||
|
&pEnumTraceSubSubClasses
|
||
|
);
|
||
|
SysFreeString ( bszSubClassName );
|
||
|
VariantClear(&pVal);
|
||
|
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
|
||
|
ULONG uReturnedSub = 1;
|
||
|
MatchFound = FALSE;
|
||
|
|
||
|
while(uReturnedSub == 1){
|
||
|
|
||
|
pTraceSubSubClasses = NULL;
|
||
|
// enumerate through the resultset.
|
||
|
hRes = pEnumTraceSubSubClasses->Next((-1), // timeout in infinite seconds
|
||
|
1, // return just one instance
|
||
|
&pTraceSubSubClasses, // pointer to a Sub class
|
||
|
&uReturnedSub); // number obtained: one or zero
|
||
|
if (ERROR_SUCCESS == hRes && uReturnedSub == 1) {
|
||
|
// Get the subclass name
|
||
|
hRes = pTraceSubSubClasses->Get(bszPropertyName, // Class name
|
||
|
0L,
|
||
|
&pVal, // output to this variant
|
||
|
NULL,
|
||
|
NULL);
|
||
|
VariantClear(&pVal);
|
||
|
|
||
|
if (ERROR_SUCCESS == hRes){
|
||
|
|
||
|
// Get Qualifier Set.
|
||
|
if (pQualSet) {
|
||
|
pQualSet->Release();
|
||
|
pQualSet = NULL;
|
||
|
}
|
||
|
pTraceSubSubClasses->GetQualifierSet (&pQualSet );
|
||
|
|
||
|
// Get GUID among Qualifiers
|
||
|
hRes = pQualSet->Get(bszGuid,
|
||
|
0,
|
||
|
&pGuidVal,
|
||
|
0);
|
||
|
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
StringCchCopyW(strGuid, MAXGUIDSTR, (LPWSTR)V_BSTR(&pGuidVal));
|
||
|
VariantClear ( &pGuidVal );
|
||
|
|
||
|
if (!wcsstr(strGuid, L"{")) {
|
||
|
WCHAR strTempGuid[MAXGUIDSTR];
|
||
|
StringCchCopyW(strTempGuid, MAXGUIDSTR, strGuid);
|
||
|
StringCchPrintfW(strGuid, MAXGUIDSTR, L"{%ws}", strTempGuid);
|
||
|
}
|
||
|
|
||
|
if (!_wcsicmp(strTargetGuid, strGuid)) {
|
||
|
hRes = pQualSet->Get(bszVersion,
|
||
|
0,
|
||
|
&pVersionVal,
|
||
|
0);
|
||
|
if (ERROR_SUCCESS == hRes) {
|
||
|
hRes = VariantChangeType(&pVersionVal, &pVersionVal, 0, VT_I2);
|
||
|
if (ERROR_SUCCESS == hRes)
|
||
|
nEventVersion = (SHORT)V_I2(&pVersionVal);
|
||
|
else
|
||
|
nEventVersion = (SHORT)V_I4(&pVersionVal);
|
||
|
VariantClear(&pVersionVal);
|
||
|
|
||
|
if (nVersion == nEventVersion) {
|
||
|
// Match is found.
|
||
|
// Now put all events in this subtree into the list
|
||
|
MatchFound = TRUE;
|
||
|
pMofLookup = GetPropertiesFromWBEM( pTraceSubSubClasses,
|
||
|
Guid,
|
||
|
nVersion,
|
||
|
nLevel,
|
||
|
nType,
|
||
|
bKernelEvent
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
// if there is no version number for this event
|
||
|
MatchFound = TRUE;
|
||
|
//_tprintf(_T("Close Match Found: \t%s\t, version %d\n"), strGuid, nEventVersion);
|
||
|
pMofLookup = GetPropertiesFromWBEM( pTraceSubSubClasses,
|
||
|
Guid,
|
||
|
EVENT_VERSION_DEFAULT,
|
||
|
nLevel,
|
||
|
nType,
|
||
|
bKernelEvent
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} // end while enumerating sub classes
|
||
|
if (MatchFound) {
|
||
|
break;
|
||
|
}
|
||
|
if (pEnumTraceSubSubClasses) {
|
||
|
pEnumTraceSubSubClasses->Release();
|
||
|
pEnumTraceSubSubClasses = NULL;
|
||
|
}
|
||
|
} // if creating enumeration was successful
|
||
|
} // if getting class name was successful
|
||
|
}
|
||
|
nCounter++;
|
||
|
// if match is found, break out of the top level search
|
||
|
if (MatchFound)
|
||
|
break;
|
||
|
} // end while enumerating top classes
|
||
|
if( pEnumTraceSubClasses ){
|
||
|
pEnumTraceSubClasses->Release();
|
||
|
pEnumTraceSubClasses = NULL;
|
||
|
}
|
||
|
} // if creating enumeration for top level is successful
|
||
|
|
||
|
cleanup:
|
||
|
|
||
|
VariantClear(&pGuidVal);
|
||
|
VariantClear(&pVersionVal);
|
||
|
|
||
|
SysFreeString(bszGuid);
|
||
|
SysFreeString(bszPropertyName);
|
||
|
SysFreeString(bszVersion);
|
||
|
|
||
|
if (pEnumTraceSubClasses){
|
||
|
pEnumTraceSubClasses->Release();
|
||
|
pEnumTraceSubClasses = NULL;
|
||
|
}
|
||
|
if (pEnumTraceSubSubClasses){
|
||
|
pEnumTraceSubSubClasses->Release();
|
||
|
pEnumTraceSubSubClasses = NULL;
|
||
|
}
|
||
|
if (pQualSet) {
|
||
|
pQualSet->Release();
|
||
|
pQualSet = NULL;
|
||
|
}
|
||
|
|
||
|
return pMofLookup;
|
||
|
}
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsMofFiles ( GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent )
|
||
|
{
|
||
|
FILE *f = NULL;
|
||
|
PMOF_VERSION pMofLookup = NULL;
|
||
|
//
|
||
|
// If MofFileName is given, use it. Otherwise, look for
|
||
|
// the default file mofdata.guid
|
||
|
//
|
||
|
|
||
|
if (TraceContext->MofFileName != NULL) {
|
||
|
f = _wfopen( TraceContext->MofFileName, L"r" );
|
||
|
if( f != NULL ){
|
||
|
pMofLookup = GetGuidsFile(f, Guid, nVersion, nLevel, nType, bKernelEvent);
|
||
|
fclose(f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((pMofLookup == NULL) && (TraceContext->DefMofFileName != NULL)) {
|
||
|
f = _wfopen( TraceContext->DefMofFileName, L"r" );
|
||
|
if( f != NULL ){
|
||
|
pMofLookup = GetGuidsFile(f, Guid, nVersion, nLevel, nType, bKernelEvent);
|
||
|
fclose(f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pMofLookup;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
PMOF_VERSION
|
||
|
GetGuidsFile( FILE *f, GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent )
|
||
|
{
|
||
|
WCHAR line[MAXSTR];
|
||
|
WCHAR buffer[MAXSTR];
|
||
|
|
||
|
PMOF_INFO pMofInfo = NULL;
|
||
|
PMOF_VERSION pMofLookup = NULL;
|
||
|
PMOF_VERSION pMofVersion = NULL;
|
||
|
|
||
|
UINT i;
|
||
|
LPWSTR s;
|
||
|
UINT typeCount = 0;
|
||
|
BOOL bInInfo = FALSE;
|
||
|
BOOL bInGuid = FALSE;
|
||
|
|
||
|
SHORT nTypeIndex;
|
||
|
CHAR nLevelIndex = -1;
|
||
|
SHORT nVersionIndex = -1;
|
||
|
SHORT nMatchLevel = 0;
|
||
|
|
||
|
GUID guid;
|
||
|
|
||
|
LIST_ENTRY ListHead;
|
||
|
|
||
|
InitializeListHead( &ListHead );
|
||
|
|
||
|
//
|
||
|
// If MofFileName is given, use it. Otherwise, look for
|
||
|
// the default file mofdata.guid
|
||
|
//
|
||
|
|
||
|
while ( fgetws(line, MAXSTR, f) != NULL ) {
|
||
|
UINT Index;
|
||
|
if(line[0] == '/'){
|
||
|
continue;
|
||
|
}
|
||
|
if(line[0] == '{' && bInGuid ){
|
||
|
bInInfo = TRUE;
|
||
|
}
|
||
|
else if ( line[0] == '}' && bInGuid ){
|
||
|
bInInfo = FALSE;
|
||
|
FlushMofVersionList( pMofInfo, &ListHead );
|
||
|
}
|
||
|
else if( bInInfo && bInGuid ){
|
||
|
ITEM_TYPE type;
|
||
|
LPWSTR strValue;
|
||
|
|
||
|
Index = 1;
|
||
|
strValue = wcstok(line, L"\n\t\r,");
|
||
|
|
||
|
s = wcstok( NULL, L" \n\t\r,[");
|
||
|
if(s != NULL && strValue != NULL ){
|
||
|
PWCHAR t;
|
||
|
|
||
|
while (*strValue == ' ') { // skip leading blanks
|
||
|
strValue++;
|
||
|
}
|
||
|
t = wcstok(NULL, L"]" );
|
||
|
|
||
|
if (t != NULL) {
|
||
|
Index = _wtoi(t);
|
||
|
}
|
||
|
|
||
|
if(! _wcsicmp(s,STR_ItemChar)) type = ItemChar;
|
||
|
else if(! _wcsicmp(s,STR_ItemCharHidden)) type = ItemCharHidden;
|
||
|
else if(! _wcsicmp(s,STR_ItemUChar)) type = ItemUChar;
|
||
|
else if(! _wcsicmp(s,STR_ItemWChar)) type = ItemWChar;
|
||
|
else if(! _wcsicmp(s,STR_ItemCharShort))type = ItemCharShort;
|
||
|
else if(! _wcsicmp(s,STR_ItemCharSign)) type = ItemCharSign;
|
||
|
else if(! _wcsicmp(s,STR_ItemShort)) type = ItemShort;
|
||
|
else if(! _wcsicmp(s,STR_ItemUShort)) type = ItemUShort;
|
||
|
else if(! _wcsicmp(s,STR_ItemLong)) type = ItemLong;
|
||
|
else if(! _wcsicmp(s,STR_ItemULong)) type = ItemULong;
|
||
|
else if(! _wcsicmp(s,STR_ItemULongX)) type = ItemULongX;
|
||
|
else if(! _wcsicmp(s,STR_ItemLongLong)) type = ItemLongLong;
|
||
|
else if(! _wcsicmp(s,STR_ItemULongLong)) type = ItemULongLong;
|
||
|
else if(! _wcsicmp(s,STR_ItemString)) type = ItemString;
|
||
|
else if(! _wcsicmp(s,STR_ItemWString)) type = ItemWString;
|
||
|
else if(! _wcsicmp(s,STR_ItemRString)) type = ItemRString;
|
||
|
else if(! _wcsicmp(s,STR_ItemRWString)) type = ItemRWString;
|
||
|
else if(! _wcsicmp(s,STR_ItemPString)) type = ItemPString;
|
||
|
else if(! _wcsicmp(s,STR_ItemMLString)) type = ItemMLString;
|
||
|
else if(! _wcsicmp(s,STR_ItemNWString)) type = ItemNWString;
|
||
|
else if(! _wcsicmp(s,STR_ItemPWString)) type = ItemPWString;
|
||
|
else if(! _wcsicmp(s,STR_ItemDSString)) type = ItemDSString;
|
||
|
else if(! _wcsicmp(s,STR_ItemDSWString)) type = ItemDSWString;
|
||
|
else if(! _wcsicmp(s,STR_ItemSid)) type = ItemSid;
|
||
|
else if(! _wcsicmp(s,STR_ItemChar4)) type = ItemChar4;
|
||
|
else if(! _wcsicmp(s,STR_ItemIPAddr)) type = ItemIPAddr;
|
||
|
else if(! _wcsicmp(s,STR_ItemTDIAddr)) type = ItemTDIAddr;
|
||
|
else if(! _wcsicmp(s,STR_ItemPort)) type = ItemPort;
|
||
|
else if(! _wcsicmp(s,STR_ItemPtr)) type = ItemPtr;
|
||
|
else if(! _wcsicmp(s,STR_ItemSizeT)) type = ItemSizeT;
|
||
|
else if(! _wcsicmp(s,STR_ItemGuid)) type = ItemGuid;
|
||
|
else if(! _wcsicmp(s,STR_ItemOptArgs)) type = ItemOptArgs;
|
||
|
else if(! _wcsicmp(s,STR_ItemCPUTime)) type = ItemCPUTime;
|
||
|
else if(! _wcsicmp(s,STR_ItemVariant)) type = ItemVariant;
|
||
|
else if(! _wcsicmp(s,STR_ItemBool)) type = ItemBool;
|
||
|
else type = ItemUnknown;
|
||
|
|
||
|
AddMofInfo( &ListHead, strValue, (SHORT)type, Index, NULL );
|
||
|
}
|
||
|
}
|
||
|
else if( line[0] == '#' && bInGuid ){
|
||
|
LPWSTR strType;
|
||
|
LPWSTR strValue;
|
||
|
|
||
|
s = wcstok( line, L" \t");
|
||
|
if( NULL == s ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( line[1] == 'l' || line[1] == 'L' ){ // level
|
||
|
|
||
|
strValue = wcstok( NULL, L" \t\n\r" );
|
||
|
if( strValue != NULL ){
|
||
|
nLevelIndex = (CHAR)_wtoi( strValue );
|
||
|
}
|
||
|
|
||
|
}else if( line[1] == 'v' || line[1] == 'V' ){ // version
|
||
|
|
||
|
strValue = wcstok( NULL, L" \t\n\r" );
|
||
|
if( strValue != NULL ){
|
||
|
nVersionIndex = (SHORT)_wtoi( strValue );
|
||
|
}
|
||
|
typeCount = 0;
|
||
|
|
||
|
}else if( line[1] == 't' || line[1] == 'T' ){ // type
|
||
|
|
||
|
SHORT nMatchCheck = 0;
|
||
|
|
||
|
strType = wcstok( NULL, L" \t\n\r" );
|
||
|
strValue = wcstok( NULL, L"\"\n,\r" );
|
||
|
|
||
|
if( strType && strValue ){
|
||
|
nTypeIndex = (SHORT)_wtoi( strValue );
|
||
|
}else{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
typeCount++;
|
||
|
if (typeCount >= MAXTYPE) {
|
||
|
//fwprintf(stderr, L"Warning: Too many types defined\n");
|
||
|
}
|
||
|
|
||
|
pMofVersion = GetNewMofVersion( nTypeIndex, nVersionIndex, nLevelIndex );
|
||
|
|
||
|
if( NULL != pMofVersion ){
|
||
|
InsertTailList( (&ListHead), &pMofVersion->Entry);
|
||
|
|
||
|
pMofVersion->strType = (LPWSTR)malloc( (lstrlenW(strType)+1) * sizeof(WCHAR) );
|
||
|
|
||
|
if( NULL != pMofVersion->strType ){
|
||
|
StringCchCopyW( pMofVersion->strType, lstrlenW(strType)+1, strType );
|
||
|
}
|
||
|
|
||
|
if( nTypeIndex == nType ){
|
||
|
nMatchCheck = 1;
|
||
|
if( nLevelIndex == nLevel ){
|
||
|
nMatchCheck++;
|
||
|
}
|
||
|
if( nVersionIndex == nVersion ){
|
||
|
nMatchCheck++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if( nMatchCheck > nMatchLevel ){
|
||
|
nMatchLevel = nMatchCheck;
|
||
|
pMofLookup = pMofVersion;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ( (line[0] >= '0' && line[0] <= '9')
|
||
|
|| (line[0] >= 'a' && line[0] <= 'f')
|
||
|
|| (line[0] >= 'A' && line[0] <= 'F')) {
|
||
|
|
||
|
LPWSTR strName = NULL;
|
||
|
bInGuid = FALSE;
|
||
|
|
||
|
typeCount = 0;
|
||
|
|
||
|
wcsncpy(buffer, line, 8);
|
||
|
buffer[8] = 0;
|
||
|
guid.Data1 = ahextoi(&buffer[0]);
|
||
|
|
||
|
wcsncpy(buffer, &line[9], 4);
|
||
|
buffer[4] = 0;
|
||
|
guid.Data2 = (USHORT) ahextoi(&buffer[0]);
|
||
|
|
||
|
wcsncpy(buffer, &line[14], 4);
|
||
|
buffer[4] = 0;
|
||
|
guid.Data3 = (USHORT) ahextoi(buffer);
|
||
|
|
||
|
for (i=0; i<2; i++) {
|
||
|
wcsncpy(buffer, &line[19 + (i*2)], 2);
|
||
|
buffer[2] = 0;
|
||
|
guid.Data4[i] = (UCHAR) ahextoi(buffer);
|
||
|
}
|
||
|
for (i=2; i<8; i++) {
|
||
|
wcsncpy(buffer, &line[20 + (i*2)], 2);
|
||
|
buffer[2] = 0;
|
||
|
guid.Data4[i] = (UCHAR) ahextoi(buffer);
|
||
|
}
|
||
|
|
||
|
if( ! IsEqualGUID( &Guid, &guid ) ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
s = &line[36];
|
||
|
|
||
|
strName = wcstok( s, L" \n\t\r" );
|
||
|
|
||
|
if( NULL == strName ){ // Must have a name for the Guid.
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
bInGuid = TRUE;
|
||
|
FlushMofVersionList(pMofInfo, &ListHead);
|
||
|
|
||
|
pMofInfo = GetMofInfoHead(&Guid);
|
||
|
if (pMofInfo == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
pMofInfo->bKernelEvent = bKernelEvent;
|
||
|
pMofInfo->strDescription = (LPWSTR)malloc((lstrlenW(strName)+1) * sizeof(WCHAR));
|
||
|
if( NULL != pMofInfo->strDescription ){
|
||
|
StringCchCopyW(pMofInfo->strDescription, lstrlenW(strName)+1, strName);
|
||
|
}
|
||
|
|
||
|
|
||
|
pMofVersion = GetNewMofVersion(
|
||
|
EVENT_TYPE_DEFAULT,
|
||
|
EVENT_VERSION_DEFAULT,
|
||
|
EVENT_LEVEL_DEFAULT
|
||
|
);
|
||
|
|
||
|
if (pMofVersion == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pMofLookup = pMofVersion;
|
||
|
InsertTailList( (&ListHead), &pMofVersion->Entry);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
FlushMofVersionList(pMofInfo, &ListHead );
|
||
|
return pMofLookup;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
UpdateThreadPrintData(
|
||
|
PPRINT_JOB_RECORD pJob,
|
||
|
PEVENT_TRACE_HEADER pHeader,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
unsigned long i = 0;
|
||
|
BOOLEAN bFound = FALSE;
|
||
|
|
||
|
if ( (pJob == NULL) || (pHeader == NULL) || (pThread == NULL) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < pJob->NumberOfThreads; i++) {
|
||
|
if (pJob->ThreadData[i].ThreadId == pHeader->ThreadId) {
|
||
|
bFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ((i < MAX_THREADS) && !bFound) {
|
||
|
pJob->ThreadData[i].ThreadId = pHeader->ThreadId;
|
||
|
pJob->NumberOfThreads++;
|
||
|
bFound = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bFound) {
|
||
|
//
|
||
|
// TODO: There is potential for double counting if the same thread
|
||
|
// came back and did more work for this job after having done work for an other
|
||
|
// job in between.
|
||
|
//
|
||
|
if (pJob->ThreadData[i].PrevKCPUTime > 0)
|
||
|
pJob->ThreadData[i].KCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pJob->ThreadData[i].PrevKCPUTime;
|
||
|
if (pJob->ThreadData[i].PrevUCPUTime > 0)
|
||
|
pJob->ThreadData[i].UCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pJob->ThreadData[i].PrevUCPUTime;
|
||
|
if (pJob->ThreadData[i].PrevReadIO > 0)
|
||
|
pJob->ThreadData[i].ReadIO += pThread->ReadIO - pJob->ThreadData[i].PrevReadIO;
|
||
|
if (pJob->ThreadData[i].PrevWriteIO > 0)
|
||
|
pJob->ThreadData[i].WriteIO += pThread->WriteIO - pJob->ThreadData[i].PrevWriteIO;
|
||
|
|
||
|
pJob->ThreadData[i].PrevKCPUTime = pHeader->KernelTime * CurrentSystem.TimerResolution;
|
||
|
pJob->ThreadData[i].PrevUCPUTime = pHeader->UserTime * CurrentSystem.TimerResolution;
|
||
|
pJob->ThreadData[i].PrevReadIO = pThread->ReadIO;
|
||
|
pJob->ThreadData[i].PrevWriteIO = pThread->WriteIO;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PrintJobCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_RECORD pThread;
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
PMOF_INFO pMofInfo;
|
||
|
ULONG JobId = 0;
|
||
|
PPRINT_JOB_RECORD pJob;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
//
|
||
|
// Ignore Process/Thread Start/End transactions. Only go after
|
||
|
// User Defined Transactions.
|
||
|
//
|
||
|
pMofInfo = GetMofInfoHead( &pEvent->Header.Guid );
|
||
|
if (pMofInfo == NULL){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!IsEqualGUID(&pEvent->Header.Guid, &ThreadGuid))
|
||
|
GetMofData(pEvent, L"JobId", &JobId, sizeof(ULONG));
|
||
|
|
||
|
pThread = FindGlobalThreadById(pHeader->ThreadId, pEvent);
|
||
|
|
||
|
|
||
|
if (JobId == 0) {
|
||
|
if (pThread == NULL) return;
|
||
|
JobId = pThread->JobId; // if Current Job Id is 0, use the cached one.
|
||
|
}
|
||
|
else {
|
||
|
if (pThread != NULL) {
|
||
|
if (JobId != pThread->JobId) {
|
||
|
pJob = FindPrintJobRecord(pThread->JobId);
|
||
|
UpdateThreadPrintData(pJob, pHeader, pThread);
|
||
|
}
|
||
|
|
||
|
pThread->JobId = JobId;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (JobId == 0) return; // To filter all th termination without print jobs.
|
||
|
|
||
|
|
||
|
pJob = FindPrintJobRecord(JobId);
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_SPOOLJOB) {
|
||
|
if (pJob) {
|
||
|
// A job id is being reused before it was deleted from the last
|
||
|
// use. We must have missed a delete event, so just through the old
|
||
|
// job away.
|
||
|
DeletePrintJobRecord(pJob, FALSE);
|
||
|
}
|
||
|
pJob = AddPrintJobRecord(JobId);
|
||
|
if (pJob != NULL) {
|
||
|
pJob->StartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pJob == NULL) // if a Start event is lost for this job, this could happen.
|
||
|
return;
|
||
|
|
||
|
UpdateThreadPrintData(pJob, pHeader, pThread);
|
||
|
|
||
|
// If you see any of these things then stop tracking resources on the
|
||
|
// thread.
|
||
|
if ((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_ENDTRACKTHREAD) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_DELETEJOB) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_PAUSE) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_RESUME)) {
|
||
|
if (pThread != NULL)
|
||
|
pThread->JobId = 0;
|
||
|
}
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_PAUSE) {
|
||
|
pJob->PauseStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_RESUME) {
|
||
|
pJob->PauseTime += (pEvent->Header.TimeStamp.QuadPart - pJob->PauseStartTime) / 10000;
|
||
|
pJob->PauseStartTime = 0;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_PRINTJOB) {
|
||
|
pJob->PrintJobTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_DELETEJOB) {
|
||
|
unsigned long i;
|
||
|
pJob->EndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
pJob->ResponseTime += (pEvent->Header.TimeStamp.QuadPart - pJob->StartTime) / 10000; // in msec
|
||
|
GetMofData(pEvent, L"JobSize", &pJob->JobSize, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"DataType", &pJob->DataType, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"Pages", &pJob->Pages, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"PagesPerSide", &pJob->PagesPerSide, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"FilesOpened", &pJob->FilesOpened, sizeof(SHORT));
|
||
|
|
||
|
pJob->KCPUTime = 0;
|
||
|
pJob->UCPUTime = 0;
|
||
|
pJob->ReadIO = 0;
|
||
|
pJob->WriteIO = 0;
|
||
|
for (i=0; i < pJob->NumberOfThreads; i++) {
|
||
|
pJob->KCPUTime += pJob->ThreadData[i].KCPUTime;
|
||
|
pJob->UCPUTime += pJob->ThreadData[i].UCPUTime;
|
||
|
pJob->ReadIO += pJob->ThreadData[i].ReadIO;
|
||
|
pJob->WriteIO += pJob->ThreadData[i].WriteIO;
|
||
|
|
||
|
}
|
||
|
DeletePrintJobRecord(pJob, TRUE);
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_SPL_JOBRENDERED) {
|
||
|
GetMofData(pEvent, L"GdiJobSize", &pJob->GdiJobSize, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"ICMMethod", &pJob->ICMMethod, sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"Color", &pJob->Color, sizeof(SHORT));
|
||
|
GetMofData(pEvent, L"XRes", &pJob->XRes, sizeof(SHORT));
|
||
|
GetMofData(pEvent, L"YRes", &pJob->YRes, sizeof(SHORT));
|
||
|
GetMofData(pEvent, L"Quality", &pJob->Quality, sizeof(SHORT));
|
||
|
GetMofData(pEvent, L"Copies", &pJob->Copies, sizeof(SHORT));
|
||
|
GetMofData(pEvent, L"TTOption", &pJob->TTOption, sizeof(SHORT));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
UpdateThreadIisData(
|
||
|
PHTTP_REQUEST_RECORD pReq,
|
||
|
PEVENT_TRACE_HEADER pHeader,
|
||
|
PTHREAD_RECORD pThread
|
||
|
)
|
||
|
{
|
||
|
unsigned long i = 0;
|
||
|
BOOLEAN bFound = FALSE;
|
||
|
|
||
|
if ( (pReq == NULL) || (pHeader == NULL) || (pThread == NULL) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < pReq->NumberOfThreads; i++) {
|
||
|
if (pReq->ThreadData[i].ThreadId == pHeader->ThreadId) {
|
||
|
if (i != pReq->CurrentThreadIndex) {
|
||
|
// This means the same thread worked on the same request multiple times after having done
|
||
|
// work for another job in between.
|
||
|
// This will result in double counting. We should set the previous time and exit.
|
||
|
pReq->ThreadData[i].PrevKCPUTime = pHeader->KernelTime * CurrentSystem.TimerResolution;
|
||
|
pReq->ThreadData[i].PrevUCPUTime = pHeader->UserTime * CurrentSystem.TimerResolution;
|
||
|
pReq->ThreadData[i].PrevReadIO = pThread->ReadIO;
|
||
|
pReq->ThreadData[i].PrevWriteIO = pThread->WriteIO;
|
||
|
|
||
|
pReq->CurrentThreadIndex = i;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
bFound = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ((i < MAX_THREADS) && !bFound) {
|
||
|
pReq->ThreadData[i].ThreadId = pHeader->ThreadId;
|
||
|
pReq->NumberOfThreads++;
|
||
|
bFound = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bFound) {
|
||
|
|
||
|
if (pHeader->KernelTime * CurrentSystem.TimerResolution < pReq->ThreadData[i].PrevKCPUTime) {
|
||
|
pReq->ThreadData[i].PrevKCPUTime = pHeader->KernelTime * CurrentSystem.TimerResolution;
|
||
|
}
|
||
|
if (pHeader->UserTime * CurrentSystem.TimerResolution < pReq->ThreadData[i].PrevUCPUTime) {
|
||
|
pReq->ThreadData[i].PrevUCPUTime = pHeader->UserTime * CurrentSystem.TimerResolution;
|
||
|
}
|
||
|
|
||
|
// New for IIS Events
|
||
|
// Due to the hook placements, we needed to tweak which routine (UL, W3core, W3filter,
|
||
|
// ISAPI, ASP, CGI) we need to charge CPU time to.
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0)
|
||
|
pReq->ThreadData[i].KCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0)
|
||
|
pReq->ThreadData[i].UCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
if (pReq->ThreadData[i].PrevReadIO > 0)
|
||
|
pReq->ThreadData[i].ReadIO += pThread->ReadIO - pReq->ThreadData[i].PrevReadIO;
|
||
|
if (pReq->ThreadData[i].PrevWriteIO > 0)
|
||
|
pReq->ThreadData[i].WriteIO += pThread->WriteIO - pReq->ThreadData[i].PrevWriteIO;
|
||
|
|
||
|
if (IsEqualGUID(&pHeader->Guid, &UlGuid)) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ULCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ULCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pHeader->Guid, &W3CoreGuid)) {
|
||
|
if (pReq->ASPStartTime == 0 || pReq->ASPEndTime != 0) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pHeader->Guid, &W3FilterGuid)) {
|
||
|
if (pReq->W3FilterVisits > 0) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->W3FltrCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->W3FltrCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pHeader->Guid, &W3CgiGuid)) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->CGICPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->CGICPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pHeader->Guid, &W3IsapiGuid)) {
|
||
|
if (pReq->ASPStartTime == 0 || pReq->ASPEndTime != 0) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ISAPICPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ISAPICPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pHeader->Guid, &IisAspGuid) ||
|
||
|
IsEqualGUID(&pHeader->Guid, &IisAspNetGuid) ||
|
||
|
IsEqualGUID(&pHeader->Guid, &IisCustomIsapiGuid)) {
|
||
|
if (pReq->ASPStartTime == 0) {
|
||
|
if (pReq->ISAPIStartTime == 0) {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->W3CPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ISAPICPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ISAPICPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ThreadData[i].PrevKCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->KernelTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevKCPUTime;
|
||
|
}
|
||
|
if (pReq->ThreadData[i].PrevUCPUTime > 0) {
|
||
|
pReq->ASPCPUTime += pHeader->UserTime * CurrentSystem.TimerResolution - pReq->ThreadData[i].PrevUCPUTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pReq->ThreadData[i].PrevKCPUTime = pHeader->KernelTime * CurrentSystem.TimerResolution;
|
||
|
pReq->ThreadData[i].PrevUCPUTime = pHeader->UserTime * CurrentSystem.TimerResolution;
|
||
|
pReq->ThreadData[i].PrevReadIO = pThread->ReadIO;
|
||
|
pReq->ThreadData[i].PrevWriteIO = pThread->WriteIO;
|
||
|
|
||
|
pReq->CurrentThreadIndex = i;
|
||
|
|
||
|
}
|
||
|
#ifdef DBG
|
||
|
else { // MAX_THREADS (== 10) is reached.
|
||
|
TrctrDbgPrint(("TRACERPT Warning Req: %I64u MAX_THREADS reached.\n", pReq->RequestId));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This routine sums up CPU time and IO counts to HTTP_REQUEST_RECORD
|
||
|
// so that the request can be written to a file.
|
||
|
//
|
||
|
VOID
|
||
|
SumUpCPUTime(
|
||
|
PHTTP_REQUEST_RECORD pReq
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
if (NULL == pReq) {
|
||
|
return;
|
||
|
}
|
||
|
pReq->KCPUTime = 0;
|
||
|
pReq->UCPUTime = 0;
|
||
|
pReq->ReadIO = 0;
|
||
|
pReq->WriteIO = 0;
|
||
|
for (i = 0; i < pReq->NumberOfThreads; i++) {
|
||
|
pReq->KCPUTime += pReq->ThreadData[i].KCPUTime;
|
||
|
pReq->UCPUTime += pReq->ThreadData[i].UCPUTime;
|
||
|
pReq->ReadIO += pReq->ThreadData[i].ReadIO;
|
||
|
pReq->WriteIO += pReq->ThreadData[i].WriteIO;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PHTTP_REQUEST_RECORD
|
||
|
GetBestAspRequest(
|
||
|
ULONGLONG ConnId,
|
||
|
BOOLEAN AspStart
|
||
|
)
|
||
|
{
|
||
|
PHTTP_REQUEST_RECORD pReq1, pReq2;
|
||
|
pReq1 = FindHttpReqRecordByConId(ConnId, NULL);
|
||
|
if (pReq1 == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
pReq2 = FindHttpReqRecordByConId(ConnId, pReq1);
|
||
|
if (pReq2 == NULL) {
|
||
|
return pReq1;
|
||
|
}
|
||
|
if (AspStart) {
|
||
|
if (pReq1->ASPStartTime == 0 && pReq2->ASPStartTime == 0) {
|
||
|
return ((pReq1->ISAPIStartTime < pReq1->ISAPIStartTime) ?
|
||
|
pReq1 : pReq2);
|
||
|
}
|
||
|
else if (pReq1->ASPStartTime != 0 && pReq2->ASPStartTime == 0) {
|
||
|
return pReq2;
|
||
|
}
|
||
|
else if (pReq1->ASPStartTime == 0 && pReq2->ASPStartTime != 0) {
|
||
|
return pReq1;
|
||
|
}
|
||
|
else { // both ASPStartTimes are non-zero.
|
||
|
DeleteHttpReqRecord(pReq1, FALSE);
|
||
|
DeleteHttpReqRecord(pReq2, FALSE);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq1->ASPEndTime == 0 && pReq2->ASPEndTime == 0) {
|
||
|
if (pReq1->ASPStartTime == 0 && pReq2->ASPStartTime != 0) {
|
||
|
return pReq2;
|
||
|
}
|
||
|
else if (pReq1->ASPStartTime != 0 && pReq2->ASPStartTime == 0) {
|
||
|
return pReq1;
|
||
|
}
|
||
|
else if (pReq1->ASPStartTime != 0 && pReq2->ASPStartTime != 0) {
|
||
|
return ((pReq1->ASPStartTime < pReq1->ASPStartTime) ?
|
||
|
pReq1 : pReq2);
|
||
|
}
|
||
|
else { // both ASPStartTimes are zero.
|
||
|
DeleteHttpReqRecord(pReq1, FALSE);
|
||
|
DeleteHttpReqRecord(pReq2, FALSE);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
else if (pReq1->ASPEndTime != 0 && pReq2->ASPEndTime == 0) {
|
||
|
return pReq2;
|
||
|
}
|
||
|
else if (pReq1->ASPEndTime == 0 && pReq2->ASPEndTime != 0) {
|
||
|
return pReq1;
|
||
|
}
|
||
|
else { // both ASPEndTimes are non-zero.
|
||
|
DeleteHttpReqRecord(pReq1, FALSE);
|
||
|
DeleteHttpReqRecord(pReq2, FALSE);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
IISEventCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_RECORD pThread;
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
PMOF_INFO pMofInfo;
|
||
|
ULONGLONG RequestId = 0;
|
||
|
ULONG IpAddr = 0;
|
||
|
PHTTP_REQUEST_RECORD pReq = NULL;
|
||
|
|
||
|
if (pEvent == NULL)
|
||
|
return;
|
||
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
||
|
|
||
|
pMofInfo = GetMofInfoHead( &pEvent->Header.Guid );
|
||
|
if (pMofInfo == NULL){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (CurrentSystem.IISStartTime == 0) {
|
||
|
CurrentSystem.IISStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
CurrentSystem.IISEndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
|
||
|
pThread = FindGlobalThreadById(pHeader->ThreadId, pEvent);
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &IisAspGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisAspNetGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisCustomIsapiGuid)) {
|
||
|
ULONG ConId32 = 0;
|
||
|
ULONGLONG ConId64 = 0;
|
||
|
BOOLEAN AspStart;
|
||
|
if (PointerSize == 32) {
|
||
|
GetMofData(pEvent, L"ConnID", &ConId32, 4);
|
||
|
ConId64 = (ULONGLONG)ConId32;
|
||
|
}
|
||
|
else {
|
||
|
GetMofData(pEvent, L"ConnID", &ConId64, 8);
|
||
|
}
|
||
|
AspStart = (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISASP_START);
|
||
|
pReq = GetBestAspRequest(ConId64, AspStart);
|
||
|
if (pReq != NULL) {
|
||
|
RequestId = pReq->RequestId;
|
||
|
if (pThread != NULL) {
|
||
|
if (RequestId != pThread->IisReqId) {
|
||
|
PHTTP_REQUEST_RECORD pThreadReq = FindHttpReqRecord(pThread->IisReqId);
|
||
|
UpdateThreadIisData(pThreadReq, pHeader, pThread);
|
||
|
}
|
||
|
pThread->IisReqId = RequestId;
|
||
|
}
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &IisAspNetGuid)) {
|
||
|
pReq->IsapiExt = ISAPI_EXTENTION_ASP_NET;
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &IisCustomIsapiGuid)) {
|
||
|
pReq->IsapiExt = ISAPI_EXTENTION_CUSTOM;
|
||
|
}
|
||
|
else {
|
||
|
pReq->IsapiExt = ISAPI_EXTENTION_ASP;
|
||
|
}
|
||
|
}
|
||
|
else { // ASP event with no previous RequestId. Exit.
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else { // non-ASP events
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &IisStrmFilterGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisSslHandShakeGuid)) {
|
||
|
// These events don't have request ID. We'll just use the request that this thread is working on.
|
||
|
if (pThread != NULL) {
|
||
|
RequestId = pThread->IisReqId;
|
||
|
}
|
||
|
}
|
||
|
else if (!IsEqualGUID(&pEvent->Header.Guid, &ThreadGuid)) {
|
||
|
if ((IsEqualGUID(&pEvent->Header.Guid, &UlGuid)) &&
|
||
|
((pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_START) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_PARSE) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_DELIVER) ||
|
||
|
(pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_CACHEDEND))) {
|
||
|
RequestId = 0;
|
||
|
GetMofData(pEvent, L"RequestObj", &RequestId, (PointerSize / 8));
|
||
|
}
|
||
|
else {
|
||
|
GetMofData(pEvent, L"RequestId", &RequestId, sizeof(ULONGLONG));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RequestId == 0) {
|
||
|
if (pThread == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
RequestId = pThread->IisReqId; // if Current Request Id is 0, use the cached one.
|
||
|
}
|
||
|
else {
|
||
|
if (pThread != NULL) {
|
||
|
if (RequestId != pThread->IisReqId) {
|
||
|
pReq = FindHttpReqRecord(pThread->IisReqId);
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
}
|
||
|
pThread->IisReqId = RequestId;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RequestId == 0) return; // To filter all the termination without any useful IIS activity.
|
||
|
|
||
|
pReq = FindHttpReqRecord(RequestId);
|
||
|
// If there no active request, look for it in the (almost finished) pending list.
|
||
|
|
||
|
if (pReq == NULL) {
|
||
|
pReq = FindPendingHttpReqRecord(RequestId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &UlGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_START) {
|
||
|
// struct needed for IPV6 address format.
|
||
|
struct {
|
||
|
USHORT TdiAddrType;
|
||
|
union
|
||
|
{
|
||
|
TDI_ADDRESS_IP RemoteAddrIn;
|
||
|
TDI_ADDRESS_IP6 RemoteAddrIn6;
|
||
|
};
|
||
|
} TdiAddress;
|
||
|
|
||
|
if (pReq != NULL) {
|
||
|
// A request id is being reused before it was deleted from the last
|
||
|
// use. We must have missed a delete event, so just through the old
|
||
|
// request away.
|
||
|
EnterTracelibCritSection();
|
||
|
RemoveEntryList( &pReq->Entry );
|
||
|
LeaveTracelibCritSection();
|
||
|
DeleteHttpReqRecord(pReq, FALSE);
|
||
|
IISRequestsDiscarded++;
|
||
|
}
|
||
|
RtlZeroMemory(&TdiAddress, sizeof(TdiAddress));
|
||
|
GetMofData(pEvent, L"AddressType", &TdiAddress, sizeof(TdiAddress));
|
||
|
pReq = AddHttpReqRecord(RequestId,
|
||
|
TdiAddress.TdiAddrType,
|
||
|
TdiAddress.RemoteAddrIn.in_addr,
|
||
|
TdiAddress.RemoteAddrIn6.sin6_addr);
|
||
|
if (pReq != NULL) {
|
||
|
pReq->ULStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
// if a Start event is lost for this job, this could happen.
|
||
|
// We will not bother with transactions with missing
|
||
|
// Start or Parse.
|
||
|
if (pReq == NULL) {
|
||
|
IISEventsDiscarded++;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &UlGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_PARSE) {
|
||
|
ULONG URLSize = 0;
|
||
|
PWCHAR URLStrTemp;
|
||
|
PCHAR URLStr;
|
||
|
|
||
|
pReq->ULParseTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
if (pReq->URL != NULL) {
|
||
|
free (pReq->URL);
|
||
|
}
|
||
|
// Get URL
|
||
|
URLStrTemp = (PWCHAR)malloc(MAXSTR * sizeof(WCHAR));
|
||
|
if (URLStrTemp != NULL) {
|
||
|
RtlZeroMemory(URLStrTemp, MAXSTR * sizeof(WCHAR));
|
||
|
URLSize = GetMofData(pEvent, L"Url", URLStrTemp, MAXSTR * sizeof(WCHAR));
|
||
|
if (URLSize > (MAXSTR * sizeof(WCHAR))) {
|
||
|
free(URLStrTemp);
|
||
|
// We need to allocate one more char so that GetMofDat() can put an ending NULL in it.
|
||
|
URLStrTemp = (PWCHAR)malloc(URLSize + sizeof(WCHAR));
|
||
|
if (URLStrTemp != NULL) {
|
||
|
RtlZeroMemory(URLStrTemp, URLSize + sizeof(WCHAR));
|
||
|
GetMofData(pEvent, L"Url", URLStrTemp, URLSize);
|
||
|
}
|
||
|
else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
return;
|
||
|
}
|
||
|
// Save memory by just mallocing only the amount of space we need.
|
||
|
URLSize = wcslen(URLStrTemp);
|
||
|
if (URLSize > 0) {
|
||
|
URLStr = (PCHAR)malloc((URLSize + 1));
|
||
|
if (URLStr != NULL) {
|
||
|
WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
URLStrTemp,
|
||
|
URLSize,
|
||
|
URLStr,
|
||
|
(URLSize + 1),
|
||
|
NULL,
|
||
|
NULL);
|
||
|
URLStr[URLSize] = '\0';
|
||
|
}
|
||
|
pReq->URL = URLStr;
|
||
|
}
|
||
|
free(URLStrTemp);
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_DELIVER) {
|
||
|
ULONG SiteId;
|
||
|
ULONGLONG NewRequestId = 0;
|
||
|
PHTTP_REQUEST_RECORD pPendingReq;
|
||
|
|
||
|
// If the request is delivered to the user mode, no need to track it
|
||
|
// on the thread.
|
||
|
if (pThread != NULL) {
|
||
|
pThread->IisReqId = 0;
|
||
|
}
|
||
|
// Update RequestId with the real one.
|
||
|
GetMofData(pEvent, L"RequestId", &NewRequestId, sizeof(ULONGLONG));
|
||
|
|
||
|
// There may be another (almost finished) request using the same RequestId.
|
||
|
// Put that request to the pending request list.
|
||
|
pPendingReq = FindHttpReqRecord(NewRequestId);
|
||
|
if (pPendingReq != NULL) {
|
||
|
EnterTracelibCritSection();
|
||
|
RemoveEntryList( &pPendingReq->Entry );
|
||
|
InsertHeadList( &CurrentSystem.PendingHttpReqListHead, &pPendingReq->Entry );
|
||
|
LeaveTracelibCritSection();
|
||
|
}
|
||
|
pReq->RequestId = NewRequestId;
|
||
|
|
||
|
pReq->ULDeliverTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
GetMofData(pEvent, L"SiteId", &SiteId, sizeof(ULONG));
|
||
|
pReq->SiteId = SiteId;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_RECVRESP ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_RECVBODY ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_FASTRESP) {
|
||
|
|
||
|
pReq->ULReceiveTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
pReq->ULReceiveType = pEvent->Header.Class.Type;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_CACHEDEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_CACHEANDSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_FASTSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_ZEROSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_SENDERROR ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_END) {
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_CACHEDEND) {
|
||
|
GetMofData(pEvent, L"BytesSent", &(pReq->BytesSent), sizeof(ULONG));
|
||
|
GetMofData(pEvent, L"SiteId", &(pReq->SiteId), sizeof(ULONG));
|
||
|
pReq->HttpStatus = 200;
|
||
|
}
|
||
|
else {
|
||
|
// This is UL End events for non-cached URL requests.
|
||
|
// If W3StartTime or ULReceiveTime is missing, look for a pending
|
||
|
// request with the same RequestId.
|
||
|
if (pReq->W3StartTime == 0 || pReq->ULReceiveTime == 0) {
|
||
|
PHTTP_REQUEST_RECORD pPendingReq = FindPendingHttpReqRecord(RequestId);
|
||
|
if (pPendingReq != NULL) {
|
||
|
pReq = pPendingReq;
|
||
|
}
|
||
|
}
|
||
|
GetMofData(pEvent, L"HttpStatus", &(pReq->HttpStatus), sizeof(USHORT));
|
||
|
}
|
||
|
pReq->ULEndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
pReq->ULEndType = pEvent->Header.Class.Type;
|
||
|
pReq->ULResponseTime = (pReq->ULEndTime - pReq->ULStartTime); // in msec
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_UL_CACHEDEND) {
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
else if (pReq->ASPStartTime == 0) {
|
||
|
if (pReq->W3EndTime != 0) { // Wait till W3 ends to get BytesSent
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->W3EndTime != 0 && pReq->ASPEndTime != 0) { // Wait till W3 ends to get BytesSent
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &W3CoreGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_START) {
|
||
|
pReq->W3StartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_FILEREQ ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_CGIREQ ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_ISAPIREQ ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_OOPREQ) {
|
||
|
pReq->W3ProcessType = pEvent->Header.Class.Type;
|
||
|
pReq->FileReqTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_SENDBODY ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_SENDRESP ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_SENDENTITY ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_SENDFILTER ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_ERRSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_ERRSENDENT ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_ERRSENDCTX ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_ERRVECSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_VECTORSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CORE_END) {
|
||
|
// This is W3 End events for non-cached URL requests.
|
||
|
// If W3StartTime or ULReceiveTime is missing, look for a pending
|
||
|
// request with the same RequestId.
|
||
|
if (pReq->W3StartTime == 0 || pReq->ULReceiveTime == 0) {
|
||
|
PHTTP_REQUEST_RECORD pPendingReq = FindPendingHttpReqRecord(RequestId);
|
||
|
if (pPendingReq != NULL) {
|
||
|
pReq = pPendingReq;
|
||
|
}
|
||
|
}
|
||
|
GetMofData(pEvent, L"BytesSent", &(pReq->BytesSent), sizeof(ULONG));
|
||
|
pReq->W3EndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
pReq->W3EndType = pEvent->Header.Class.Type;
|
||
|
if (pReq->ASPStartTime != 0) {
|
||
|
if (pReq->ULEndTime != 0 && pReq->ASPEndTime != 0) {
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (pReq->ULEndTime != 0) {
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &W3FilterGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3FILTER_START) {
|
||
|
if (pReq->W3FilterStartTime == 0) {
|
||
|
pReq->W3FilterStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
pReq->W3FilterVisits++;
|
||
|
}
|
||
|
else {
|
||
|
pReq->W3FilterStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3FILTER_END) {
|
||
|
if (pReq->W3FilterStartTime != 0) {
|
||
|
pReq->W3FilterResponseTime += pEvent->Header.TimeStamp.QuadPart - pReq->W3FilterStartTime;
|
||
|
pReq->W3FilterStartTime = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &W3CgiGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CGI_START) {
|
||
|
pReq->W3ProcessType = EVENT_TRACE_TYPE_W3CORE_CGIREQ;
|
||
|
pReq->CGIStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3CGI_END) {
|
||
|
pReq->CGIEndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &W3IsapiGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_START) {
|
||
|
ULONG ConId32 = 0;
|
||
|
ULONGLONG ConId64 = 0;
|
||
|
pReq->W3ProcessType = EVENT_TRACE_TYPE_W3CORE_ISAPIREQ;
|
||
|
if (PointerSize == 32) {
|
||
|
GetMofData(pEvent, L"connID", &ConId32, 4);
|
||
|
ConId64 = (ULONGLONG)ConId32;
|
||
|
}
|
||
|
else {
|
||
|
GetMofData(pEvent, L"connID", &ConId64, 8);
|
||
|
}
|
||
|
pReq->ConId = ConId64;
|
||
|
pReq->ISAPIStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_SENDHDR ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_SENDHDREX ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_VECTORSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_ERRORSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_SSFSEND ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_SSDERROR ||
|
||
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_W3ISAPI_END) {
|
||
|
pReq->ISAPIEndType = pEvent->Header.Class.Type;
|
||
|
pReq->ISAPIEndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &IisStrmFilterGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISSTRMFILTER_START) {
|
||
|
if (pReq->StrmFltrResponseTime == 0) {
|
||
|
pReq->StrmFltrResponseTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISSTRMFILTER_END) {
|
||
|
if (pReq->StrmFltrResponseTime != 0 && (ULONGLONG)(pEvent->Header.TimeStamp.QuadPart) > pReq->StrmFltrResponseTime) {
|
||
|
pReq->StrmFltrResponseTime = pEvent->Header.TimeStamp.QuadPart - pReq->StrmFltrResponseTime;
|
||
|
}
|
||
|
else {
|
||
|
pReq->StrmFltrResponseTime = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &IisSslHandShakeGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISSSLHANDLESHAKE_START) {
|
||
|
if (pReq->SSLResponseTime == 0) {
|
||
|
pReq->SSLResponseTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISSSLHANDLESHAKE_END) {
|
||
|
if (pReq->SSLResponseTime != 0 && (ULONGLONG)(pEvent->Header.TimeStamp.QuadPart) > pReq->SSLResponseTime) {
|
||
|
pReq->SSLResponseTime = pEvent->Header.TimeStamp.QuadPart - pReq->SSLResponseTime;
|
||
|
}
|
||
|
else {
|
||
|
pReq->SSLResponseTime = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &IisAspGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisAspNetGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisCustomIsapiGuid)) {
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISASP_START) {
|
||
|
pReq->ASPStartTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_IISASP_END) {
|
||
|
pReq->ASPEndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
if (pReq->ULEndTime != 0 && pReq->W3EndTime != 0) {
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
SumUpCPUTime(pReq);
|
||
|
DeleteHttpReqRecord(pReq, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Finally, charge CPU time on on-going requests.
|
||
|
UpdateThreadIisData(pReq, pHeader, pThread);
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
GeneralEventCallback(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_RECORD pThread = NULL;
|
||
|
|
||
|
if ((pEvent == NULL) || (TraceContext == NULL)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CurrentSystem.LastEventTime = (ULONGLONG) pEvent->Header.TimeStamp.QuadPart;
|
||
|
|
||
|
if (XPorHigher) {
|
||
|
// If the ThreadId is -1 or the FieldTypeFlags in the event
|
||
|
// shows there is no CPU Time, ignore the event. This can happen
|
||
|
// when PERFINFO headers are found in kernel data.
|
||
|
//
|
||
|
// However, we exclude FileIo events from this because we need
|
||
|
// those events. Later on, we may exclude network events as well.
|
||
|
if (!IsEqualGUID(&pEvent->Header.Guid, &FileIoGuid)) {
|
||
|
|
||
|
if ( (pEvent->Header.ThreadId == -1) ||
|
||
|
(pEvent->Header.FieldTypeFlags & EVENT_TRACE_USE_NOCPUTIME) ) {
|
||
|
if (TraceContext->Flags & (TRACE_DUMP|TRACE_SUMMARY)) {
|
||
|
DumpEvent(pEvent);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &EventTraceGuid))
|
||
|
{
|
||
|
LogHeaderCallback(pEvent);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Notes: This code is here to fix up the Event Record for the
|
||
|
// Idle Threads. Since Idle threads are not guaranteed to have
|
||
|
// Cid initialized, we could end up with bogus thread Ids.
|
||
|
//
|
||
|
// Assumption: In DC_START records, the first process record must
|
||
|
// be the idle process followed by idle threads.
|
||
|
//
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_START) {
|
||
|
if (bCaptureBogusThreads) {
|
||
|
//
|
||
|
// Here we will convert the next N threads into idle threads
|
||
|
// N = Number of Processors.
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &ThreadGuid)) {
|
||
|
if (pEvent->Header.ThreadId != 0) {
|
||
|
PULONG Ptr;
|
||
|
BogusThreads[BogusCount++] = pEvent->Header.ThreadId;
|
||
|
pEvent->Header.ThreadId = 0;
|
||
|
//
|
||
|
// Assumption: The first two ULONGs are the
|
||
|
// ThreadId and ProcessId in this record. If that changes
|
||
|
// this will corrupt memory!
|
||
|
//
|
||
|
Ptr = (PULONG)pEvent->MofData;
|
||
|
*Ptr = 0;
|
||
|
Ptr++;
|
||
|
*Ptr = 0;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Once all the idle threads are seen, no need to capture anymore
|
||
|
//
|
||
|
if (IdleThreadCount++ == NumProc) bCaptureBogusThreads = FALSE;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// This is the TimeConsuming Part. We need to do this only if
|
||
|
// we found bogus threads earlier.
|
||
|
//
|
||
|
if (BogusCount > 0) {
|
||
|
ULONG i;
|
||
|
for (i=0; i < BogusCount; i++) {
|
||
|
if (pEvent->Header.ThreadId == BogusThreads[i]) {
|
||
|
pEvent->Header.ThreadId = 0;
|
||
|
|
||
|
//
|
||
|
// If DC_END records also fix up the Mof for Thread End
|
||
|
//
|
||
|
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_END) {
|
||
|
PULONG Ptr;
|
||
|
|
||
|
Ptr = (PULONG)pEvent->MofData;
|
||
|
*Ptr = 0;
|
||
|
Ptr++;
|
||
|
*Ptr = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CurrentSystem.fNoEndTime
|
||
|
&& CurrentSystem.EndTime < (ULONGLONG) pEvent->Header.TimeStamp.QuadPart)
|
||
|
{
|
||
|
CurrentSystem.EndTime = pEvent->Header.TimeStamp.QuadPart;
|
||
|
if (fDSOnly && CurrentSystem.EndTime > DSEndTime) {
|
||
|
CurrentSystem.EndTime = DSEndTime;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// After the above code we should not see any threadId's over 64K
|
||
|
//
|
||
|
/*
|
||
|
#if DBG
|
||
|
if (pEvent->Header.ThreadId > 65536)
|
||
|
DbgPrint("%d: Bad ThreadId %x Found\n", EventCount+1,
|
||
|
pEvent->Header.ThreadId);
|
||
|
#endif
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Dump the event in csv file, if required.
|
||
|
//
|
||
|
if (TraceContext->Flags & (TRACE_DUMP|TRACE_SUMMARY)) {
|
||
|
DumpEvent(pEvent);
|
||
|
}
|
||
|
else {
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PMOF_VERSION pMofVersion = NULL;
|
||
|
pMofInfo = GetMofInfoHead( &pEvent->Header.Guid );
|
||
|
if (pMofInfo == NULL){
|
||
|
return;
|
||
|
}
|
||
|
pMofInfo->EventCount++;
|
||
|
|
||
|
pMofVersion = GetMofVersion(pMofInfo,
|
||
|
pEvent->Header.Class.Type,
|
||
|
pEvent->Header.Class.Version,
|
||
|
pEvent->Header.Class.Level
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if ( (TraceContext->Flags & TRACE_REDUCE) == 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// TODO: This may prevent DiskIO write events and TCP receive events to
|
||
|
// get ignored
|
||
|
//
|
||
|
|
||
|
|
||
|
if (pEvent->Header.ThreadId == 0) {
|
||
|
if ( (pEvent->Header.Class.Type != EVENT_TRACE_TYPE_START)
|
||
|
&& (pEvent->Header.Class.Type != EVENT_TRACE_TYPE_DC_START)
|
||
|
&& (pEvent->Header.Class.Type != EVENT_TRACE_TYPE_END)
|
||
|
&& (pEvent->Header.Class.Type != EVENT_TRACE_TYPE_DC_END)
|
||
|
)
|
||
|
{
|
||
|
EventCount++;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!IsEqualGUID(&pEvent->Header.Guid, &FileIoGuid) &&
|
||
|
!IsEqualGUID(&pEvent->Header.Guid, &TcpIpGuid) &&
|
||
|
!IsEqualGUID(&pEvent->Header.Guid, &UdpIpGuid)) {
|
||
|
// FileIo events and network events have Perf Header with ThreadId == -1
|
||
|
// No need to add this bogus thread
|
||
|
pThread = FindGlobalThreadById(pEvent->Header.ThreadId, pEvent);
|
||
|
}
|
||
|
|
||
|
EventCount ++;
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &ProcessGuid))
|
||
|
{
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
ProcessCallback(pEvent);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &ThreadGuid))
|
||
|
{
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_START)
|
||
|
{
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
ThreadCallback(pEvent);
|
||
|
}
|
||
|
else if (pEvent->Header.ThreadId != 0)
|
||
|
{
|
||
|
if (!IsEqualGUID(&pEvent->Header.Guid, &FileIoGuid) &&
|
||
|
!IsEqualGUID(&pEvent->Header.Guid, &TcpIpGuid) &&
|
||
|
!IsEqualGUID(&pEvent->Header.Guid, &UdpIpGuid)) {
|
||
|
AdjustThreadTime(pEvent, pThread);
|
||
|
}
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &DiskIoGuid))
|
||
|
{
|
||
|
DiskIoCallback(pEvent, pThread);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &FileIoGuid))
|
||
|
{
|
||
|
// No need to do callbacks on file rundown events.
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_FILEIO_NAME) {
|
||
|
HotFileCallback(pEvent);
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &ImageLoadGuid))
|
||
|
{
|
||
|
ModuleLoadCallback(pEvent);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &TcpIpGuid))
|
||
|
{
|
||
|
TcpIpCallback(pEvent, pThread);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &UdpIpGuid))
|
||
|
{
|
||
|
TcpIpCallback(pEvent, pThread);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &PageFaultGuid))
|
||
|
{
|
||
|
PageFaultCallback(pEvent, pThread);
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &EventTraceConfigGuid)) {
|
||
|
//
|
||
|
// We only need Logical Disk events for now.
|
||
|
//
|
||
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_CONFIG_LOGICALDISK) {
|
||
|
LogDriveCallback(pEvent);
|
||
|
}
|
||
|
else if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_CONFIG_CPU) {
|
||
|
CpuCallback(pEvent);
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(&pEvent->Header.Guid, &UlGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &W3CoreGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &W3FilterGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &W3CgiGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &W3IsapiGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisStrmFilterGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisSslHandShakeGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisAspGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisAspNetGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &IisCustomIsapiGuid)) {
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &UlGuid)) {
|
||
|
bIISEvents = TRUE;
|
||
|
}
|
||
|
if (bIISEvents) {
|
||
|
IISEventCallback(pEvent);
|
||
|
}
|
||
|
//
|
||
|
// Cannot use EventCallBack() to compute the response time becase
|
||
|
// one transaction goes through different Start/Stop through different
|
||
|
// events.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// This is a hack specific to Print Servers.
|
||
|
// Need to come up with a general solution. MKR.
|
||
|
//
|
||
|
|
||
|
if (IsEqualGUID(&pEvent->Header.Guid, &PrintJobGuid) ||
|
||
|
IsEqualGUID(&pEvent->Header.Guid, &RenderedJobGuid)) {
|
||
|
PrintJobCallback(pEvent);
|
||
|
}
|
||
|
|
||
|
EventCallback(pEvent, pThread);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG ahextoi( WCHAR *s)
|
||
|
{
|
||
|
int len;
|
||
|
ULONG num, base, hex;
|
||
|
|
||
|
len = lstrlenW(s);
|
||
|
hex = 0; base = 1; num = 0;
|
||
|
while (--len >= 0) {
|
||
|
if ( (s[len] == 'x' || s[len] == 'X') &&
|
||
|
(s[len-1] == '0') )
|
||
|
break;
|
||
|
if (s[len] >= '0' && s[len] <= '9')
|
||
|
num = s[len] - '0';
|
||
|
else if (s[len] >= 'a' && s[len] <= 'f')
|
||
|
num = (s[len] - 'a') + 10;
|
||
|
else if (s[len] >= 'A' && s[len] <= 'F')
|
||
|
num = (s[len] - 'A') + 10;
|
||
|
else
|
||
|
continue;
|
||
|
|
||
|
hex += num * base;
|
||
|
base = base * 16;
|
||
|
}
|
||
|
return hex;
|
||
|
}
|
||
|
|
||
|
ULONG StringToNumber( LPWSTR sz )
|
||
|
{
|
||
|
if( NULL == sz ){
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if( wcsstr( sz, L"x" ) || wcsstr( sz, L"X" ) ){
|
||
|
return ahextoi( sz );
|
||
|
}else{
|
||
|
return _wtol( sz );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AnsiToUnicode(PCHAR str, PWCHAR wstr)
|
||
|
{
|
||
|
int len, i;
|
||
|
PUCHAR AnsiChar;
|
||
|
|
||
|
if (str == NULL || wstr == NULL)
|
||
|
return;
|
||
|
|
||
|
len = strlen(str);
|
||
|
for (i=0; i<len; i++)
|
||
|
{
|
||
|
AnsiChar = (PUCHAR) &str[i];
|
||
|
wstr[i] = (WCHAR) RtlAnsiCharToUnicodeChar(&AnsiChar);
|
||
|
}
|
||
|
wstr[len] = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
PrintMapValue( PVALUEMAP pValueMap, DWORD dwValue )
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Function assumes TraceContext->hDumpFile
|
||
|
// is open and valid
|
||
|
//
|
||
|
|
||
|
BOOL bFirst = TRUE;
|
||
|
BOOL bDone = FALSE;
|
||
|
|
||
|
LONG HUGEP *pValueMapData;
|
||
|
BSTR HUGEP *pValuesData;
|
||
|
|
||
|
LONG uMapBound, lMapBound;
|
||
|
LONG uValuesBound, lValuesBound;
|
||
|
|
||
|
if( NULL != pValueMap->saValueMap ){
|
||
|
SafeArrayGetUBound( pValueMap->saValueMap, 1, &uMapBound );
|
||
|
SafeArrayGetLBound( pValueMap->saValueMap, 1, &lMapBound );
|
||
|
SafeArrayAccessData( pValueMap->saValueMap, (void HUGEP **)&pValueMapData );
|
||
|
}
|
||
|
|
||
|
if( NULL != pValueMap->saValues ){
|
||
|
SafeArrayGetUBound( pValueMap->saValues, 1, &uValuesBound );
|
||
|
SafeArrayGetLBound( pValueMap->saValues, 1, &lValuesBound );
|
||
|
SafeArrayAccessData( pValueMap->saValues, (void HUGEP **)&pValuesData );
|
||
|
}
|
||
|
|
||
|
if( NULL != pValueMap->saValues && NULL != pValueMap->saValueMap ){
|
||
|
for ( LONG i=lMapBound; i<=uMapBound && !bDone; i++) {
|
||
|
|
||
|
switch( pValueMap->dwValueType ){
|
||
|
case VALUETYPE_INDEX:
|
||
|
if( dwValue == pValueMapData[i] ){
|
||
|
fwprintf( TraceContext->hDumpFile, L"\"%ws\", ", pValuesData[i] );
|
||
|
bDone = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case VALUETYPE_FLAG:
|
||
|
if( (dwValue & pValueMapData[i]) == pValueMapData[i] ){
|
||
|
if( bFirst ){
|
||
|
fwprintf( TraceContext->hDumpFile, L"\"%ws", pValuesData[i] );
|
||
|
bFirst = FALSE;
|
||
|
}else{
|
||
|
fwprintf( TraceContext->hDumpFile, L"|%ws", pValuesData[i] );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}else if( NULL != pValueMap->saValues ){
|
||
|
if( (LONG)dwValue >= lValuesBound && (LONG)dwValue <= uValuesBound ){
|
||
|
fwprintf( TraceContext->hDumpFile, L"\"%ws\", ", pValuesData[dwValue] );
|
||
|
bDone = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if( !bFirst && !bDone ){
|
||
|
|
||
|
//
|
||
|
// Flags were found; need to end the quotes
|
||
|
//
|
||
|
|
||
|
fwprintf( TraceContext->hDumpFile, L"\", " );
|
||
|
}
|
||
|
|
||
|
if( bFirst && !bDone ){
|
||
|
|
||
|
//
|
||
|
// No values mapped; just print the DWORD
|
||
|
//
|
||
|
|
||
|
fwprintf( TraceContext->hDumpFile, L"%d, ", dwValue );
|
||
|
}
|
||
|
|
||
|
if( NULL != pValueMap->saValueMap ){
|
||
|
SafeArrayUnaccessData( pValueMap->saValueMap );
|
||
|
}
|
||
|
if( NULL != pValueMap->saValues ){
|
||
|
SafeArrayUnaccessData( pValueMap->saValues );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define PRINTVALUE( s, v ) \
|
||
|
if( NULL == pItem->pValueMap ){ \
|
||
|
fwprintf(DumpFile, s, v); \
|
||
|
}else{ \
|
||
|
PrintMapValue( pItem->pValueMap, (DWORD)v ); \
|
||
|
}
|
||
|
|
||
|
void
|
||
|
WINAPI
|
||
|
DumpEvent(
|
||
|
PEVENT_TRACE pEvent
|
||
|
)
|
||
|
{
|
||
|
PEVENT_TRACE_HEADER pHeader;
|
||
|
ULONG i;
|
||
|
PITEM_DESC pItem;
|
||
|
PCHAR str;
|
||
|
PWCHAR wstr;
|
||
|
PCHAR ptr;
|
||
|
ULONG ulongword;
|
||
|
LONG longword;
|
||
|
USHORT ushortword;
|
||
|
SHORT shortword;
|
||
|
PMOF_INFO pMofInfo;
|
||
|
PMOF_VERSION pMofVersion;
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
char iChar;
|
||
|
WCHAR iwChar;
|
||
|
ULONG MofDataUsed;
|
||
|
FILE* DumpFile = NULL;
|
||
|
|
||
|
TotalEventCount++;
|
||
|
|
||
|
if (pEvent == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pHeader = (PEVENT_TRACE_HEADER) &pEvent->Header;
|
||
|
|
||
|
if (MofData == NULL) {
|
||
|
MofLength = pEvent->MofLength + sizeof(UNICODE_NULL);
|
||
|
MofData = (LPSTR)malloc(MofLength);
|
||
|
}
|
||
|
else if ((pEvent->MofLength + sizeof(UNICODE_NULL)) > MofLength) {
|
||
|
free(MofData);
|
||
|
MofLength = pEvent->MofLength + sizeof(UNICODE_NULL);
|
||
|
MofData = (LPSTR)malloc(MofLength);
|
||
|
}
|
||
|
|
||
|
if (MofData == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if ((pEvent->MofData == NULL) && (0 != pEvent->MofLength)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pEvent->MofData != NULL) {
|
||
|
RtlCopyMemory(MofData, pEvent->MofData, pEvent->MofLength);
|
||
|
}
|
||
|
|
||
|
MofData[pEvent->MofLength] = 0;
|
||
|
MofData[pEvent->MofLength+1] = 0;
|
||
|
ptr = MofData;
|
||
|
MofDataUsed = 0;
|
||
|
|
||
|
pMofInfo = GetMofInfoHead( &pEvent->Header.Guid );
|
||
|
|
||
|
if (pMofInfo == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
pMofInfo->EventCount++;
|
||
|
|
||
|
pMofVersion = GetMofVersion(pMofInfo,
|
||
|
pEvent->Header.Class.Type,
|
||
|
pEvent->Header.Class.Version,
|
||
|
pEvent->Header.Class.Level
|
||
|
);
|
||
|
|
||
|
if( NULL == pMofVersion ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pMofVersion->EventCountByType++;
|
||
|
|
||
|
if( !(TraceContext->Flags & TRACE_DUMP) ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DumpFile = TraceContext->hDumpFile;
|
||
|
str = (PCHAR)malloc(MOFSTR);
|
||
|
if (str == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
wstr = (PWCHAR)malloc(MOFWSTR * sizeof(WCHAR));
|
||
|
if (wstr == NULL) {
|
||
|
free(str);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( pMofInfo->strDescription != NULL ){
|
||
|
fwprintf( DumpFile, L"%12s, ", pMofInfo->strDescription );
|
||
|
}else{
|
||
|
fwprintf( DumpFile, L"%12s, ", CpdiGuidToString( wstr, MOFWSTR, &pMofInfo->Guid ) );
|
||
|
}
|
||
|
|
||
|
if(pMofVersion->strType != NULL && wcslen(pMofVersion->strType) ){
|
||
|
fwprintf( DumpFile, L"%10s, ", pMofVersion->strType );
|
||
|
}else{
|
||
|
fwprintf( DumpFile, L"%10d, ", pEvent->Header.Class.Type );
|
||
|
}
|
||
|
|
||
|
if( TraceContext->Flags & TRACE_EXTENDED_FMT ){
|
||
|
fwprintf( DumpFile, L"%8d,%8d,%8d, ",
|
||
|
pEvent->Header.Class.Type,
|
||
|
pEvent->Header.Class.Level,
|
||
|
pEvent->Header.Class.Version
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Thread ID
|
||
|
fwprintf( DumpFile, L"0x%08X, ", pHeader->ThreadId );
|
||
|
|
||
|
// System Time
|
||
|
fwprintf( DumpFile, L"%20I64u, ", pHeader->TimeStamp.QuadPart);
|
||
|
|
||
|
if( g_bUserMode == FALSE ){
|
||
|
// Kernel Time
|
||
|
fwprintf(DumpFile, L"%10lu, ", pHeader->KernelTime * TimerResolution);
|
||
|
|
||
|
// User Time
|
||
|
fwprintf(DumpFile, L"%10lu, ", pHeader->UserTime * TimerResolution);
|
||
|
}else{
|
||
|
// processor Time
|
||
|
fwprintf(DumpFile, L"%I64u, ", pHeader->ProcessorTime);
|
||
|
}
|
||
|
|
||
|
Head = &pMofVersion->ItemHeader;
|
||
|
Next = Head->Flink;
|
||
|
|
||
|
if ((Head == Next) && (pEvent->MofLength > 0)) {
|
||
|
fwprintf(DumpFile, L"DataSize=%d, ", pEvent->MofLength);
|
||
|
}
|
||
|
|
||
|
while (Head != Next) {
|
||
|
pItem = CONTAINING_RECORD(Next, ITEM_DESC, Entry);
|
||
|
Next = Next->Flink;
|
||
|
|
||
|
MofDataUsed = (ULONG) (ptr - MofData);
|
||
|
|
||
|
if (MofDataUsed >= pEvent->MofLength){
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (pItem->ItemType)
|
||
|
{
|
||
|
case ItemChar:
|
||
|
case ItemUChar:
|
||
|
if( NULL == pItem->pValueMap ){
|
||
|
fwprintf(DumpFile, L"\"" );
|
||
|
for (i = 0; i < pItem->ArraySize; i++){
|
||
|
iChar = *((PCHAR) ptr);
|
||
|
if (iChar != '\0') {
|
||
|
fwprintf(DumpFile, L"%c", iChar);
|
||
|
}
|
||
|
ptr += sizeof(CHAR);
|
||
|
}
|
||
|
fwprintf(DumpFile, L"\", " );
|
||
|
}else{
|
||
|
iChar = *((PCHAR) ptr);
|
||
|
PrintMapValue( pItem->pValueMap, (DWORD)iChar );
|
||
|
ptr += sizeof(CHAR);
|
||
|
}
|
||
|
break;
|
||
|
case ItemCharHidden:
|
||
|
ptr += sizeof(CHAR) * pItem->ArraySize;
|
||
|
break;
|
||
|
case ItemWChar:
|
||
|
if( NULL == pItem->pValueMap ){
|
||
|
fwprintf(DumpFile, L"\"" );
|
||
|
for(i = 0; i < pItem->ArraySize; i++){
|
||
|
iwChar = *((PWCHAR) ptr);
|
||
|
if (iwChar != '\0') {
|
||
|
fwprintf(DumpFile, L"%wc", iwChar);
|
||
|
}
|
||
|
ptr += sizeof(WCHAR);
|
||
|
}
|
||
|
fwprintf(DumpFile, L"\", ");
|
||
|
}else{
|
||
|
iwChar = *((PWCHAR) ptr);
|
||
|
PrintMapValue( pItem->pValueMap, (DWORD)iwChar );
|
||
|
ptr += sizeof(WCHAR);
|
||
|
}
|
||
|
break;
|
||
|
case ItemCharSign:
|
||
|
{
|
||
|
char sign[5];
|
||
|
RtlCopyMemory(&sign[0], ptr, sizeof(CHAR) * 2);
|
||
|
sign[2] = '\0';
|
||
|
StringCchCopyA(str, MOFSTR, sign);
|
||
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
ptr += sizeof(CHAR) * 2;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemCharShort:
|
||
|
iChar = *((PCHAR) ptr);
|
||
|
PRINTVALUE( L"%d, ", iChar );
|
||
|
ptr += sizeof(CHAR);
|
||
|
break;
|
||
|
|
||
|
case ItemShort:
|
||
|
RtlCopyMemory(&shortword, ptr, sizeof(SHORT));
|
||
|
PRINTVALUE( L"%6d, ", shortword);
|
||
|
ptr += sizeof (SHORT);
|
||
|
break;
|
||
|
|
||
|
case ItemUShort:
|
||
|
RtlCopyMemory(&ushortword, ptr, sizeof(USHORT));
|
||
|
PRINTVALUE( L"%6u, ", ushortword );
|
||
|
ptr += sizeof (USHORT);
|
||
|
break;
|
||
|
|
||
|
case ItemLong:
|
||
|
RtlCopyMemory(&longword, ptr, sizeof(LONG));
|
||
|
PRINTVALUE( L"%8d, ", longword );
|
||
|
ptr += sizeof (LONG);
|
||
|
break;
|
||
|
|
||
|
case ItemULong:
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
PRINTVALUE( L"%8lu, ", ulongword);
|
||
|
ptr += sizeof (ULONG);
|
||
|
break;
|
||
|
|
||
|
case ItemULongX:
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
PRINTVALUE( L"0x%08X, ", ulongword);
|
||
|
ptr += sizeof (ULONG);
|
||
|
break;
|
||
|
|
||
|
case ItemPtr :
|
||
|
{
|
||
|
unsigned __int64 pointer;
|
||
|
if (PointerSize == 64) {
|
||
|
RtlCopyMemory(&pointer, ptr, PointerSize / 8);
|
||
|
fwprintf(DumpFile, L"0x%08X, ", pointer);
|
||
|
ptr += PointerSize / 8;
|
||
|
}
|
||
|
else { // assumes 32 bit otherwise
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
fwprintf(DumpFile, L"0x%08X, ", ulongword);
|
||
|
ptr += sizeof(ULONG);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ItemSizeT :
|
||
|
{
|
||
|
unsigned __int64 pointer;
|
||
|
if (PointerSize == 64) {
|
||
|
RtlCopyMemory(&pointer, ptr, PointerSize / 8);
|
||
|
fwprintf(DumpFile, L"%16I64d, ", pointer);
|
||
|
ptr += PointerSize / 8;
|
||
|
}
|
||
|
else { // assumes 32 bit otherwise
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
fwprintf(DumpFile, L"%8d, ", ulongword);
|
||
|
ptr += sizeof(ULONG);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemIPAddr:
|
||
|
{
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
|
||
|
// Convert it to readable form
|
||
|
//
|
||
|
fwprintf(DumpFile, L"%03d.%03d.%03d.%03d, ",
|
||
|
(ulongword >> 0) & 0xff,
|
||
|
(ulongword >> 8) & 0xff,
|
||
|
(ulongword >> 16) & 0xff,
|
||
|
(ulongword >> 24) & 0xff);
|
||
|
ptr += sizeof (ULONG);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemTDIAddr:
|
||
|
{
|
||
|
WCHAR ipAddrBuffer[MAX_ADDRESS_LENGTH];
|
||
|
PWCHAR pszW = &ipAddrBuffer[0];
|
||
|
PTDI_ADDRESS_IP pIPv4Address;
|
||
|
PTDI_ADDRESS_IP6 pIPv6Address;
|
||
|
|
||
|
RtlCopyMemory(&ushortword, ptr, sizeof(USHORT));
|
||
|
ptr += sizeof (USHORT);
|
||
|
|
||
|
pIPv4Address = ((PTDI_ADDRESS_IP) ptr);
|
||
|
pIPv6Address = ((PTDI_ADDRESS_IP6) ptr);
|
||
|
|
||
|
// Right now, we only recognize PV4 and PV6
|
||
|
DecodeIpAddressW(
|
||
|
ushortword,
|
||
|
&pIPv4Address->in_addr,
|
||
|
&pIPv6Address->sin6_addr[0],
|
||
|
pszW
|
||
|
);
|
||
|
|
||
|
// Convert it to readable form
|
||
|
//
|
||
|
fwprintf(DumpFile, L"%ws, ", ipAddrBuffer);
|
||
|
ptr = MofData + pEvent->MofLength; // ItemTDIAddr can only be the last member
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemPort:
|
||
|
{
|
||
|
RtlCopyMemory(&ushortword, ptr, sizeof(USHORT));
|
||
|
fwprintf(DumpFile, L"%u, ", NTOHS(ushortword));
|
||
|
ptr += sizeof (USHORT);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemLongLong:
|
||
|
{
|
||
|
LONGLONG n64;
|
||
|
RtlCopyMemory(&n64, ptr, sizeof(LONGLONG));
|
||
|
ptr += sizeof(LONGLONG);
|
||
|
fwprintf(DumpFile, L"%16I64d, ", n64);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemULongLong:
|
||
|
{
|
||
|
ULONGLONG n64;
|
||
|
RtlCopyMemory(&n64, ptr, sizeof(ULONGLONG));
|
||
|
ptr += sizeof(ULONGLONG);
|
||
|
fwprintf(DumpFile, L"%16I64u, ", n64);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemString:
|
||
|
case ItemRString:
|
||
|
{
|
||
|
USHORT pLen = (USHORT)strlen((CHAR*) ptr);
|
||
|
|
||
|
if (pLen > 0)
|
||
|
{
|
||
|
StringCchCopyA(str, MOFSTR, ptr);
|
||
|
if (pItem->ItemType == ItemRString)
|
||
|
{
|
||
|
reduceA(str);
|
||
|
}
|
||
|
str[pLen] = '\0';
|
||
|
for (i= pLen - 1; i > 0; i--) {
|
||
|
if (str[i] == 0xFF)
|
||
|
{
|
||
|
str[i] = 0;
|
||
|
}
|
||
|
else break;
|
||
|
}
|
||
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += (pLen + 1);
|
||
|
break;
|
||
|
}
|
||
|
case ItemRWString:
|
||
|
case ItemWString:
|
||
|
{
|
||
|
USHORT pLen = 0;
|
||
|
|
||
|
if (*(WCHAR *) ptr)
|
||
|
{
|
||
|
if (pItem->ItemType == ItemRWString)
|
||
|
{
|
||
|
reduceW((WCHAR *) ptr);
|
||
|
}
|
||
|
pLen = ((lstrlenW((WCHAR*)ptr) + 1) * sizeof(WCHAR));
|
||
|
RtlCopyMemory(wstr, ptr, pLen);
|
||
|
wstr[(pLen / sizeof(WCHAR))] = L'\0';
|
||
|
|
||
|
for (i = (pLen/sizeof(WCHAR)) - 1; i > 0; i--)
|
||
|
{
|
||
|
if (((USHORT) wstr[i] == (USHORT) 0xFFFF))
|
||
|
{
|
||
|
wstr[i] = (USHORT) 0;
|
||
|
}
|
||
|
else break;
|
||
|
}
|
||
|
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += pLen;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemDSString: // Counted String
|
||
|
{
|
||
|
USHORT pLen = (USHORT)(256 * ((USHORT) * ptr) + ((USHORT) * (ptr + 1)));
|
||
|
ptr += sizeof(USHORT);
|
||
|
if (pLen > (pEvent->MofLength - MofDataUsed - 1)) {
|
||
|
pLen = (USHORT) (pEvent->MofLength - MofDataUsed - 1);
|
||
|
}
|
||
|
if (pLen > 0)
|
||
|
{
|
||
|
StringCchCopyA(str, MOFSTR, ptr);
|
||
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
||
|
replaceNLW(wstr);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += (pLen + 1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemPString: // Counted String
|
||
|
{
|
||
|
USHORT pLen;
|
||
|
RtlCopyMemory(&pLen, ptr, sizeof(USHORT));
|
||
|
ptr += sizeof(USHORT);
|
||
|
|
||
|
if (pLen > (pEvent->MofLength - MofDataUsed)) {
|
||
|
pLen = (USHORT) (pEvent->MofLength - MofDataUsed);
|
||
|
}
|
||
|
|
||
|
if (pLen > MOFSTR * sizeof(CHAR)) {
|
||
|
pLen = MOFSTR * sizeof(CHAR);
|
||
|
}
|
||
|
if (pLen > 0) {
|
||
|
RtlCopyMemory(str, ptr, pLen);
|
||
|
str[pLen] = '\0';
|
||
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += pLen;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemDSWString: // DS Counted Wide Strings
|
||
|
case ItemPWString: // Counted Wide Strings
|
||
|
{
|
||
|
USHORT pLen;
|
||
|
if (pItem->ItemType == ItemDSWString) {
|
||
|
pLen = (USHORT)(256 * ((USHORT) * ptr) + ((USHORT) * (ptr + 1)));
|
||
|
}
|
||
|
else {
|
||
|
RtlCopyMemory(&pLen, ptr, sizeof(USHORT));
|
||
|
}
|
||
|
ptr += sizeof(USHORT);
|
||
|
|
||
|
if (pLen > (pEvent->MofLength - MofDataUsed)) {
|
||
|
pLen = (USHORT) (pEvent->MofLength - MofDataUsed);
|
||
|
}
|
||
|
|
||
|
if (pLen > MOFWSTR * sizeof(WCHAR)) {
|
||
|
pLen = MOFWSTR * sizeof(WCHAR);
|
||
|
}
|
||
|
if (pLen > 0) {
|
||
|
RtlCopyMemory(wstr, ptr, pLen);
|
||
|
wstr[pLen / sizeof(WCHAR)] = L'\0';
|
||
|
if (pItem->ItemType == ItemDSWString) {
|
||
|
replaceNLW(wstr);
|
||
|
}
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += pLen;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemNWString: // Non Null Terminated String
|
||
|
{
|
||
|
USHORT Size;
|
||
|
|
||
|
Size = (USHORT)(pEvent->MofLength - (ULONG)(ptr - MofData));
|
||
|
if( Size > MOFSTR )
|
||
|
{
|
||
|
Size = MOFSTR;
|
||
|
}
|
||
|
if (Size > 0)
|
||
|
{
|
||
|
RtlCopyMemory(wstr, ptr, Size);
|
||
|
wstr[Size / sizeof(WCHAR)] = '\0';
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += Size;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemMLString: // Multi Line String
|
||
|
{
|
||
|
USHORT pLen;
|
||
|
char * src, * dest;
|
||
|
BOOL inQ = FALSE;
|
||
|
BOOL skip = FALSE;
|
||
|
UINT lineCount = 0;
|
||
|
|
||
|
ptr += sizeof(UCHAR) * 2;
|
||
|
pLen = (USHORT)strlen(ptr);
|
||
|
if (pLen > 0)
|
||
|
{
|
||
|
src = ptr;
|
||
|
dest = str;
|
||
|
while (* src != '\0'){
|
||
|
if (* src == '\n'){
|
||
|
if (!lineCount){
|
||
|
* dest++ = ' ';
|
||
|
}
|
||
|
lineCount++;
|
||
|
}else if (* src == '\"'){
|
||
|
if (inQ){
|
||
|
char strCount[32];
|
||
|
char * cpy;
|
||
|
|
||
|
StringCchPrintfA(strCount, 32, "{%dx}", lineCount);
|
||
|
cpy = & strCount[0];
|
||
|
while (* cpy != '\0'){
|
||
|
* dest ++ = * cpy ++;
|
||
|
}
|
||
|
}
|
||
|
inQ = !inQ;
|
||
|
}else if (!skip){
|
||
|
*dest++ = *src;
|
||
|
}
|
||
|
skip = (lineCount > 1 && inQ);
|
||
|
src++;
|
||
|
}
|
||
|
*dest = '\0';
|
||
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
}
|
||
|
ptr += (pLen);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemSid:
|
||
|
{
|
||
|
WCHAR UserName[64];
|
||
|
WCHAR Domain[64];
|
||
|
WCHAR FullName[256];
|
||
|
ULONG asize = 0;
|
||
|
ULONG bsize = 0;
|
||
|
ULONG SidMarker;
|
||
|
SID_NAME_USE Se;
|
||
|
ULONG nSidLength;
|
||
|
|
||
|
RtlCopyMemory(&SidMarker, ptr, sizeof(ULONG));
|
||
|
if (SidMarker == 0){
|
||
|
ptr += 4;
|
||
|
fwprintf(DumpFile, L"0, ");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (PointerSize == 64) {
|
||
|
ptr += 16; // skip the TOKEN_USER structure
|
||
|
}
|
||
|
else {
|
||
|
ptr += 8; // skip the TOKEN_USER structure
|
||
|
}
|
||
|
nSidLength = 8 + (4*ptr[1]);
|
||
|
|
||
|
asize = 64;
|
||
|
bsize = 64;
|
||
|
if (LookupAccountSidW(
|
||
|
NULL,
|
||
|
(PSID) ptr,
|
||
|
(LPWSTR) & UserName[0],
|
||
|
& asize,
|
||
|
(LPWSTR) & Domain[0],
|
||
|
& bsize,
|
||
|
& Se))
|
||
|
{
|
||
|
LPWSTR pFullName = &FullName[0];
|
||
|
StringCchPrintfW(pFullName, 256, L"\\\\%s\\%s", Domain, UserName);
|
||
|
asize = (ULONG) lstrlenW(pFullName);
|
||
|
if (asize > 0){
|
||
|
fwprintf(DumpFile, L"\"%s\", ", pFullName);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fwprintf(DumpFile, L"\"System\", " );
|
||
|
}
|
||
|
SetLastError( ERROR_SUCCESS );
|
||
|
ptr += nSidLength;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemChar4:
|
||
|
fwprintf(DumpFile,
|
||
|
L"%c%c%c%c, ",
|
||
|
*ptr, ptr[1], ptr[2], ptr[3]);
|
||
|
ptr += 4 * sizeof(CHAR);
|
||
|
break;
|
||
|
|
||
|
case ItemGuid:
|
||
|
{
|
||
|
WCHAR s[MAXGUIDSTR];
|
||
|
|
||
|
fwprintf(DumpFile, L"%s, ", CpdiGuidToString(&s[0], MAXGUIDSTR, (LPGUID)ptr));
|
||
|
ptr += sizeof(GUID);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemCPUTime:
|
||
|
{
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
fwprintf(DumpFile, L"%8lu, ", ulongword * TimerResolution);
|
||
|
ptr += sizeof (ULONG);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemOptArgs:
|
||
|
{
|
||
|
DWORD dwOptArgs = * ((PLONG) ptr);
|
||
|
DWORD dwMofLen = pEvent->MofLength + sizeof(UNICODE_NULL);
|
||
|
DWORD dwMofUsed = MofDataUsed + sizeof(DWORD);
|
||
|
DWORD dwType;
|
||
|
LPWSTR wszString;
|
||
|
LPSTR aszString;
|
||
|
LONG lValue32;
|
||
|
LONGLONG lValue64;
|
||
|
|
||
|
ptr += sizeof(LONG);
|
||
|
for (i = 0; i < 8; i ++) {
|
||
|
if (dwMofUsed > dwMofLen) {
|
||
|
break;
|
||
|
}
|
||
|
dwType = (dwOptArgs >> (i * 4)) & 0x0000000F;
|
||
|
switch (dwType) {
|
||
|
case 0: // LONG
|
||
|
dwMofUsed += sizeof(LONG);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
RtlCopyMemory(&lValue32, ptr, sizeof(LONG));
|
||
|
ptr += sizeof(LONG);
|
||
|
PRINTVALUE( L"%d,", lValue32);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 1: // WSTR
|
||
|
wszString = (LPWSTR) ptr;
|
||
|
dwMofUsed += sizeof(WCHAR) * (lstrlenW(wszString) + 1);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
fwprintf(DumpFile, L"\"%ws\",", wszString);
|
||
|
ptr += sizeof(WCHAR) * (lstrlenW(wszString) + 1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2: // STR
|
||
|
aszString = (LPSTR) ptr;
|
||
|
dwMofUsed += sizeof(CHAR) * (lstrlenA(aszString) + 1);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
MultiByteToWideChar(CP_ACP, 0, aszString, -1, wstr, MOFWSTR);
|
||
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
||
|
ptr += sizeof(CHAR) * (lstrlenA(aszString) + 1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3: // LONG64
|
||
|
dwMofUsed += sizeof(LONGLONG);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
RtlCopyMemory(&lValue64, ptr, sizeof(LONGLONG));
|
||
|
ptr += sizeof(LONGLONG);
|
||
|
fwprintf(DumpFile, L"%I64d,", lValue64);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 4: // LONGX
|
||
|
dwMofUsed += sizeof(LONG);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
RtlCopyMemory(&lValue32, ptr, sizeof(LONG));
|
||
|
ptr += sizeof(LONG);
|
||
|
fwprintf(DumpFile, L"0x%08X,", lValue32);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 5: // LONGLONGX
|
||
|
dwMofUsed += sizeof(LONGLONG);
|
||
|
if (dwMofUsed <= dwMofLen) {
|
||
|
RtlCopyMemory(&lValue64, ptr, sizeof(LONGLONG));
|
||
|
ptr += sizeof(LONGLONG);
|
||
|
fwprintf(DumpFile, L"0x%016I64X,", lValue64);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ItemVariant:
|
||
|
{
|
||
|
//
|
||
|
// Variable Size. First ULONG gives the sizee and the rest is blob
|
||
|
//
|
||
|
RtlCopyMemory(&ulongword, ptr, sizeof(ULONG));
|
||
|
ptr += sizeof(ULONG);
|
||
|
|
||
|
fwprintf(DumpFile, L"DataSize=%d, ", ulongword);
|
||
|
|
||
|
// No need to dump the contents of the Blob itself.
|
||
|
|
||
|
ptr += ulongword;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case ItemBool:
|
||
|
{
|
||
|
BOOL Flag;
|
||
|
RtlCopyMemory(&Flag, ptr, sizeof(BOOL));
|
||
|
fwprintf(DumpFile, L"%5s, " , (Flag) ? L"TRUE" : L"FALSE" );
|
||
|
ptr += sizeof(BOOL);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
ptr += sizeof (int);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Instance ID, Parent Instance ID
|
||
|
fwprintf(DumpFile, L"%d, %d\n", pEvent->InstanceId, pEvent->ParentInstanceId );
|
||
|
|
||
|
free(str);
|
||
|
free(wstr);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|