|
|
/*++
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
|