5755 lines
176 KiB
C++
5755 lines
176 KiB
C++
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
callbacks.c
|
|
|
|
Abstract:
|
|
|
|
Setting up and handling the callbacks for the events from the
|
|
trace file.
|
|
|
|
Author:
|
|
|
|
Melur Raghuraman (mraghu) 03-Oct-1997
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
Insung Park (insungp) 05-Jan-2001
|
|
|
|
Updated DumpEvent() so that by default, it searches WBEM namespace
|
|
for the event data layout information.
|
|
Functions added/modified: GetArraySize, GetItemType,
|
|
GetPropertiesFromWBEM, GetGuidsWbem, GetGuidsFile, and GetGuids.
|
|
|
|
Insung Park (insungp) 16-Jan-2001
|
|
|
|
Changes enabling tracerpt to handle an invalid type name array in the WBEM namespace.
|
|
Bug fixes for memory corruption (GetPropertiesFromWBEM and GetGuidsWBEM).
|
|
|
|
|
|
--*/
|
|
#ifdef __cplusplus
|
|
extern "C"{
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "cpdata.h"
|
|
#include <wbemidl.h>
|
|
#include "tracectr.h"
|
|
#include "item.h"
|
|
#include "guids.h"
|
|
|
|
#define BUFFER_SIZE 64*1024
|
|
#define MAX_BUFFER_SIZE 10*1024*1024
|
|
|
|
#define MOFWSTR 16360
|
|
#define MOFSTR 32720
|
|
#define MAXTYPE 256
|
|
#define 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;
|
|
|
|
#define EVENT_TRACE_TYPE_SPL_SPOOLJOB EVENT_TRACE_TYPE_START
|
|
#define EVENT_TRACE_TYPE_SPL_PRINTJOB EVENT_TRACE_TYPE_DEQUEUE
|
|
#define EVENT_TRACE_TYPE_SPL_DELETEJOB EVENT_TRACE_TYPE_END
|
|
#define EVENT_TRACE_TYPE_SPL_TRACKTHREAD EVENT_TRACE_TYPE_CHECKPOINT
|
|
#define EVENT_TRACE_TYPE_SPL_ENDTRACKTHREAD 0x0A
|
|
#define EVENT_TRACE_TYPE_SPL_JOBRENDERED 0x0B
|
|
#define EVENT_TRACE_TYPE_SPL_PAUSE 0x0C
|
|
#define EVENT_TRACE_TYPE_SPL_RESUME 0x0D
|
|
|
|
extern PTRACE_CONTEXT_BLOCK TraceContext;
|
|
extern ULONG TotalBuffersRead;
|
|
|
|
ULONG HPFReadCount = 0;
|
|
ULONG HPFWriteCount = 0;
|
|
|
|
ULONG TotalEventsLost = 0;
|
|
ULONG TotalEventCount = 0;
|
|
ULONG TimerResolution = 10;
|
|
ULONGLONG StartTime = 0;
|
|
ULONGLONG EndTime = 0;
|
|
BOOL fNoEndTime = FALSE;
|
|
__int64 ElapseTime;
|
|
|
|
PCHAR MofData = NULL;
|
|
size_t MofLength = 0;
|
|
BOOLEAN fIgnorePerfClock = FALSE;
|
|
BOOLEAN fRealTimeCircular = FALSE;
|
|
ULONG PointerSize = sizeof(PVOID) * 8;
|
|
|
|
BOOL g_bUserMode = FALSE;
|
|
|
|
static ULONG NumProc = 0;
|
|
ULONGLONG BogusThreads[64];
|
|
ULONG BogusCount=0;
|
|
ULONG IdleThreadCount=0;
|
|
BOOLEAN bCaptureBogusThreads=TRUE;
|
|
|
|
IWbemServices *pWbemServices = NULL;
|
|
|
|
void AnsiToUnicode(PCHAR str, PWCHAR wstr);
|
|
|
|
ULONG
|
|
ahextoi( WCHAR *s);
|
|
|
|
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
|
|
GetGuidsFile(
|
|
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
|
|
);
|
|
|
|
|
|
VOID
|
|
UpdateThreadData(
|
|
PJOB_RECORD pJob,
|
|
PEVENT_TRACE_HEADER pHeader,
|
|
PTHREAD_RECORD pThread
|
|
);
|
|
|
|
VOID
|
|
PrintJobCallback(
|
|
PEVENT_TRACE pEvent
|
|
);
|
|
|
|
void
|
|
WINAPI
|
|
DumpEvent(
|
|
PEVENT_TRACE pEvent
|
|
);
|
|
|
|
void
|
|
DumpMofVersionItem(
|
|
PMOF_VERSION pMofVersion
|
|
);
|
|
|
|
|
|
extern PWCHAR CpdiGuidToString(PWCHAR s, 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;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
memset (pMofInfo, 0, 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 in the file.
|
|
//
|
|
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 ){
|
|
wcscpy( pMofVersion->strType, 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
|
|
)
|
|
{
|
|
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 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;
|
|
case ItemOptArgs :
|
|
default : pItem->DataSize = 0;
|
|
}
|
|
|
|
|
|
pItem->strDescription = (PWCHAR) malloc( ( lstrlenW(strType)+1)*sizeof(WCHAR));
|
|
|
|
if( NULL == pItem->strDescription ){
|
|
free( pItem );
|
|
return;
|
|
}
|
|
wcscpy(pItem->strDescription, strType);
|
|
|
|
//
|
|
// 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;
|
|
|
|
if (pEvent == NULL)
|
|
return;
|
|
pHeader = (PEVENT_TRACE_HEADER)&pEvent->Header;
|
|
|
|
if (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_GUIDMAP) {
|
|
return;
|
|
}
|
|
|
|
BuildNumber = ((PTRACE_LOGFILE_HEADER)pEvent->MofData)->ProviderVersion;
|
|
BuildNumber &= (0xFAFFFFFF);
|
|
CurrentSystem.BuildNumber = BuildNumber;
|
|
|
|
pEvmInfo = (PTRACE_LOGFILE_HEADER) pEvent->MofData;
|
|
CurrentSystem.TimerResolution = pEvmInfo->TimerResolution / 10000;
|
|
CurrentSystem.NumberOfProcessors = pEvmInfo->NumberOfProcessors;
|
|
|
|
//
|
|
// If Multiple files are given, use the values from the first file.
|
|
//
|
|
|
|
if (NumProc == 0) {
|
|
NumProc = pEvmInfo->NumberOfProcessors;
|
|
RtlZeroMemory(&BogusThreads, 64*sizeof(ULONG));
|
|
}
|
|
|
|
//
|
|
// With Multiple LogFiles always take the largest time window
|
|
//
|
|
if ((CurrentSystem.StartTime == (ULONGLONG) 0) ||
|
|
((ULONGLONG)pHeader->TimeStamp.QuadPart < CurrentSystem.StartTime))
|
|
CurrentSystem.StartTime = pHeader->TimeStamp.QuadPart;
|
|
|
|
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.EndTime == 0) {
|
|
CurrentSystem.fNoEndTime = TRUE;
|
|
}
|
|
|
|
if (DSEndTime == 0)
|
|
DSEndTime = CurrentSystem.EndTime;
|
|
if (fDSOnly && CurrentSystem.EndTime > DSEndTime)
|
|
CurrentSystem.EndTime = DSEndTime;
|
|
|
|
pFileRec = (PPROCESS_FILE_RECORD)malloc(sizeof(PROCESS_FILE_RECORD));
|
|
if( pFileRec != NULL ){
|
|
// Temporary... WMI Should dereference ->LogFileName
|
|
LPWSTR pName = (LPWSTR)pEvmInfo;
|
|
pName = (LPWSTR)((PCHAR)pName + sizeof( TRACE_LOGFILE_HEADER ));
|
|
pFileRec->TraceName = (LPWSTR)malloc( ( lstrlenW( pName )+1 )*sizeof(WCHAR) );
|
|
if( pFileRec->TraceName != NULL ){
|
|
wcscpy( pFileRec->TraceName, pName );
|
|
}
|
|
|
|
pName += lstrlenW( pName ) + 1;
|
|
pFileRec->FileName = (LPWSTR)malloc( ( lstrlenW( pName )+1 )*sizeof(WCHAR) );
|
|
if( pFileRec->FileName != NULL ){
|
|
wcscpy( pFileRec->FileName, pName );
|
|
}
|
|
pFileRec->StartTime = pHeader->TimeStamp.QuadPart;
|
|
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.
|
|
// Also, thread creation between process rundown code (UserMode) and
|
|
// logger thread start (kernel mode) are missed.
|
|
// 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;
|
|
}
|
|
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;
|
|
char ImageName[16];
|
|
ULONG returnLength = 16;
|
|
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;
|
|
if ( AddProcess(ProcessId, &pProcess) ) {
|
|
//
|
|
// 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;
|
|
RtlZeroMemory(&ImageName, 16 * sizeof(CHAR) );
|
|
GetMofData(pEvent, L"ImageFileName", &ImageName, returnLength);
|
|
asize = lstrlenA(ImageName);
|
|
if (asize > 0) {
|
|
pProcess->ImageName = (LPWSTR)malloc((asize + 1) * sizeof(WCHAR));
|
|
if (pProcess->ImageName == NULL) {
|
|
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) {
|
|
return;
|
|
}
|
|
if (ProcessId == 0)
|
|
{
|
|
wcscpy(pProcess->ImageName, L"Idle");
|
|
}
|
|
else
|
|
{
|
|
wsprintfW(pProcess->ImageName,
|
|
L"Unknown(0x%08X)",
|
|
ProcessId);
|
|
}
|
|
}
|
|
|
|
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];
|
|
strcpy(pFullName, "\\\\");
|
|
strcat(pFullName, Domain);
|
|
strcat(pFullName, "\\");
|
|
strcat(pFullName, 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) {
|
|
wcscpy(pProcess->UserName, L"system");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PsEndCallback(
|
|
PEVENT_TRACE pEvent
|
|
)
|
|
{
|
|
PEVENT_TRACE_HEADER pHeader;
|
|
ULONG ProcessId;
|
|
ULONG ReadId = 0;
|
|
PPROCESS_RECORD pProcess;
|
|
char ImageName[16];
|
|
ULONG returnLength = 16;
|
|
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;
|
|
RtlZeroMemory(&ImageName, 16 * sizeof(CHAR) );
|
|
GetMofData(pEvent, L"ImageFileName", &ImageName, returnLength);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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];
|
|
strcpy(pFullName, "\\\\");
|
|
strcat(pFullName, Domain);
|
|
strcat(pFullName, "\\");
|
|
strcat(pFullName, 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) {
|
|
wcscpy(pProcess->UserName, 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 = pEvent->ClientContext & 0x000000FF;
|
|
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;
|
|
// }
|
|
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 ( (ThreadId == pHeader->ThreadId)
|
|
|| (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_DC_END))
|
|
{
|
|
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));
|
|
event.Header.TimeStamp.QuadPart = CurrentSystem.EndTime;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
memcpy( &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.
|
|
// Also, thread creation between process rundown code (UserMode) and
|
|
// logger thread start (kernel mode) are missed.
|
|
// 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;
|
|
}
|
|
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
|
|
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;
|
|
PPROTO_FILE_RECORD protoFileRec;
|
|
PFILE_OBJECT fileObj;
|
|
PVOID fDO;
|
|
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, MAXSTR * sizeof(WCHAR));
|
|
|
|
GetMofData(pEvent, L"FileObject", &fDO, sizeof(ULONG));
|
|
RetLength = GetMofData(pEvent, L"FileName", &FileName, MAXSTR*sizeof(WCHAR));
|
|
if (RetLength == 0) {
|
|
return;
|
|
}
|
|
|
|
// Remember to Add the DISKNUMBER to the name
|
|
//
|
|
// When we get a FileName We need to find the FILE_RECORD
|
|
//
|
|
if ((fileRec = FindFileRecordByName(FileName)) == NULL) {
|
|
AddFile(FileName, &fileRec);
|
|
}
|
|
|
|
//
|
|
// Get the FileObject from the fileTable and update the information.
|
|
//
|
|
|
|
fileObj = FindFileInTable(fDO);
|
|
if (fileObj == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (fileObj->fileRec != NULL) {
|
|
/*
|
|
#if DBG
|
|
DbgPrint("BUG: APC for known file %ws\n", FileName);
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
if ((pThread = FindGlobalThreadById(pHeader->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, 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, 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 pModule = SearchSysModule(pProcess, lPC, TRUE);
|
|
if (pModule)
|
|
{
|
|
UpdatePageFaultCount(
|
|
pProcess, pModule, lFaultAddr, pHeader->Class.Type);
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
PLIST_ENTRY pModuleHead = & pProcess->ModuleListHead;
|
|
PLIST_ENTRY pModuleNext = pModuleHead->Flink;
|
|
PMODULE_RECORD pModule;
|
|
|
|
while (pModuleNext != pModuleHead)
|
|
{
|
|
pModule = CONTAINING_RECORD(pModuleNext,
|
|
MODULE_RECORD,
|
|
Entry);
|
|
pModuleNext = pModuleNext->Flink;
|
|
if (!_wcsicmp(pModule->strModuleName, L"other"))
|
|
{
|
|
if ( pModule->lBaseAddress == 0
|
|
&& pModule->lModuleSize == 0)
|
|
{
|
|
pModule->lBaseAddress = lPC;
|
|
pModule->lModuleSize = 1;
|
|
}
|
|
else if (pModule->lBaseAddress > lPC)
|
|
{
|
|
pModule->lModuleSize += pModule->lBaseAddress - lPC;
|
|
pModule->lBaseAddress = lPC;
|
|
}
|
|
else if ( pModule->lModuleSize
|
|
< lPC - pModule->lBaseAddress + 1)
|
|
{
|
|
pModule->lModuleSize =
|
|
lPC - pModule->lBaseAddress + 1;
|
|
}
|
|
UpdatePageFaultCount(
|
|
pProcess,
|
|
pModule,
|
|
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 = (PUCHAR) pEvent->MofData;
|
|
ULONG RequiredLength = 0;
|
|
BOOLEAN AddNull = FALSE;
|
|
PLIST_ENTRY Head, Next;
|
|
PMOF_INFO pMofInfo;
|
|
PMOF_VERSION pMofVersion;
|
|
|
|
if (pEvent == NULL)
|
|
return 0;
|
|
|
|
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 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 :
|
|
{
|
|
PULONG pSid;
|
|
pSid = (PULONG) pData;
|
|
if (*pSid == 0) {
|
|
RequiredLength = 4;
|
|
}
|
|
else {
|
|
pData += 8; // skip the TOKEN_USER structure
|
|
RequiredLength = 8 + (4*pData[1]);
|
|
|
|
}
|
|
}
|
|
break;
|
|
case ItemPtr :
|
|
{
|
|
RequiredLength = PointerSize / 8;
|
|
if ( (RequiredLength != 4) && (RequiredLength != 8) ) {
|
|
RequiredLength = 4;
|
|
}
|
|
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;
|
|
}
|
|
|
|
memcpy(ReturnValue, pData, RequiredLength);
|
|
|
|
if (AddNull) {
|
|
WCHAR* ws;
|
|
ws = (WCHAR*) ReturnValue;
|
|
ws[RequiredLength/2] = 0;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
else {
|
|
|
|
}
|
|
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, MAXSTR);
|
|
pMofData = FindMofData(pMofInfo, strSortKey );
|
|
wcscpy(pThread->strSortKey, 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
ThreadRunDown(
|
|
IN PSYSTEM_PROCESS_INFORMATION pProcessInfo
|
|
)
|
|
{
|
|
PSYSTEM_THREAD_INFORMATION pThreadInfo;
|
|
ULONG i;
|
|
EVENT_TRACE Event;
|
|
HANDLE EventInfo[2];
|
|
PEVENT_TRACE_HEADER pWnode;
|
|
ULONG TimerResolution = 1; // How do I get this??
|
|
|
|
RtlZeroMemory(&Event, sizeof(EVENT_TRACE));
|
|
|
|
pWnode = &Event.Header;
|
|
pWnode->Size = sizeof(EVENT_TRACE_HEADER) + 2 * sizeof(HANDLE);
|
|
pWnode->Class.Type = EVENT_TRACE_TYPE_DC_START;
|
|
Event.MofData = EventInfo;
|
|
Event.MofLength = 2 * sizeof(HANDLE);
|
|
GetSystemTimeAsFileTime((struct _FILETIME *)&pWnode->TimeStamp);
|
|
RtlCopyMemory(&pWnode->Guid, &ThreadGuid, sizeof(GUID));
|
|
|
|
|
|
pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
|
|
|
|
for (i=0; i < pProcessInfo->NumberOfThreads; i++) {
|
|
EventInfo[0] = pThreadInfo->ClientId.UniqueThread;
|
|
EventInfo[1] = pThreadInfo->ClientId.UniqueProcess;
|
|
pWnode->KernelTime = (ULONG) (pThreadInfo->KernelTime.QuadPart
|
|
/ TimerResolution);
|
|
pWnode->UserTime = (ULONG) (pThreadInfo->UserTime.QuadPart
|
|
/ TimerResolution);
|
|
|
|
ThreadCallback(&Event);
|
|
|
|
pThreadInfo += 1;
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
ProcessRunDown(
|
|
)
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION pProcessInfo;
|
|
PSYSTEM_THREAD_INFORMATION pThreadInfo;
|
|
char* LargeBuffer1;
|
|
NTSTATUS status;
|
|
ULONG ReturnLength;
|
|
ULONG CurrentBufferSize;
|
|
ULONG TotalOffset = 0;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
EVENT_TRACE Event;
|
|
ULONG_PTR AuxInfo[64];
|
|
PEVENT_TRACE_HEADER pWnode;
|
|
RtlZeroMemory(&Event, sizeof(EVENT_TRACE));
|
|
pWnode = &Event.Header;
|
|
pWnode->Size = sizeof(EVENT_TRACE_HEADER) + 2 * sizeof(HANDLE);
|
|
pWnode->Class.Type = EVENT_TRACE_TYPE_DC_START;
|
|
Event.MofData = AuxInfo;
|
|
Event.MofLength = 2 * sizeof(HANDLE);
|
|
GetSystemTimeAsFileTime((struct _FILETIME *)&pWnode->TimeStamp);
|
|
RtlCopyMemory(&pWnode->Guid, &ProcessGuid, sizeof(GUID));
|
|
|
|
LargeBuffer1 = (LPSTR)VirtualAlloc (NULL,
|
|
MAX_BUFFER_SIZE,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (LargeBuffer1 == NULL) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
if (VirtualAlloc (LargeBuffer1,
|
|
BUFFER_SIZE,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE) == NULL) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
CurrentBufferSize = BUFFER_SIZE;
|
|
retry:
|
|
status = NtQuerySystemInformation(
|
|
SystemProcessInformation,
|
|
LargeBuffer1,
|
|
CurrentBufferSize,
|
|
&ReturnLength
|
|
);
|
|
|
|
if (status == STATUS_INFO_LENGTH_MISMATCH) {
|
|
|
|
//
|
|
// Increase buffer size.
|
|
//
|
|
|
|
CurrentBufferSize += 8192;
|
|
|
|
if (VirtualAlloc (LargeBuffer1,
|
|
CurrentBufferSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE) == NULL) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
goto retry;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return(status);
|
|
}
|
|
|
|
|
|
TotalOffset = 0;
|
|
pProcessInfo = (SYSTEM_PROCESS_INFORMATION *) LargeBuffer1;
|
|
while (pProcessInfo != NULL) {
|
|
ULONG Size;
|
|
ULONG Length = 0;
|
|
ULONG SidLength = 0;
|
|
PUCHAR AuxPtr;
|
|
ANSI_STRING s;
|
|
HANDLE Token;
|
|
HANDLE pProcess;
|
|
PCLIENT_ID Cid;
|
|
ULONG TempInfo[128];
|
|
|
|
s.Buffer = NULL;
|
|
s.Length = 0;
|
|
|
|
Size = sizeof(EVENT_TRACE_HEADER) + 2 * sizeof(ULONG_PTR);
|
|
|
|
pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
|
|
if (pProcessInfo->NumberOfThreads > 0) {
|
|
Cid = (PCLIENT_ID) &pThreadInfo->ClientId;
|
|
}
|
|
else {
|
|
Cid = NULL;
|
|
}
|
|
|
|
if ( pProcessInfo->ImageName.Buffer &&
|
|
pProcessInfo->ImageName.Length > 0 ) {
|
|
RtlUnicodeStringToAnsiString(
|
|
&s,
|
|
(PUNICODE_STRING)&pProcessInfo->ImageName,
|
|
TRUE);
|
|
Length = s.Length + 1;
|
|
}
|
|
else {
|
|
Length = 1;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes, 0, 0, NULL, NULL);
|
|
status = NtOpenProcess(
|
|
&pProcess,
|
|
PROCESS_QUERY_INFORMATION,
|
|
&objectAttributes,
|
|
Cid);
|
|
if (NT_SUCCESS(status)) {
|
|
status = NtOpenProcessToken(
|
|
pProcess,
|
|
TOKEN_READ,
|
|
&Token);
|
|
if (NT_SUCCESS(status)) {
|
|
status = NtQueryInformationToken(
|
|
Token,
|
|
TokenUser,
|
|
TempInfo,
|
|
256,
|
|
&SidLength);
|
|
NtClose(Token);
|
|
}
|
|
NtClose(pProcess);
|
|
}
|
|
if ( (!NT_SUCCESS(status)) || SidLength <= 0) {
|
|
TempInfo[0] = 0;
|
|
SidLength = sizeof(ULONG);
|
|
}
|
|
|
|
Size += Length + SidLength;
|
|
|
|
AuxInfo[0] = (ULONG_PTR) pProcessInfo->UniqueProcessId;
|
|
AuxInfo[1] = (ULONG_PTR) pProcessInfo->InheritedFromUniqueProcessId;
|
|
AuxPtr = (PUCHAR) &AuxInfo[2];
|
|
|
|
RtlCopyMemory(AuxPtr, &TempInfo, SidLength);
|
|
AuxPtr += SidLength;
|
|
|
|
if ( Length > 1) {
|
|
RtlCopyMemory(AuxPtr, s.Buffer, Length);
|
|
AuxPtr += Length;
|
|
RtlFreeAnsiString(&s);
|
|
}
|
|
*AuxPtr = '\0';
|
|
AuxPtr++;
|
|
|
|
Event.MofLength = Size - sizeof(EVENT_TRACE_HEADER);
|
|
|
|
ProcessCallback(&Event);
|
|
|
|
ThreadRunDown(pProcessInfo);
|
|
|
|
if (pProcessInfo->NextEntryOffset == 0) {
|
|
break;
|
|
}
|
|
TotalOffset += pProcessInfo->NextEntryOffset;
|
|
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
|
|
}
|
|
VirtualFree(LargeBuffer1, 0, MEM_RELEASE);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// 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 GetGuidsFile( 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)
|
|
wcscpy(strFormat, pVal.bstrVal);
|
|
|
|
bszQualName = SysAllocString(L"StringTermination");
|
|
VariantClear(&pVal);
|
|
hRes = pQualSet->Get(bszQualName,
|
|
0,
|
|
&pVal,
|
|
0);
|
|
SysFreeString(bszQualName);
|
|
if (ERROR_SUCCESS == hRes && NULL != pVal.bstrVal)
|
|
wcscpy(strTermination, pVal.bstrVal);
|
|
|
|
bszQualName = SysAllocString(L"pointer");
|
|
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)
|
|
wcscpy(strTemp, 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;
|
|
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"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;
|
|
}
|
|
|
|
PMOF_VERSION
|
|
GetPropertiesFromWBEM(
|
|
// IWbemServices *pWbemServices,
|
|
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;
|
|
|
|
TCHAR strClassName[MAXSTR];
|
|
TCHAR 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) {
|
|
wcscpy(strClassName, pClassName.bstrVal);
|
|
pMofInfo->strDescription = (LPTSTR)malloc((_tcslen(strClassName) + 1) * sizeof(TCHAR));
|
|
if (NULL != pMofInfo->strDescription) {
|
|
_tcscpy(pMofInfo->strDescription, 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 = (LPTSTR)malloc((_tcslen(pTypeNameData[lCount]) + 1) * sizeof(TCHAR));
|
|
if (pMofVersion->strType != NULL){
|
|
wcscpy(pMofVersion->strType, (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) {
|
|
wcscpy(strType, 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 = (LPTSTR)malloc((_tcslen(strType) + 1) * sizeof(TCHAR));
|
|
if (pMofVersion->strType != NULL){
|
|
_tcscpy(pMofVersion->strType, 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;
|
|
}
|
|
|
|
AddMofInfo(&ListHead,
|
|
bszPropName,
|
|
ItemType,
|
|
ArraySize);
|
|
}
|
|
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;
|
|
|
|
TCHAR strGuid[MAXSTR], strTargetGuid[MAXSTR];
|
|
|
|
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, &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) {
|
|
_tcscpy(strGuid, (LPTSTR)V_BSTR(&pGuidVal));
|
|
VariantClear ( &pGuidVal );
|
|
|
|
if (!_tcsstr(strGuid, _T("{")))
|
|
_stprintf(strGuid , _T("{%s}"), strGuid);
|
|
|
|
if (!_tcsicmp(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) {
|
|
//_tprintf(_T("Match Found: \t%s\t, version %d\n"), strGuid, nVersion);
|
|
// 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
|
|
GetGuidsFile( GUID Guid, SHORT nVersion, CHAR nLevel, SHORT nType, BOOL bKernelEvent )
|
|
{
|
|
FILE *f = NULL;
|
|
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
|
|
//
|
|
|
|
if (TraceContext->MofFileName != NULL) {
|
|
f = _wfopen( TraceContext->MofFileName, L"r" );
|
|
if( !f ){
|
|
return NULL;
|
|
}
|
|
}else{
|
|
return NULL;
|
|
}
|
|
|
|
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_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_ItemPort)) type = ItemPort;
|
|
else if(! _wcsicmp(s,STR_ItemPtr)) type = ItemPtr;
|
|
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 );
|
|
}
|
|
}
|
|
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 ){
|
|
wcscpy( pMofVersion->strType, 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 ){
|
|
wcscpy(pMofInfo->strDescription, 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 );
|
|
fclose(f);
|
|
return pMofLookup;
|
|
}
|
|
|
|
|
|
VOID
|
|
UpdateThreadData(
|
|
PJOB_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;
|
|
PJOB_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 = FindJobRecord(pThread->JobId);
|
|
UpdateThreadData(pJob, pHeader, pThread);
|
|
}
|
|
|
|
pThread->JobId = JobId;
|
|
}
|
|
}
|
|
|
|
if (JobId == 0) return; // To filter all th termination without print jobs.
|
|
|
|
|
|
pJob = FindJobRecord(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.
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pJob->Entry );
|
|
LeaveTracelibCritSection();
|
|
free (pJob);
|
|
}
|
|
pJob = AddJobRecord(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;
|
|
|
|
UpdateThreadData(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;
|
|
|
|
}
|
|
DeleteJobRecord(pJob, (TraceContext->Flags & TRACE_SPOOLER));
|
|
}
|
|
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
|
|
GeneralEventCallback(
|
|
PEVENT_TRACE pEvent
|
|
)
|
|
{
|
|
PTHREAD_RECORD pThread;
|
|
|
|
if ((pEvent == NULL) || (TraceContext == NULL))
|
|
return;
|
|
|
|
// 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.
|
|
//
|
|
|
|
if ( (pEvent->Header.ThreadId == -1) ||
|
|
(pEvent->Header.FieldTypeFlags & EVENT_TRACE_USE_NOCPUTIME) ) {
|
|
if (TraceContext->Flags & (TRACE_DUMP|TRACE_SUMMARY)) {
|
|
DumpEvent(pEvent);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
pThread = FindGlobalThreadById(pEvent->Header.ThreadId, pEvent);
|
|
|
|
if ( CurrentSystem.fNoEndTime
|
|
&& CurrentSystem.EndTime < (ULONGLONG) pEvent->Header.TimeStamp.QuadPart)
|
|
{
|
|
CurrentSystem.EndTime = pEvent->Header.TimeStamp.QuadPart;
|
|
if (fDSOnly && CurrentSystem.EndTime > DSEndTime)
|
|
CurrentSystem.EndTime = DSEndTime;
|
|
}
|
|
|
|
EventCount ++;
|
|
|
|
if (IsEqualGUID(&pEvent->Header.Guid, &EventTraceGuid))
|
|
{
|
|
AdjustThreadTime(pEvent, pThread);
|
|
LogHeaderCallback(pEvent);
|
|
}
|
|
else 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)
|
|
{
|
|
AdjustThreadTime(pEvent, pThread);
|
|
if (IsEqualGUID(&pEvent->Header.Guid, &DiskIoGuid))
|
|
{
|
|
DiskIoCallback(pEvent, pThread);
|
|
}
|
|
else if (IsEqualGUID(&pEvent->Header.Guid, &FileIoGuid))
|
|
{
|
|
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)) {
|
|
// Ignore for now.
|
|
// We need to pick this up for a Hardwareconfig report.
|
|
//
|
|
}
|
|
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;
|
|
}
|
|
|
|
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
|
|
WINAPI
|
|
DumpEvent(
|
|
PEVENT_TRACE pEvent
|
|
)
|
|
{
|
|
PEVENT_TRACE_HEADER pHeader;
|
|
ULONG i;
|
|
PITEM_DESC pItem;
|
|
char str[MOFSTR];
|
|
WCHAR wstr[MOFWSTR];
|
|
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( IsEqualGUID(&pEvent->Header.Guid, &EventTraceGuid) &&
|
|
pEvent->Header.Class.Type == EVENT_TRACE_TYPE_INFO ) {
|
|
|
|
PTRACE_LOGFILE_HEADER head = (PTRACE_LOGFILE_HEADER)pEvent->MofData;
|
|
if( NULL != head ){
|
|
g_bUserMode = (head->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE);
|
|
|
|
if(head->TimerResolution > 0){
|
|
TimerResolution = head->TimerResolution / 10000;
|
|
}
|
|
|
|
StartTime = head->StartTime.QuadPart;
|
|
EndTime = head->EndTime.QuadPart;
|
|
fNoEndTime = (EndTime == 0);
|
|
|
|
PointerSize = head->PointerSize;
|
|
if (PointerSize < 16){ // minimum is 16 bits
|
|
PointerSize = 32; // defaults = 32 bits
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fNoEndTime && EndTime < (ULONGLONG) pHeader->TimeStamp.QuadPart) {
|
|
EndTime = pHeader->TimeStamp.QuadPart;
|
|
}
|
|
|
|
if (MofData == NULL) {
|
|
MofLength = pEvent->MofLength + sizeof(UNICODE_NULL);
|
|
MofData = (LPSTR)malloc(MofLength);
|
|
}
|
|
else if ((pEvent->MofLength + sizeof(UNICODE_NULL)) > MofLength) {
|
|
MofLength = pEvent->MofLength + sizeof(UNICODE_NULL);
|
|
MofData = (LPSTR)realloc(MofData, MofLength);
|
|
}
|
|
|
|
if (MofData == NULL) {
|
|
return;
|
|
}
|
|
if ((pEvent->MofData == NULL) && (0 != pEvent->MofLength)) {
|
|
return;
|
|
}
|
|
|
|
if (pEvent->MofData != NULL) {
|
|
memcpy(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;
|
|
|
|
if( pMofInfo->strDescription != NULL ){
|
|
fwprintf( DumpFile, L"%12s, ", pMofInfo->strDescription );
|
|
}else{
|
|
fwprintf( DumpFile, L"%12s, ", CpdiGuidToString( wstr, &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%04X, ", 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:
|
|
for (i=0;i<pItem->ArraySize;i++){
|
|
iChar = *((PCHAR) ptr);
|
|
fwprintf(DumpFile, L"%c", iChar);
|
|
ptr += sizeof(CHAR);
|
|
}
|
|
fwprintf(DumpFile, L", " );
|
|
break;
|
|
case ItemCharHidden:
|
|
ptr += sizeof(CHAR) * pItem->ArraySize;
|
|
break;
|
|
case ItemWChar:
|
|
for(i=0;i<pItem->ArraySize;i++){
|
|
iwChar = *((PWCHAR) ptr);
|
|
fwprintf(DumpFile, L"%wc", iwChar);
|
|
ptr += sizeof(WCHAR);
|
|
}
|
|
fwprintf(DumpFile, L", ");
|
|
break;
|
|
case ItemCharSign:
|
|
{
|
|
char sign[5];
|
|
memcpy(&sign, ptr, sizeof(CHAR) * 2);
|
|
sign[2] = '\0';
|
|
strcpy(str, sign);
|
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
|
ptr += sizeof(CHAR) * 2;
|
|
break;
|
|
}
|
|
|
|
case ItemCharShort:
|
|
iChar = *((PCHAR) ptr);
|
|
fwprintf(DumpFile, L"%d, ", iChar);
|
|
ptr += sizeof(CHAR);
|
|
break;
|
|
|
|
case ItemShort:
|
|
shortword = * ((PSHORT) ptr);
|
|
fwprintf(DumpFile, L"%6d, ", shortword);
|
|
ptr += sizeof (SHORT);
|
|
break;
|
|
|
|
case ItemUShort:
|
|
ushortword = *((PUSHORT) ptr);
|
|
fwprintf(DumpFile, L"%6u, ", ushortword);
|
|
ptr += sizeof (USHORT);
|
|
break;
|
|
|
|
case ItemLong:
|
|
longword = *((PLONG) ptr);
|
|
fwprintf(DumpFile, L"%8d, ", longword);
|
|
ptr += sizeof (LONG);
|
|
break;
|
|
|
|
case ItemULong:
|
|
ulongword = *((PULONG) ptr);
|
|
fwprintf(DumpFile, L"%8lu, ", ulongword);
|
|
ptr += sizeof (ULONG);
|
|
break;
|
|
|
|
case ItemULongX:
|
|
ulongword = *((PULONG) ptr);
|
|
fwprintf(DumpFile, L"0x%08X, ", ulongword);
|
|
ptr += sizeof (ULONG);
|
|
break;
|
|
|
|
case ItemPtr :
|
|
{
|
|
unsigned __int64 pointer;
|
|
if (PointerSize == 64) {
|
|
pointer = *((unsigned __int64 *) ptr);
|
|
fwprintf(DumpFile, L"0x%X, ", pointer);
|
|
}
|
|
else { // assumes 32 bit otherwise
|
|
ulongword = *((PULONG) ptr);
|
|
fwprintf(DumpFile, L"0x%08X, ", ulongword);
|
|
}
|
|
ptr += PointerSize / 8;
|
|
//
|
|
// If target source is Win64, then use Ptr, else use ulongword
|
|
//
|
|
break;
|
|
}
|
|
|
|
case ItemIPAddr:
|
|
{
|
|
ulongword = *((PULONG) ptr);
|
|
|
|
// 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 ItemPort:
|
|
{
|
|
fwprintf(DumpFile, L"%u, ", NTOHS((USHORT) *ptr));
|
|
ptr += sizeof (USHORT);
|
|
break;
|
|
}
|
|
|
|
case ItemLongLong:
|
|
{
|
|
LONGLONG n64;
|
|
n64 = *((LONGLONG*) ptr);
|
|
ptr += sizeof(LONGLONG);
|
|
fwprintf(DumpFile, L"%16I64d, ", n64);
|
|
break;
|
|
}
|
|
|
|
case ItemULongLong:
|
|
{
|
|
ULONGLONG n64;
|
|
n64 = *((ULONGLONG*) ptr);
|
|
ptr += sizeof(ULONGLONG);
|
|
fwprintf(DumpFile, L"%16I64u, ", n64);
|
|
break;
|
|
}
|
|
|
|
case ItemString:
|
|
case ItemRString:
|
|
{
|
|
USHORT pLen = (USHORT)strlen((CHAR*) ptr);
|
|
|
|
if (pLen > 0)
|
|
{
|
|
strcpy(str, ptr);
|
|
if (pItem->ItemType == ItemRString)
|
|
{
|
|
reduceA(str);
|
|
}
|
|
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:
|
|
{
|
|
size_t pLen = 0;
|
|
size_t i;
|
|
|
|
if (*(WCHAR *) ptr)
|
|
{
|
|
if (pItem->ItemType == ItemRWString)
|
|
{
|
|
reduceW((WCHAR *) ptr);
|
|
}
|
|
pLen = ((lstrlenW((WCHAR*)ptr) + 1) * sizeof(WCHAR));
|
|
memcpy(wstr, ptr, pLen);
|
|
for (i = (pLen/2)-1; i > 0; i--)
|
|
{
|
|
if (((USHORT) wstr[i] == (USHORT) 0xFFFF))
|
|
{
|
|
wstr[i] = (USHORT) 0;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
wstr[pLen / 2] = wstr[(pLen / 2) + 1]= '\0';
|
|
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)
|
|
{
|
|
strcpy(str, ptr);
|
|
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
|
|
fwprintf(DumpFile, L"\"%ws\", ", wstr);
|
|
}
|
|
ptr += (pLen + 1);
|
|
break;
|
|
}
|
|
|
|
case ItemPString: // Counted String
|
|
{
|
|
USHORT pLen = * ((USHORT *) ptr);
|
|
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) {
|
|
memcpy(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 = (USHORT)(( pItem->ItemType == ItemDSWString)
|
|
? (256 * ((USHORT) * ptr) + ((USHORT) * (ptr + 1)))
|
|
: (* ((USHORT *) ptr)));
|
|
|
|
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) {
|
|
memcpy(wstr, ptr, pLen);
|
|
wstr[pLen / sizeof(WCHAR)] = L'\0';
|
|
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)
|
|
{
|
|
memcpy(wstr, ptr, Size);
|
|
wstr[Size / 2] = '\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;
|
|
|
|
sprintf(strCount, "{%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 Sid[64];
|
|
PULONG pSid = & Sid[0];
|
|
SID_NAME_USE Se;
|
|
ULONG nSidLength;
|
|
|
|
pSid = (PULONG) ptr;
|
|
if (*pSid == 0){
|
|
ptr += 4;
|
|
fwprintf(DumpFile, L"%4d, ", *pSid);
|
|
}
|
|
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];
|
|
swprintf( pFullName, 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[64];
|
|
|
|
fwprintf(DumpFile, L"%s, ", CpdiGuidToString(&s[0], (LPGUID)ptr));
|
|
ptr += sizeof(GUID);
|
|
break;
|
|
}
|
|
|
|
case ItemCPUTime:
|
|
{
|
|
ulongword = * ((PULONG) ptr);
|
|
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;
|
|
DWORD i;
|
|
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) {
|
|
lValue32 = * ((LONG *) ptr);
|
|
ptr += sizeof(LONG);
|
|
fwprintf(DumpFile, 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) {
|
|
fwprintf(DumpFile, L"\"%s\",", aszString);
|
|
ptr += sizeof(CHAR) * (lstrlenA(aszString) + 1);
|
|
}
|
|
break;
|
|
|
|
case 3: // LONG64
|
|
dwMofUsed += sizeof(LONGLONG);
|
|
if (dwMofUsed <= dwMofLen) {
|
|
lValue64 = * ((LONGLONG *) ptr);
|
|
ptr += sizeof(LONGLONG);
|
|
fwprintf(DumpFile, L"%I64d,", lValue64);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ItemVariant:
|
|
{
|
|
//
|
|
// Variable Size. First ULONG gives the sizee and the rest is blob
|
|
//
|
|
ulongword = *((PULONG) ptr);
|
|
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 = (BOOL)*ptr;
|
|
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 );
|
|
}
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|