You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1331 lines
77 KiB
1331 lines
77 KiB
/*++ BUILD Version: 0001 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
extinit.c
|
|
|
|
Abstract:
|
|
|
|
This file implements all the initialization library routines operating on
|
|
extensible performance libraries.
|
|
|
|
Author:
|
|
|
|
JeePang
|
|
|
|
Revision History:
|
|
|
|
09/27/2000 - JeePang - Moved from perflib.c
|
|
|
|
--*/
|
|
#define UNICODE
|
|
//
|
|
// Include files
|
|
//
|
|
#pragma warning(disable:4306)
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntregapi.h>
|
|
#include <ntprfctr.h>
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <winperf.h>
|
|
#include <rpc.h>
|
|
#include "regrpc.h"
|
|
#include "ntconreg.h"
|
|
#include "prflbmsg.h" // event log messages
|
|
#include "perflib.h"
|
|
#pragma warning(default:4306)
|
|
|
|
//
|
|
// static constant definitions
|
|
//
|
|
// constants used by guard page testing
|
|
//
|
|
#define GUARD_PAGE_SIZE 1024
|
|
#define GUARD_PAGE_CHAR 0xA5
|
|
#define GUARD_PAGE_DWORD 0xA5A5A5A5
|
|
|
|
typedef struct _EXT_OBJ_ITEM {
|
|
DWORD dwObjId;
|
|
DWORD dwFlags;
|
|
} EXT_OBJ_LIST, *PEXT_OBJ_LIST;
|
|
|
|
#define PERF_EOL_ITEM_FOUND ((DWORD)0x00000001)
|
|
|
|
__inline
|
|
DWORD
|
|
RegisterExtObjListAccess ()
|
|
{
|
|
LONG Status;
|
|
LARGE_INTEGER liWaitTime;
|
|
|
|
if (hGlobalDataMutex != NULL) {
|
|
liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
|
|
// wait for access to the list of ext objects
|
|
Status = NtWaitForSingleObject (
|
|
hGlobalDataMutex,
|
|
FALSE,
|
|
&liWaitTime);
|
|
if (Status != WAIT_TIMEOUT) {
|
|
if (hExtObjListIsNotInUse != NULL) {
|
|
// indicate that we are going to use the list
|
|
InterlockedIncrement ((LONG *)&dwExtObjListRefCount);
|
|
if (dwExtObjListRefCount > 0) {
|
|
ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
|
|
} else {
|
|
SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
} else {
|
|
Status = ERROR_NOT_READY;
|
|
}
|
|
ReleaseMutex (hGlobalDataMutex);
|
|
} // else return status;
|
|
} else {
|
|
Status = ERROR_LOCK_FAILED;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
__inline
|
|
DWORD
|
|
DeRegisterExtObjListAccess ()
|
|
{
|
|
LONG Status;
|
|
LARGE_INTEGER liWaitTime;
|
|
|
|
if (hGlobalDataMutex != NULL) {
|
|
liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
|
|
// wait for access to the list of ext objects
|
|
Status = NtWaitForSingleObject (
|
|
hGlobalDataMutex,
|
|
FALSE,
|
|
&liWaitTime);
|
|
if (Status != WAIT_TIMEOUT) {
|
|
if (hExtObjListIsNotInUse != NULL) {
|
|
assert (dwExtObjListRefCount > 0);
|
|
// indicate that we are going to use the list
|
|
InterlockedDecrement ((LONG *)&dwExtObjListRefCount);
|
|
if (dwExtObjListRefCount > 0) {
|
|
ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
|
|
} else {
|
|
SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
} else {
|
|
Status = ERROR_NOT_READY;
|
|
}
|
|
ReleaseMutex (hGlobalDataMutex);
|
|
} // else return status;
|
|
} else {
|
|
Status = ERROR_LOCK_FAILED;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
LONG
|
|
QueryExtensibleData (
|
|
COLLECT_THREAD_DATA * pArgs
|
|
)
|
|
/*++
|
|
QueryExtensibleData - Get data from extensible objects
|
|
|
|
Inputs:
|
|
|
|
dwQueryType - Query type (GLOBAL, COSTLY, item list, etc.)
|
|
|
|
lpValueName - pointer to value string (unused)
|
|
|
|
lpData - pointer to start of data block
|
|
where data is being collected
|
|
|
|
lpcbData - pointer to size of data buffer
|
|
|
|
lppDataDefinition - pointer to pointer to where object
|
|
definition for this object type should
|
|
go
|
|
|
|
Outputs:
|
|
|
|
*lppDataDefinition - set to location for next Type
|
|
Definition if successful
|
|
|
|
Returns:
|
|
|
|
0 if successful, else Win 32 error code of failure
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD dwQueryType = pArgs->dwQueryType;
|
|
LPWSTR lpValueName = pArgs->lpValueName;
|
|
LPBYTE lpData = pArgs->lpData;
|
|
LPDWORD lpcbData = pArgs->lpcbData;
|
|
LPVOID *lppDataDefinition = pArgs->lppDataDefinition;
|
|
|
|
DWORD Win32Error=ERROR_SUCCESS; // Failure code
|
|
DWORD BytesLeft;
|
|
DWORD InitialBytesLeft;
|
|
DWORD NumObjectTypes;
|
|
|
|
LPVOID lpExtDataBuffer = NULL;
|
|
LPVOID lpCallBuffer = NULL;
|
|
LPVOID lpLowGuardPage = NULL;
|
|
LPVOID lpHiGuardPage = NULL;
|
|
LPVOID lpEndPointer = NULL;
|
|
LPVOID lpBufferBefore = NULL;
|
|
LPVOID lpBufferAfter = NULL;
|
|
PUCHAR lpCheckPointer;
|
|
LARGE_INTEGER liStartTime, liEndTime, liWaitTime, liDiff;
|
|
|
|
PEXT_OBJECT pThisExtObj = NULL;
|
|
DWORD dwLibEntry;
|
|
|
|
BOOL bGuardPageOK;
|
|
BOOL bBufferOK;
|
|
BOOL bException;
|
|
BOOL bUseSafeBuffer;
|
|
BOOL bUnlockObjData = FALSE;
|
|
|
|
LPTSTR szMessageArray[8];
|
|
ULONG_PTR dwRawDataDwords[8]; // raw data buffer
|
|
DWORD dwDataIndex;
|
|
WORD wStringIndex;
|
|
LONG lReturnValue = ERROR_SUCCESS;
|
|
|
|
LONG lDllTestLevel;
|
|
|
|
LONG lInstIndex;
|
|
DWORD lCtrIndex;
|
|
PERF_OBJECT_TYPE *pObject, *pNextObject;
|
|
PERF_INSTANCE_DEFINITION *pInstance;
|
|
PERF_COUNTER_DEFINITION *pCounterDef;
|
|
PERF_DATA_BLOCK *pPerfData;
|
|
BOOL bForeignDataBuffer;
|
|
|
|
DWORD dwItemsInArray = 0;
|
|
DWORD dwItemsInList = 0;
|
|
volatile PEXT_OBJ_LIST pQueryList = NULL;
|
|
LPWSTR pwcThisChar;
|
|
|
|
DWORD dwThisNumber;
|
|
DWORD dwIndex, dwEntry;
|
|
BOOL bFound;
|
|
BOOL bDisabled = FALSE;
|
|
BOOL bUseTimer;
|
|
DWORD dwType = 0;
|
|
DWORD dwValue = 0;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
DWORD status = 0;
|
|
DWORD dwObjectBufSize;
|
|
|
|
OPEN_PROC_WAIT_INFO opwInfo;
|
|
HANDLE hPerflibFuncTimer;
|
|
PVOID pNewBuffer;
|
|
|
|
HEAP_PROBE();
|
|
|
|
//
|
|
// Make sure that the caller's buffer is aligned properly
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
if ((ULONG_PTR) *lppDataDefinition & (ULONG_PTR) 0x07) {
|
|
DebugPrint((0, "QueryExtensibleData: lppDataDefinition not aligned %I64x\n", lppDataDefinition));
|
|
return ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
/*
|
|
if ((ULONG_PTR) *lpcbData & (ULONG_PTR) 0x07) {
|
|
DebugPrint((0, "QueryExtensibleData: lpcbData not aligned %I64x\n", *lpcbData));
|
|
return ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
*/
|
|
if ((ULONG_PTR) lpData & (ULONG_PTR) 0x07) {
|
|
DebugPrint((0, "QueryExtensibleData: lpData not aligned %I64x\n", lpData));
|
|
return ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
#endif
|
|
// see if perf data has been disabled
|
|
// this is to prevent crashing WINLOGON if the
|
|
// system has installed a bogus DLL
|
|
|
|
if (ghKeyPerflib == NULL || ghKeyPerflib == INVALID_HANDLE_VALUE) {
|
|
// Ignore Status return. We only need ghKeyPerflib to query "DisablePerformanceCounters" DWORD value.
|
|
//
|
|
HKEY lhKeyPerflib = NULL;
|
|
status = (DWORD) RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLMPerflibKey, 0L, KEY_READ, & lhKeyPerflib);
|
|
if (status == ERROR_SUCCESS) {
|
|
if (InterlockedCompareExchangePointer(& ghKeyPerflib, lhKeyPerflib, NULL) != NULL) {
|
|
RegCloseKey(lhKeyPerflib);
|
|
lhKeyPerflib = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert (ghKeyPerflib != NULL);
|
|
dwSize = sizeof(dwValue);
|
|
dwValue = dwType = 0;
|
|
if (ghKeyPerflib != NULL && ghKeyPerflib != INVALID_HANDLE_VALUE) {
|
|
status = PrivateRegQueryValueExW(
|
|
ghKeyPerflib,
|
|
DisablePerformanceCounters,
|
|
NULL,
|
|
& dwType,
|
|
(LPBYTE) & dwValue,
|
|
& dwSize);
|
|
if (status == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 1) {
|
|
// then DON'T Load any libraries and unload any that have been
|
|
// loaded
|
|
bDisabled = TRUE;
|
|
}
|
|
}
|
|
|
|
// if data collection is disabled and there's a collection thread
|
|
// then close it
|
|
if (bDisabled && (hCollectThread != NULL)) {
|
|
pArgs->dwActionFlags = CTD_AF_CLOSE_THREAD;
|
|
} else if (!bDisabled &&
|
|
((hCollectThread == NULL) && (dwCollectionFlags == COLL_FLAG_USE_SEPARATE_THREAD))) {
|
|
// then data collection is enabled and they want a separate collection
|
|
// thread, but there's no thread at the moment, so create it here
|
|
pArgs->dwActionFlags = CTD_AF_OPEN_THREAD;
|
|
}
|
|
|
|
lReturnValue = RegisterExtObjListAccess();
|
|
|
|
if (lReturnValue == ERROR_SUCCESS) {
|
|
liStartTime.QuadPart = 0;
|
|
InitialBytesLeft = 0;
|
|
liEndTime.QuadPart = 0;
|
|
|
|
if ((dwQueryType == QUERY_ITEMS) && (!bDisabled)) {
|
|
// alloc the call list
|
|
pwcThisChar = lpValueName;
|
|
dwThisNumber = 0;
|
|
|
|
// read the value string and build an object ID list
|
|
|
|
while (*pwcThisChar != 0) {
|
|
dwThisNumber = GetNextNumberFromList (
|
|
pwcThisChar, &pwcThisChar);
|
|
if (dwThisNumber != 0) {
|
|
if (dwItemsInList >= dwItemsInArray) {
|
|
dwItemsInArray += 16; // starting point for # of objects
|
|
pNewBuffer = NULL;
|
|
if (pQueryList == NULL) {
|
|
// alloc a new buffer
|
|
pNewBuffer = ALLOCMEM ((sizeof(EXT_OBJ_LIST) * dwItemsInArray));
|
|
} else {
|
|
// realloc a new buffer
|
|
pNewBuffer = REALLOCMEM(pQueryList,
|
|
(sizeof(EXT_OBJ_LIST) * dwItemsInArray));
|
|
}
|
|
if (pNewBuffer == NULL) {
|
|
// unable to alloc memory so bail
|
|
if (pQueryList)
|
|
FREEMEM(pQueryList);
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
else {
|
|
pQueryList = pNewBuffer;
|
|
}
|
|
}
|
|
|
|
// then add to the list
|
|
pQueryList[dwItemsInList].dwObjId = dwThisNumber;
|
|
pQueryList[dwItemsInList].dwFlags = 0;
|
|
dwItemsInList++;
|
|
}
|
|
}
|
|
|
|
if (Win32Error == ERROR_SUCCESS) {
|
|
//
|
|
// Walk through list of ext. objects and tag the ones to call
|
|
// as the query objects are found
|
|
//
|
|
for (pThisExtObj = ExtensibleObjects, dwLibEntry = 0;
|
|
pThisExtObj != NULL;
|
|
pThisExtObj = pThisExtObj->pNext, dwLibEntry++) {
|
|
|
|
if (pThisExtObj->dwNumObjects > 0) {
|
|
// then examine list
|
|
for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex++) {
|
|
// look at each entry in the list
|
|
for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
|
|
if (pQueryList[dwEntry].dwObjId == pThisExtObj->dwObjList[dwIndex]) {
|
|
// tag this entry as found
|
|
pQueryList[dwEntry].dwFlags |= PERF_EOL_ITEM_FOUND;
|
|
// tag the object as needed
|
|
pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// this entry doesn't list it's supported objects
|
|
}
|
|
}
|
|
|
|
assert (dwLibEntry == NumExtensibleObjects);
|
|
|
|
// see if any in the query list do not have entries
|
|
|
|
bFound = TRUE;
|
|
for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
|
|
if (!(pQueryList[dwEntry].dwFlags & PERF_EOL_ITEM_FOUND)) {
|
|
// no matching object found
|
|
bFound = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound) {
|
|
// at least one of the object ID's in the query list was
|
|
// not found in an object that supports an object list
|
|
// then tag all entries that DO NOT support an object list
|
|
// to be called and hope one of them supports it/them.
|
|
for (pThisExtObj = ExtensibleObjects;
|
|
pThisExtObj != NULL;
|
|
pThisExtObj = pThisExtObj->pNext) {
|
|
if (pThisExtObj->dwNumObjects == 0) {
|
|
// tag this one so it will be called
|
|
pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
|
|
}
|
|
}
|
|
}
|
|
} // end if first scan was successful
|
|
|
|
if (pQueryList != NULL) FREEMEM (pQueryList);
|
|
} // end if QUERY_ITEMS
|
|
|
|
|
|
if (lReturnValue == ERROR_SUCCESS) {
|
|
for (pThisExtObj = ExtensibleObjects;
|
|
pThisExtObj != NULL;
|
|
pThisExtObj = pThisExtObj->pNext) {
|
|
|
|
// set the current ext object pointer
|
|
pArgs->pCurrentExtObject = pThisExtObj;
|
|
// convert timeout value
|
|
liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
|
|
|
|
// close the unused Perf DLL's IF:
|
|
// the perflib key is disabled or this is an item query
|
|
// and this is an Item (as opposed to a global or foreign) query or
|
|
// the requested objects are not it this library or this library is disabled
|
|
// and this library has been opened
|
|
//
|
|
if (((dwQueryType == QUERY_ITEMS) || bDisabled) &&
|
|
(bDisabled || (!(pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY)) || (pThisExtObj->dwFlags & PERF_EO_DISABLED)) &&
|
|
(pThisExtObj->hLibrary != NULL)) {
|
|
// then free this object
|
|
if (pThisExtObj->hMutex != NULL) {
|
|
NTSTATUS NtStatus = NtWaitForSingleObject (
|
|
pThisExtObj->hMutex,
|
|
FALSE,
|
|
&liWaitTime);
|
|
Win32Error = PerfpDosError(NtStatus);
|
|
if (NtStatus == STATUS_SUCCESS) {
|
|
// then we got a lock
|
|
CloseExtObjectLibrary (pThisExtObj, bDisabled);
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
} else {
|
|
pThisExtObj->dwLockoutCount++;
|
|
DebugPrint((0, "Unable to Lock object for %ws to close in Query\n", pThisExtObj->szServiceName));
|
|
}
|
|
} else {
|
|
Win32Error = ERROR_LOCK_FAILED;
|
|
DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
|
|
}
|
|
|
|
if (hCollectThread != NULL) {
|
|
// close the collection thread
|
|
|
|
}
|
|
} else if (((dwQueryType == QUERY_FOREIGN) ||
|
|
(dwQueryType == QUERY_GLOBAL) ||
|
|
(dwQueryType == QUERY_COSTLY) ||
|
|
((dwQueryType == QUERY_ITEMS) &&
|
|
(pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY))) &&
|
|
(!(pThisExtObj->dwFlags & PERF_EO_DISABLED))) {
|
|
|
|
// initialize values to pass to the extensible counter function
|
|
NumObjectTypes = 0;
|
|
BytesLeft = (DWORD) (*lpcbData - ((LPBYTE) *lppDataDefinition - lpData));
|
|
bException = FALSE;
|
|
|
|
if ((pThisExtObj->hLibrary == NULL) ||
|
|
(dwQueryType == QUERY_GLOBAL) ||
|
|
(dwQueryType == QUERY_COSTLY)) {
|
|
// lock library object
|
|
if (pThisExtObj->hMutex != NULL) {
|
|
NTSTATUS NtStatus = NtWaitForSingleObject (
|
|
pThisExtObj->hMutex,
|
|
FALSE,
|
|
&liWaitTime);
|
|
Win32Error = ERROR_SUCCESS;
|
|
if (NtStatus == STATUS_SUCCESS) {
|
|
// if this is a global or costly query, then reset the "in query"
|
|
// flag for this object. The next ITEMS query will restore it.
|
|
if ((dwQueryType == QUERY_GLOBAL) ||
|
|
(dwQueryType == QUERY_COSTLY)) {
|
|
pThisExtObj->dwFlags &= ~PERF_EO_OBJ_IN_QUERY;
|
|
}
|
|
// if necessary, open the library
|
|
if (pThisExtObj->hLibrary == NULL) {
|
|
if ((GetCurrentThreadId() != pThisExtObj->ThreadId) &&
|
|
(pThisExtObj->dwOpenFail == 0)) {
|
|
// make sure the library is open
|
|
Win32Error = OpenExtObjectLibrary(pThisExtObj);
|
|
if (Win32Error != ERROR_SUCCESS) {
|
|
#if DBG
|
|
if (Win32Error != ERROR_SERVICE_DISABLED) {
|
|
// SERVICE_DISABLED is returned when the
|
|
// service has been disabled via ExCtrLst.
|
|
// so no point in complaining about it.
|
|
// assume error has been posted
|
|
DebugPrint((0, "Unable to open perf counter library for %ws, Error: 0x%8.8x\n",
|
|
pThisExtObj->szServiceName, Win32Error));
|
|
}
|
|
#endif
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
continue; // to next entry
|
|
}
|
|
}
|
|
else {
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
continue; // to next entry
|
|
}
|
|
}
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
} else {
|
|
Win32Error = PerfpDosError(NtStatus);
|
|
pThisExtObj->dwLockoutCount++;
|
|
DebugPrint((0, "Unable to Lock object for %ws to open for Query\n", pThisExtObj->szServiceName));
|
|
}
|
|
} else {
|
|
Win32Error = ERROR_LOCK_FAILED;
|
|
DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
|
|
}
|
|
} else {
|
|
// library should be ready to use
|
|
}
|
|
|
|
// if this dll is trusted, then use the system
|
|
// defined test level, otherwise, test it
|
|
// thorourghly
|
|
bUseTimer = TRUE; // default
|
|
if (!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) {
|
|
if (pThisExtObj->dwFlags & PERF_EO_TRUSTED) {
|
|
lDllTestLevel = lExtCounterTestLevel;
|
|
bUseTimer = FALSE; // Trusted DLL's are not timed
|
|
} else {
|
|
// not trusted so use full test
|
|
lDllTestLevel = EXT_TEST_ALL;
|
|
}
|
|
} else {
|
|
// disable DLL testing
|
|
lDllTestLevel = EXT_TEST_NOMEMALLOC;
|
|
bUseTimer = FALSE; // Timing is disabled as well
|
|
}
|
|
|
|
if (lDllTestLevel < EXT_TEST_NOMEMALLOC) {
|
|
bUseSafeBuffer = TRUE;
|
|
} else {
|
|
bUseSafeBuffer = FALSE;
|
|
}
|
|
|
|
// allocate a local block of memory to pass to the
|
|
// extensible counter function.
|
|
|
|
if (bUseSafeBuffer) {
|
|
lpExtDataBuffer = ALLOCMEM (BytesLeft + (2*GUARD_PAGE_SIZE));
|
|
} else {
|
|
lpExtDataBuffer =
|
|
lpCallBuffer = *lppDataDefinition;
|
|
}
|
|
|
|
if (lpExtDataBuffer != NULL) {
|
|
|
|
if (bUseSafeBuffer) {
|
|
// set buffer pointers
|
|
lpLowGuardPage = lpExtDataBuffer;
|
|
lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
|
|
lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
|
|
lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
|
|
|
|
// initialize GuardPage Data
|
|
|
|
memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
|
|
memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
|
|
}
|
|
|
|
lpBufferBefore = lpCallBuffer;
|
|
lpBufferAfter = NULL;
|
|
hPerflibFuncTimer = NULL;
|
|
|
|
try {
|
|
//
|
|
// Collect data from extensible objects
|
|
//
|
|
|
|
if (pThisExtObj->hMutex != NULL) {
|
|
NTSTATUS NtStatus = NtWaitForSingleObject (
|
|
pThisExtObj->hMutex,
|
|
FALSE,
|
|
&liWaitTime);
|
|
Win32Error = PerfpDosError(NtStatus);
|
|
if ((NtStatus == STATUS_SUCCESS) &&
|
|
(pThisExtObj->CollectProc != NULL)) {
|
|
|
|
bUnlockObjData = TRUE;
|
|
|
|
opwInfo.pNext = NULL;
|
|
opwInfo.szLibraryName = pThisExtObj->szLibraryName;
|
|
opwInfo.szServiceName = pThisExtObj->szServiceName;
|
|
opwInfo.dwWaitTime = pThisExtObj->dwCollectTimeout;
|
|
opwInfo.dwEventMsg = PERFLIB_COLLECTION_HUNG;
|
|
opwInfo.pData = (LPVOID)pThisExtObj;
|
|
if (bUseTimer) {
|
|
hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
|
|
// if no timer, continue anyway, even though things may
|
|
// hang, it's better than not loading the DLL since they
|
|
// usually load OK
|
|
//
|
|
if (hPerflibFuncTimer == NULL) {
|
|
// unable to get a timer entry
|
|
DebugPrint((0, "Unable to acquire timer for Collect Proc\n"));
|
|
}
|
|
} else {
|
|
hPerflibFuncTimer = NULL;
|
|
}
|
|
|
|
InitialBytesLeft = BytesLeft;
|
|
|
|
NtQueryPerformanceCounter (&liStartTime, NULL);
|
|
|
|
Win32Error = (*pThisExtObj->CollectProc) (
|
|
lpValueName,
|
|
&lpCallBuffer,
|
|
&BytesLeft,
|
|
&NumObjectTypes);
|
|
|
|
NtQueryPerformanceCounter (&liEndTime, &liDiff);
|
|
|
|
if (liDiff.QuadPart > 0) {
|
|
liDiff.QuadPart = (liEndTime.QuadPart - liStartTime.QuadPart) /
|
|
(liDiff.QuadPart / 1000) ;
|
|
if ((liDiff.QuadPart > 100) || (Win32Error != ERROR_SUCCESS)) {
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(&PerflibGuid, __LINE__, PERF_QUERY_EXTDATA,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_ULONG64, 2), Win32Error,
|
|
pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
|
|
liDiff, sizeof(liDiff), NULL));
|
|
}
|
|
}
|
|
|
|
if (hPerflibFuncTimer != NULL) {
|
|
// kill timer
|
|
KillPerflibFunctionTimer (hPerflibFuncTimer);
|
|
hPerflibFuncTimer = NULL;
|
|
}
|
|
|
|
// update statistics
|
|
|
|
pThisExtObj->dwLastBufferSize = BytesLeft;
|
|
|
|
if (BytesLeft > pThisExtObj->dwMaxBufferSize) {
|
|
pThisExtObj->dwMaxBufferSize = BytesLeft;
|
|
}
|
|
|
|
if ((Win32Error == ERROR_MORE_DATA) &&
|
|
(InitialBytesLeft > pThisExtObj->dwMaxBufferRejected)) {
|
|
pThisExtObj->dwMaxBufferRejected = InitialBytesLeft;
|
|
}
|
|
|
|
lpBufferAfter = lpCallBuffer;
|
|
|
|
pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
|
|
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
bUnlockObjData = FALSE;
|
|
#if DBG
|
|
if ( (((ULONG_PTR) lpCallBuffer) & 0x07) != 0) {
|
|
DbgPrint("Perflib: Misaligned pointer %X returned from '%s'\n",
|
|
lpCallBuffer, pThisExtObj->szLibraryName);
|
|
// ASSERT( (((ULONG_PTR)lpCallBuffer) & 0x07) == 0);
|
|
}
|
|
#endif
|
|
} else {
|
|
if (pThisExtObj->CollectProc != NULL) {
|
|
DebugPrint((0,
|
|
"Unable to Lock object for %ws to Collect data\n",
|
|
pThisExtObj->szServiceName));
|
|
TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
|
|
PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
|
|
pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
|
|
NULL));
|
|
if (THROTTLE_PERFDLL(PERFLIB_COLLECTION_HUNG, pThisExtObj)) {
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = BytesLeft;
|
|
dwRawDataDwords[dwDataIndex++] =
|
|
(DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_WARNING_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_COLLECTION_HUNG, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(DWORD), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
|
|
pThisExtObj->dwLockoutCount++;
|
|
} else {
|
|
// else it's not open so ignore.
|
|
BytesLeft = 0;
|
|
NumObjectTypes = 0;
|
|
}
|
|
}
|
|
} else {
|
|
Win32Error = ERROR_LOCK_FAILED;
|
|
DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
|
|
TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
|
|
PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
|
|
pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
|
|
NULL));
|
|
}
|
|
|
|
if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
|
|
// increment perf counters
|
|
if (BytesLeft > InitialBytesLeft) {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
|
|
PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
|
|
pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
|
|
BytesLeft, sizeof(DWORD), InitialBytesLeft, sizeof(DWORD),
|
|
NULL));
|
|
if (THROTTLE_PERFDLL(PERFLIB_INVALID_SIZE_RETURNED, pThisExtObj)) {
|
|
// memory error
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)InitialBytesLeft;
|
|
dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_INVALID_SIZE_RETURNED, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
|
|
// disable the dll unless:
|
|
// testing has been disabled.
|
|
// or this is a trusted DLL (which are never disabled)
|
|
// the event log message should be reported in any case since
|
|
// this is a serious error
|
|
//
|
|
if ((!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) &&
|
|
(!(pThisExtObj->dwFlags & PERF_EO_TRUSTED))) {
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
// set error values to correct entries
|
|
BytesLeft = 0;
|
|
NumObjectTypes = 0;
|
|
} else {
|
|
// the buffer seems ok so far, so validate it
|
|
|
|
InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
|
|
pThisExtObj->llElapsedTime +=
|
|
liEndTime.QuadPart - liStartTime.QuadPart;
|
|
|
|
// test all returned buffers for correct alignment
|
|
if ((((ULONG_PTR)BytesLeft & (ULONG_PTR)0x07)) &&
|
|
!(lPerflibConfigFlags & PLCF_NO_ALIGN_ERRORS)) {
|
|
if (((pThisExtObj->dwFlags & PERF_EO_ALIGN_ERR_POSTED) == 0) &&
|
|
THROTTLE_PERFDLL(PERFLIB_BUFFER_ALIGNMENT_ERROR, pThisExtObj)) {
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)lpCallBuffer;
|
|
dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_WARNING_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_BUFFER_ALIGNMENT_ERROR, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
pThisExtObj->dwFlags |= PERF_EO_ALIGN_ERR_POSTED;
|
|
}
|
|
#ifdef _WIN64
|
|
// try and fix up BytesLeft and lpCallBuffer
|
|
BytesLeft = ExtpAlignBuffer(lpBufferBefore,
|
|
(PCHAR*) &lpCallBuffer, (InitialBytesLeft - BytesLeft));
|
|
lpBufferAfter = lpCallBuffer;
|
|
#endif
|
|
}
|
|
|
|
if (bUseSafeBuffer) {
|
|
// a data buffer was returned and
|
|
// the function returned OK so see how things
|
|
// turned out...
|
|
//
|
|
//
|
|
// check for buffer corruption here
|
|
//
|
|
bBufferOK = TRUE; // assume it's ok until a check fails
|
|
//
|
|
if (lDllTestLevel <= EXT_TEST_BASIC) {
|
|
DWORD BytesAvailable;
|
|
//
|
|
// check 1: bytes left should be the same as
|
|
// new data buffer ptr - orig data buffer ptr
|
|
//
|
|
BytesAvailable = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
|
|
if (BytesLeft != BytesAvailable) {
|
|
if (THROTTLE_PERFDLL(PERFLIB_BUFFER_POINTER_MISMATCH, pThisExtObj)) {
|
|
// issue WARNING, that bytes left param is incorrect
|
|
// load data for eventlog message
|
|
// this error is correctable
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = BytesLeft;
|
|
dwRawDataDwords[dwDataIndex++] = BytesAvailable;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_WARNING_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_BUFFER_POINTER_MISMATCH, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(DWORD), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
|
|
TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
|
|
PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
|
|
pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
|
|
BytesLeft, sizeof(DWORD), BytesAvailable, sizeof(DWORD),
|
|
NULL));
|
|
// toss this buffer
|
|
bBufferOK = FALSE;
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
// <<old code>>
|
|
// we'll keep the buffer, since the returned bytes left
|
|
// value is ignored anyway, in order to make the
|
|
// rest of this function work, we'll fix it here
|
|
// BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
|
|
// << end old code >>
|
|
}
|
|
//
|
|
// check 2: buffer after ptr should be < hi Guard page ptr
|
|
//
|
|
if (((LPBYTE)lpBufferAfter > (LPBYTE)lpHiGuardPage) && bBufferOK) {
|
|
// see if they exceeded the allocated memory
|
|
if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
|
|
// this is very serious since they've probably trashed
|
|
// the heap by overwriting the heap sig. block
|
|
// issue ERROR, buffer overrun
|
|
if (THROTTLE_PERFDLL(PERFLIB_HEAP_ERROR, pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] =
|
|
(ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_HEAP_ERROR, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
} else {
|
|
// issue ERROR, buffer overrun
|
|
if (THROTTLE_PERFDLL(PERFLIB_BUFFER_OVERFLOW, pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] =
|
|
(ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_BUFFER_OVERFLOW, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
}
|
|
bBufferOK = FALSE;
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
// since the DLL overran the buffer, the buffer
|
|
// must be too small (no comments about the DLL
|
|
// will be made here) so the status will be
|
|
// changed to ERROR_MORE_DATA and the function
|
|
// will return.
|
|
Win32Error = ERROR_MORE_DATA;
|
|
}
|
|
//
|
|
// check 3: check lo guard page for corruption
|
|
//
|
|
if (bBufferOK) {
|
|
bGuardPageOK = TRUE;
|
|
for (lpCheckPointer = (PUCHAR)lpLowGuardPage;
|
|
lpCheckPointer < (PUCHAR)lpBufferBefore;
|
|
lpCheckPointer++) {
|
|
if (*lpCheckPointer != GUARD_PAGE_CHAR) {
|
|
bGuardPageOK = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (!bGuardPageOK) {
|
|
// issue ERROR, Lo Guard Page corrupted
|
|
if (THROTTLE_PERFDLL(PERFLIB_GUARD_PAGE_VIOLATION, pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
|
|
|
|
}
|
|
bBufferOK = FALSE;
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
}
|
|
//
|
|
// check 4: check hi guard page for corruption
|
|
//
|
|
if (bBufferOK) {
|
|
bGuardPageOK = TRUE;
|
|
for (lpCheckPointer = (PUCHAR)lpHiGuardPage;
|
|
lpCheckPointer < (PUCHAR)lpEndPointer;
|
|
lpCheckPointer++) {
|
|
if (*lpCheckPointer != GUARD_PAGE_CHAR) {
|
|
bGuardPageOK = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (!bGuardPageOK) {
|
|
// issue ERROR, Hi Guard Page corrupted
|
|
if (THROTTLE_PERFDLL(PERFLIB_GUARD_PAGE_VIOLATION, pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
|
|
bBufferOK = FALSE;
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
}
|
|
//
|
|
if ((lDllTestLevel <= EXT_TEST_ALL) && bBufferOK) {
|
|
//
|
|
// Internal consistency checks
|
|
//
|
|
//
|
|
// Check 5: Check object length field values
|
|
//
|
|
// first test to see if this is a foreign
|
|
// computer data block or not
|
|
//
|
|
pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
|
|
if ((pPerfData->Signature[0] == (WCHAR)'P') &&
|
|
(pPerfData->Signature[1] == (WCHAR)'E') &&
|
|
(pPerfData->Signature[2] == (WCHAR)'R') &&
|
|
(pPerfData->Signature[3] == (WCHAR)'F')) {
|
|
// if this is a foreign computer data block, then the
|
|
// first object is after the header
|
|
pObject = (PERF_OBJECT_TYPE *) (
|
|
(LPBYTE)pPerfData + pPerfData->HeaderLength);
|
|
bForeignDataBuffer = TRUE;
|
|
} else {
|
|
// otherwise, if this is just a buffer from
|
|
// an extensible counter, the object starts
|
|
// at the beginning of the buffer
|
|
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
|
|
bForeignDataBuffer = FALSE;
|
|
}
|
|
// go to where the pointers say the end of the
|
|
// buffer is and then see if it's where it
|
|
// should be
|
|
dwObjectBufSize = 0;
|
|
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
|
|
dwObjectBufSize += pObject->TotalByteLength;
|
|
pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
|
|
pObject->TotalByteLength);
|
|
}
|
|
if (((LPBYTE)pObject != (LPBYTE)lpCallBuffer) ||
|
|
(dwObjectBufSize > BytesLeft)) {
|
|
// then a length field is incorrect. This is FATAL
|
|
// since it can corrupt the rest of the buffer
|
|
// and render the buffer unusable.
|
|
if (THROTTLE_PERFDLL(
|
|
PERFLIB_INCORRECT_OBJECT_LENGTH,
|
|
pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_INCORRECT_OBJECT_LENGTH, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
bBufferOK = FALSE;
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
//
|
|
// Test 6: Test Object definitions fields
|
|
//
|
|
if (bBufferOK) {
|
|
// set object pointer
|
|
if (bForeignDataBuffer) {
|
|
pObject = (PERF_OBJECT_TYPE *) (
|
|
(LPBYTE)pPerfData + pPerfData->HeaderLength);
|
|
} else {
|
|
// otherwise, if this is just a buffer from
|
|
// an extensible counter, the object starts
|
|
// at the beginning of the buffer
|
|
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
|
|
}
|
|
|
|
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
|
|
pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
|
|
pObject->DefinitionLength);
|
|
|
|
if (pObject->NumCounters != 0) {
|
|
pCounterDef = (PERF_COUNTER_DEFINITION *)
|
|
((LPBYTE)pObject + pObject->HeaderLength);
|
|
lCtrIndex = 0;
|
|
while (lCtrIndex < pObject->NumCounters) {
|
|
if ((LPBYTE)pCounterDef < (LPBYTE)pNextObject) {
|
|
// still ok so go to next counter
|
|
pCounterDef = (PERF_COUNTER_DEFINITION *)
|
|
((LPBYTE)pCounterDef + pCounterDef->ByteLength);
|
|
lCtrIndex++;
|
|
} else {
|
|
bBufferOK = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if ((LPBYTE)pCounterDef != (LPBYTE)pNextObject) {
|
|
bBufferOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!bBufferOK) {
|
|
break;
|
|
} else {
|
|
pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
|
|
pObject->TotalByteLength);
|
|
}
|
|
}
|
|
|
|
if (!bBufferOK) {
|
|
if (THROTTLE_PERFDLL(
|
|
PERFLIB_INVALID_DEFINITION_BLOCK,
|
|
pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_INVALID_DEFINITION_BLOCK, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
|
|
}
|
|
//
|
|
// Test 7: Test instance field size values
|
|
//
|
|
if (bBufferOK) {
|
|
// set object pointer
|
|
if (bForeignDataBuffer) {
|
|
pObject = (PERF_OBJECT_TYPE *) (
|
|
(LPBYTE)pPerfData + pPerfData->HeaderLength);
|
|
} else {
|
|
// otherwise, if this is just a buffer from
|
|
// an extensible counter, the object starts
|
|
// at the beginning of the buffer
|
|
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
|
|
}
|
|
|
|
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
|
|
pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
|
|
pObject->TotalByteLength);
|
|
|
|
if (pObject->NumInstances != PERF_NO_INSTANCES) {
|
|
pInstance = (PERF_INSTANCE_DEFINITION *)
|
|
((LPBYTE)pObject + pObject->DefinitionLength);
|
|
lInstIndex = 0;
|
|
while (lInstIndex < pObject->NumInstances) {
|
|
PERF_COUNTER_BLOCK *pCounterBlock;
|
|
|
|
pCounterBlock = (PERF_COUNTER_BLOCK *)
|
|
((PCHAR) pInstance + pInstance->ByteLength);
|
|
|
|
pInstance = (PERF_INSTANCE_DEFINITION *)
|
|
((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
|
|
|
|
lInstIndex++;
|
|
}
|
|
if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
|
|
bBufferOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!bBufferOK) {
|
|
break;
|
|
} else {
|
|
pObject = pNextObject;
|
|
}
|
|
}
|
|
|
|
if (!bBufferOK) {
|
|
if (THROTTLE_PERFDLL(
|
|
PERFLIB_INCORRECT_INSTANCE_LENGTH,
|
|
pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_INCORRECT_INSTANCE_LENGTH, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
}
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// if all the tests pass,then copy the data to the
|
|
// original buffer and update the pointers
|
|
if (bBufferOK) {
|
|
RtlMoveMemory (*lppDataDefinition,
|
|
lpBufferBefore,
|
|
BytesLeft); // returned buffer size
|
|
} else {
|
|
NumObjectTypes = 0; // since this buffer was tossed
|
|
BytesLeft = 0; // reset the size value since the buffer wasn't used
|
|
}
|
|
} else {
|
|
// function already copied data to caller's buffer
|
|
// so no further action is necessary
|
|
}
|
|
*lppDataDefinition = (LPVOID)((LPBYTE)(*lppDataDefinition) + BytesLeft); // update data pointer
|
|
}
|
|
} else {
|
|
if (Win32Error != ERROR_SUCCESS) {
|
|
InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
|
|
}
|
|
if (bUnlockObjData) {
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
}
|
|
|
|
NumObjectTypes = 0; // clear counter
|
|
}// end if function returned successfully
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Win32Error = GetExceptionCode();
|
|
InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
|
|
bException = TRUE;
|
|
|
|
if (bUnlockObjData) {
|
|
ReleaseMutex (pThisExtObj->hMutex);
|
|
bUnlockObjData = FALSE;
|
|
}
|
|
|
|
if (hPerflibFuncTimer != NULL) {
|
|
// kill timer
|
|
KillPerflibFunctionTimer (hPerflibFuncTimer);
|
|
hPerflibFuncTimer = NULL;
|
|
}
|
|
}
|
|
|
|
if (bUseSafeBuffer) {
|
|
FREEMEM (lpExtDataBuffer);
|
|
}
|
|
} else {
|
|
// unable to allocate memory so set error value
|
|
Win32Error = ERROR_OUTOFMEMORY;
|
|
} // end if temp buffer allocated successfully
|
|
//
|
|
// Update the count of the number of object types
|
|
//
|
|
((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
|
|
|
|
if ( Win32Error != ERROR_SUCCESS) {
|
|
if (bException ||
|
|
!((Win32Error == ERROR_MORE_DATA) ||
|
|
(Win32Error == WAIT_TIMEOUT))) {
|
|
// inform on exceptions & illegal error status only
|
|
if (THROTTLE_PERFDLL(PERFLIB_COLLECT_PROC_EXCEPTION, pThisExtObj)) {
|
|
// load data for eventlog message
|
|
dwDataIndex = wStringIndex = 0;
|
|
dwRawDataDwords[dwDataIndex++] = Win32Error;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szServiceName;
|
|
szMessageArray[wStringIndex++] =
|
|
pThisExtObj->szLibraryName;
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE, // error type
|
|
0, // category (not used)
|
|
(DWORD)PERFLIB_COLLECT_PROC_EXCEPTION, // event,
|
|
NULL, // SID (not used),
|
|
wStringIndex, // number of strings
|
|
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
|
|
szMessageArray, // message text array
|
|
(LPVOID)&dwRawDataDwords[0]); // raw data
|
|
|
|
} else {
|
|
if (bException) {
|
|
DebugPrint((0, "Extensible Counter %d generated an exception code: 0x%8.8x (%dL)\n",
|
|
NumObjectTypes, Win32Error, Win32Error));
|
|
} else {
|
|
DebugPrint((0, "Extensible Counter %d returned error code: 0x%8.8x (%dL)\n",
|
|
NumObjectTypes, Win32Error, Win32Error));
|
|
}
|
|
}
|
|
if (bException) {
|
|
DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
|
|
}
|
|
}
|
|
// the ext. dll is only supposed to return:
|
|
// ERROR_SUCCESS even if it encountered a problem, OR
|
|
// ERROR_MODE_DATA if the buffer was too small.
|
|
// if it's ERROR_MORE_DATA, then break and return the
|
|
// error now, since it'll just be returned again and again.
|
|
if (Win32Error == ERROR_MORE_DATA) {
|
|
lReturnValue = Win32Error;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update perf data in global section
|
|
if (pThisExtObj->pPerfSectionEntry != NULL) {
|
|
pThisExtObj->pPerfSectionEntry->llElapsedTime =
|
|
pThisExtObj->llElapsedTime;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwCollectCount =
|
|
pThisExtObj->dwCollectCount;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwOpenCount =
|
|
pThisExtObj->dwOpenCount;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwCloseCount =
|
|
pThisExtObj->dwCloseCount;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwLockoutCount =
|
|
pThisExtObj->dwLockoutCount;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwErrorCount =
|
|
pThisExtObj->dwErrorCount;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwLastBufferSize =
|
|
pThisExtObj->dwLastBufferSize;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwMaxBufferSize =
|
|
pThisExtObj->dwMaxBufferSize;
|
|
|
|
pThisExtObj->pPerfSectionEntry->dwMaxBufferRejected =
|
|
pThisExtObj->dwMaxBufferRejected;
|
|
|
|
} else {
|
|
// no data section was initialized so skip
|
|
}
|
|
} // end if this object is to be called
|
|
} // end for each object
|
|
} // else an error occurred so unable to call functions
|
|
Win32Error = DeRegisterExtObjListAccess();
|
|
} // else unable to access ext object list
|
|
|
|
HEAP_PROBE();
|
|
|
|
if (bDisabled) lReturnValue = ERROR_SERVICE_DISABLED;
|
|
return lReturnValue;
|
|
}
|