Source code of Windows XP (NT5)
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.

586 lines
23 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. extlib.c
  5. Abstract:
  6. This file implements all the library routines operating on
  7. extensible performance libraries.
  8. Author:
  9. JeePang
  10. Revision History:
  11. 09/27/2000 - JeePang - Moved from perflib.c
  12. --*/
  13. #define UNICODE
  14. //
  15. // Include files
  16. //
  17. #pragma warning(disable:4306)
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <ntregapi.h>
  22. #include <ntprfctr.h>
  23. #include <windows.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <winperf.h>
  27. #include <rpc.h>
  28. #include "regrpc.h"
  29. #include "ntconreg.h"
  30. #include "prflbmsg.h" // event log messages
  31. #include "perflib.h"
  32. #pragma warning(default:4306)
  33. // default trusted file list
  34. // all files presume to start with "perf"
  35. // static LONGLONG llTrustedNamePrefix = 0x0066007200650050; // "Perf"
  36. #define NAME_PREFIX L"Perf"
  37. DWORD dwTrustedFileNames[] = {
  38. 0x0053004F, // "OS" for PerfOS.dll
  39. 0x0065004E, // "Ne" for PerfNet.dll
  40. 0x00720050, // "Pr" for PerfProc.dll
  41. 0x00690044 // "Di" for PerfDisk.dll
  42. };
  43. CONST DWORD dwTrustedFileNameCount =
  44. sizeof(dwTrustedFileNames) / sizeof (dwTrustedFileNames[0]);
  45. // there must be at least 8 chars in the name to be checked as trusted by
  46. // default trusted file names are at least 8 chars in length
  47. CONST DWORD dwMinTrustedFileNameLen = 6;
  48. BOOL
  49. ServiceIsTrustedByDefault (
  50. LPCWSTR szServiceName
  51. )
  52. {
  53. BOOL bReturn = FALSE;
  54. DWORD dwNameToTest;
  55. DWORD dwIdx;
  56. if (szServiceName != NULL) {
  57. // check for min size
  58. dwIdx = 0;
  59. while ((dwIdx < dwMinTrustedFileNameLen) && (szServiceName[dwIdx] > 0))
  60. dwIdx++;
  61. if (dwIdx == dwMinTrustedFileNameLen) {
  62. // test first 4 bytes to see if they match
  63. if (!wcsncmp(szServiceName, NAME_PREFIX, sizeof(LONGLONG))) {
  64. // then see if the rest is in this list
  65. dwNameToTest = * ((DWORD *)(szServiceName+4));
  66. for (dwIdx = 0; dwIdx < dwTrustedFileNameCount; dwIdx++) {
  67. if (dwNameToTest == dwTrustedFileNames[dwIdx]) {
  68. // match found
  69. bReturn = TRUE;
  70. break;
  71. } else {
  72. // no match so continue
  73. }
  74. }
  75. } else {
  76. // no match so return false
  77. }
  78. } else {
  79. // the name to be checked is too short so it mustn't be
  80. // a trusted one.
  81. }
  82. } else {
  83. // no string so return false
  84. }
  85. return bReturn;
  86. }
  87. DWORD
  88. CloseExtObjectLibrary (
  89. PEXT_OBJECT pObj,
  90. BOOL bCloseNow
  91. )
  92. /*++
  93. CloseExtObjectLibrary
  94. Closes and unloads the specified performance counter library and
  95. deletes all references to the functions.
  96. The unloader is "lazy" in that it waits for the library to be
  97. inactive for a specified time before unloading. This is due to the
  98. fact that Perflib can not ever be certain that no thread will need
  99. this library from one call to the next. In order to prevent "thrashing"
  100. due to constantly loading and unloading of the library, the unloading
  101. is delayed to make sure it's not really needed.
  102. This function expects locked and exclusive access to the object while
  103. it is opening. This must be provided by the calling function.
  104. Arguments:
  105. pObj -- pointer to the object information structure of the
  106. perf object to close
  107. bCloseNow -- the flag to indicate the library should be closed
  108. immediately. This is the result of the calling function
  109. closing the registry key.
  110. --*/
  111. {
  112. DWORD Status = ERROR_SUCCESS;
  113. LONGLONG TimeoutTime;
  114. if (((dwThreadAndLibraryTimeout == 0) ||
  115. (dwThreadAndLibraryTimeout == INFINITE)) && !bCloseNow) {
  116. return Status;
  117. }
  118. if (pObj->hLibrary != NULL) {
  119. // get current time to test timeout
  120. TimeoutTime = GetTimeAsLongLong();
  121. // timeout time is in ms
  122. TimeoutTime -= dwThreadAndLibraryTimeout;
  123. // don't close the library unless the object hasn't been accessed for
  124. // a while or the caller is closing the key
  125. if ((TimeoutTime > pObj->llLastUsedTime) || bCloseNow) {
  126. // don't toss if this library has the "keep" flag set and this
  127. // isn't a "close now" case
  128. if (!bCloseNow && (pObj->dwFlags & PERF_EO_KEEP_RESIDENT)) {
  129. // keep it loaded until the key is closed.
  130. } else {
  131. // then this is the last one to close the library
  132. // free library
  133. try {
  134. // call close function for this DLL
  135. Status = (*pObj->CloseProc)();
  136. } except (EXCEPTION_EXECUTE_HANDLER) {
  137. Status = GetExceptionCode();
  138. TRACE((WINPERF_DBG_TRACE_FATAL),
  139. (&PerflibGuid, __LINE__, PERF_CLOSE_EXTOBJLIB,
  140. ARG_TYPE_STR, Status,
  141. // pObj->szCloseProcName,
  142. // STRSIZE(pObj->szCloseProcName), NULL));
  143. TRACE_STR(pObj->szCloseProcName), NULL));
  144. }
  145. FreeLibrary (pObj->hLibrary);
  146. pObj->hLibrary = NULL;
  147. // clear all pointers that are now invalid
  148. pObj->OpenProc = NULL;
  149. pObj->CollectProc = NULL;
  150. pObj->QueryProc = NULL;
  151. pObj->CloseProc = NULL;
  152. InterlockedIncrement((LONG *)&pObj->dwCloseCount);
  153. pObj->llLastUsedTime = 0;
  154. }
  155. }
  156. Status = ERROR_SUCCESS;
  157. } else {
  158. // already closed
  159. Status = ERROR_SUCCESS;
  160. }
  161. return Status;
  162. }
  163. DWORD
  164. OpenExtObjectLibrary (
  165. PEXT_OBJECT pObj
  166. )
  167. /*++
  168. OpenExtObjectLibrary
  169. Opens the specified library and looks up the functions used by
  170. the performance library. If the library is successfully
  171. loaded and opened then the open procedure is called to initialize
  172. the object.
  173. This function expects locked and exclusive access to the object while
  174. it is opening. This must be provided by the calling function.
  175. Arguments:
  176. pObj -- pointer to the object information structure of the
  177. perf object to close
  178. --*/
  179. {
  180. DWORD FnStatus = ERROR_SUCCESS;
  181. DWORD Status = ERROR_SUCCESS;
  182. DWORD dwOpenEvent = 0;
  183. DWORD dwType;
  184. DWORD dwSize;
  185. DWORD dwValue;
  186. // variables used for event logging
  187. DWORD dwDataIndex;
  188. WORD wStringIndex;
  189. ULONG_PTR dwRawDataDwords[8];
  190. LPWSTR szMessageArray[8];
  191. HANDLE hPerflibFuncTimer = NULL;
  192. DLL_VALIDATION_DATA CurrentDllData;
  193. OPEN_PROC_WAIT_INFO opwInfo;
  194. UINT nErrorMode;
  195. LPWSTR szServiceName;
  196. DWORD szServiceNameSize;
  197. BOOL bUseTimer;
  198. // check to see if the library has already been opened
  199. if (pObj->dwFlags & PERF_EO_DISABLED) return ERROR_SERVICE_DISABLED;
  200. if (pObj->hLibrary == NULL) {
  201. // library isn't loaded yet, so
  202. // check to see if this function is enabled
  203. dwType = 0;
  204. dwSize = sizeof (dwValue);
  205. dwValue = 0;
  206. Status = PrivateRegQueryValueExW (
  207. pObj->hPerfKey,
  208. DisablePerformanceCounters,
  209. NULL,
  210. &dwType,
  211. (LPBYTE)&dwValue,
  212. &dwSize);
  213. if ((Status == ERROR_SUCCESS) &&
  214. (dwType == REG_DWORD) &&
  215. (dwValue == 1)) {
  216. // then DON'T Load this library
  217. pObj->dwFlags |= PERF_EO_DISABLED;
  218. } else {
  219. // set the error status & the flag value
  220. Status = ERROR_SUCCESS;
  221. pObj->dwFlags &= ~PERF_EO_DISABLED;
  222. }
  223. szServiceName = pObj->szServiceName;
  224. if (szServiceName == NULL) {
  225. szServiceName = (LPWSTR) &NULL_STRING[0];
  226. }
  227. szServiceNameSize = WSTRSIZE(szServiceName);
  228. if ((Status == ERROR_SUCCESS) &&
  229. (pObj->LibData.FileSize > 0)) {
  230. if (ServiceIsTrustedByDefault(pObj->szServiceName)) {
  231. // then set as trusted and continue
  232. pObj->dwFlags |= PERF_EO_TRUSTED;
  233. } else {
  234. // see if this is a trusted file or a file that has been updated
  235. // get the file information
  236. memset (&CurrentDllData, 0, sizeof(CurrentDllData));
  237. Status = GetPerfDllFileInfo (
  238. pObj->szLibraryName,
  239. &CurrentDllData);
  240. if (Status == ERROR_SUCCESS) {
  241. // compare file data to registry data and update flags
  242. if ((*(LONGLONG *)&pObj->LibData.CreationDate) ==
  243. (*(LONGLONG *)&CurrentDllData.CreationDate) &&
  244. (pObj->LibData.FileSize == CurrentDllData.FileSize)) {
  245. pObj->dwFlags |= PERF_EO_TRUSTED;
  246. } else if (lEventLogLevel >= LOG_USER) {
  247. TRACE((WINPERF_DBG_TRACE_WARNING),
  248. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  249. ARG_TYPE_WSTR, 0, szServiceName,
  250. szServiceNameSize, NULL));
  251. // load data for eventlog message
  252. dwDataIndex = wStringIndex = 0;
  253. szMessageArray[wStringIndex++] =
  254. pObj->szLibraryName;
  255. szMessageArray[wStringIndex++] =
  256. pObj->szServiceName;
  257. ReportEvent (hEventLog,
  258. EVENTLOG_WARNING_TYPE, // error type
  259. 0, // category (not used)
  260. (DWORD)PERFLIB_NOT_TRUSTED_FILE, // event,
  261. NULL, // SID (not used),
  262. wStringIndex, // number of strings
  263. 0, // sizeof raw data
  264. szMessageArray, // message text array
  265. NULL); // raw data
  266. }
  267. }
  268. }
  269. }
  270. if ((Status == ERROR_SUCCESS) && (!(pObj->dwFlags & PERF_EO_DISABLED))) {
  271. // go ahead and load it
  272. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  273. // then load library & look up functions
  274. pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
  275. NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  276. if (pObj->hLibrary != NULL) {
  277. // lookup function names
  278. pObj->OpenProc = (OPENPROC)GetProcAddress(
  279. pObj->hLibrary, pObj->szOpenProcName);
  280. if (pObj->OpenProc == NULL) {
  281. TRACE((WINPERF_DBG_TRACE_FATAL),
  282. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  283. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
  284. 0, szServiceName, szServiceNameSize,
  285. TRACE_STR(pObj->szOpenProcName), NULL));
  286. if (lEventLogLevel >= LOG_USER) {
  287. WCHAR wszProcName[MAX_PATH+1];
  288. Status = GetLastError();
  289. // load data for eventlog message
  290. dwDataIndex = wStringIndex = 0;
  291. dwRawDataDwords[dwDataIndex++] =
  292. (ULONG_PTR)Status;
  293. wcstombs(pObj->szOpenProcName, wszProcName, MAX_PATH);
  294. szMessageArray[wStringIndex++] = &wszProcName[0];
  295. szMessageArray[wStringIndex++] =
  296. pObj->szLibraryName;
  297. szMessageArray[wStringIndex++] =
  298. pObj->szServiceName;
  299. ReportEvent (hEventLog,
  300. EVENTLOG_ERROR_TYPE, // error type
  301. 0, // category (not used)
  302. (DWORD)PERFLIB_OPEN_PROC_NOT_FOUND, // event,
  303. NULL, // SID (not used),
  304. wStringIndex, // number of strings
  305. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  306. szMessageArray, // message text array
  307. (LPVOID)&dwRawDataDwords[0]); // raw data
  308. }
  309. DisablePerfLibrary (pObj);
  310. }
  311. if (Status == ERROR_SUCCESS) {
  312. if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
  313. pObj->QueryProc = (QUERYPROC)GetProcAddress (
  314. pObj->hLibrary, pObj->szCollectProcName);
  315. pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
  316. } else {
  317. pObj->CollectProc = (COLLECTPROC)GetProcAddress (
  318. pObj->hLibrary, pObj->szCollectProcName);
  319. pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
  320. }
  321. if (pObj->CollectProc == NULL) {
  322. TRACE((WINPERF_DBG_TRACE_FATAL),
  323. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  324. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
  325. 0, szServiceName, szServiceNameSize,
  326. TRACE_STR(pObj->szCollectProcName), NULL));
  327. if (lEventLogLevel >= LOG_USER) {
  328. WCHAR wszProcName[MAX_PATH+1];
  329. Status = GetLastError();
  330. // load data for eventlog message
  331. dwDataIndex = wStringIndex = 0;
  332. dwRawDataDwords[dwDataIndex++] =
  333. (ULONG_PTR)Status;
  334. wcstombs(pObj->szCollectProcName,
  335. wszProcName, MAX_PATH);
  336. szMessageArray[wStringIndex++] = &wszProcName[0];
  337. szMessageArray[wStringIndex++] =
  338. pObj->szLibraryName;
  339. szMessageArray[wStringIndex++] =
  340. pObj->szServiceName;
  341. ReportEvent (hEventLog,
  342. EVENTLOG_ERROR_TYPE, // error type
  343. 0, // category (not used)
  344. (DWORD)PERFLIB_COLLECT_PROC_NOT_FOUND, // event,
  345. NULL, // SID (not used),
  346. wStringIndex, // number of strings
  347. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  348. szMessageArray, // message text array
  349. (LPVOID)&dwRawDataDwords[0]); // raw data
  350. }
  351. DisablePerfLibrary (pObj);
  352. }
  353. }
  354. if (Status == ERROR_SUCCESS) {
  355. pObj->CloseProc = (CLOSEPROC)GetProcAddress (
  356. pObj->hLibrary, pObj->szCloseProcName);
  357. if (pObj->CloseProc == NULL) {
  358. TRACE((WINPERF_DBG_TRACE_FATAL),
  359. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  360. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
  361. 0, szServiceName, szServiceNameSize,
  362. TRACE_STR(pObj->szCloseProcName), NULL));
  363. if (lEventLogLevel >= LOG_USER) {
  364. WCHAR wszProcName[MAX_PATH+1];
  365. Status = GetLastError();
  366. // load data for eventlog message
  367. dwDataIndex = wStringIndex = 0;
  368. dwRawDataDwords[dwDataIndex++] =
  369. (ULONG_PTR)Status;
  370. wcstombs(pObj->szCollectProcName,
  371. wszProcName, MAX_PATH);
  372. szMessageArray[wStringIndex++] = &wszProcName[0];
  373. szMessageArray[wStringIndex++] =
  374. pObj->szLibraryName;
  375. szMessageArray[wStringIndex++] =
  376. pObj->szServiceName;
  377. ReportEvent (hEventLog,
  378. EVENTLOG_ERROR_TYPE, // error type
  379. 0, // category (not used)
  380. (DWORD)PERFLIB_CLOSE_PROC_NOT_FOUND, // event,
  381. NULL, // SID (not used),
  382. wStringIndex, // number of strings
  383. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  384. szMessageArray, // message text array
  385. (LPVOID)&dwRawDataDwords[0]); // raw data
  386. }
  387. DisablePerfLibrary (pObj);
  388. }
  389. }
  390. bUseTimer = TRUE; // default
  391. if (!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) {
  392. if (pObj->dwFlags & PERF_EO_TRUSTED) {
  393. bUseTimer = FALSE; // Trusted DLL's are not timed
  394. }
  395. } else {
  396. // disable DLL testing
  397. bUseTimer = FALSE; // Timing is disabled as well
  398. }
  399. if (Status == ERROR_SUCCESS) {
  400. try {
  401. // start timer
  402. opwInfo.pNext = NULL;
  403. opwInfo.szLibraryName = pObj->szLibraryName;
  404. opwInfo.szServiceName = pObj->szServiceName;
  405. opwInfo.dwWaitTime = pObj->dwOpenTimeout;
  406. opwInfo.dwEventMsg = PERFLIB_OPEN_PROC_TIMEOUT;
  407. opwInfo.pData = (LPVOID)pObj;
  408. if (bUseTimer) {
  409. hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
  410. // if no timer, continue anyway, even though things may
  411. // hang, it's better than not loading the DLL since they
  412. // usually load OK
  413. //
  414. if (hPerflibFuncTimer == NULL) {
  415. // unable to get a timer entry
  416. TRACE((WINPERF_DBG_TRACE_WARNING),
  417. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB, 0, 0, NULL));
  418. }
  419. } else {
  420. hPerflibFuncTimer = NULL;
  421. }
  422. // call open procedure to initialize DLL
  423. FnStatus = (*pObj->OpenProc)(pObj->szLinkageString);
  424. // check the result.
  425. if (FnStatus != ERROR_SUCCESS) {
  426. TRACE((WINPERF_DBG_TRACE_FATAL),
  427. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  428. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
  429. FnStatus, szServiceName, szServiceNameSize,
  430. pObj->szLinkageString, (pObj->szLinkageString) ?
  431. WSTRSIZE(pObj->szLinkageString) : 0, NULL));
  432. dwOpenEvent = PERFLIB_OPEN_PROC_FAILURE;
  433. } else {
  434. InterlockedIncrement((LONG *)&pObj->dwOpenCount);
  435. }
  436. } except (EXCEPTION_EXECUTE_HANDLER) {
  437. FnStatus = GetExceptionCode();
  438. TRACE((WINPERF_DBG_TRACE_FATAL),
  439. (&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
  440. ARG_DEF(ARG_TYPE_WSTR, 1), FnStatus,
  441. szServiceName, szServiceNameSize, NULL));
  442. dwOpenEvent = PERFLIB_OPEN_PROC_EXCEPTION;
  443. }
  444. if (hPerflibFuncTimer != NULL) {
  445. // kill timer
  446. Status = KillPerflibFunctionTimer (hPerflibFuncTimer);
  447. hPerflibFuncTimer = NULL;
  448. }
  449. if (FnStatus != ERROR_SUCCESS) {
  450. DWORD ReportError = 1;
  451. if (dwOpenEvent == PERFLIB_OPEN_PROC_EXCEPTION) {
  452. DisablePerfLibrary (pObj);
  453. }
  454. else {
  455. ReportError = PerfUpdateErrorCount(pObj, 1);
  456. }
  457. if ((ReportError > 0) && (lEventLogLevel >= LOG_USER)) {
  458. // load data for eventlog message
  459. dwDataIndex = wStringIndex = 0;
  460. dwRawDataDwords[dwDataIndex++] =
  461. (ULONG_PTR)FnStatus;
  462. szMessageArray[wStringIndex++] =
  463. pObj->szServiceName;
  464. szMessageArray[wStringIndex++] =
  465. pObj->szLibraryName;
  466. ReportEventW (hEventLog,
  467. (WORD)EVENTLOG_ERROR_TYPE, // error type
  468. 0, // category (not used)
  469. dwOpenEvent, // event,
  470. NULL, // SID (not used),
  471. wStringIndex, // number of strings
  472. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  473. szMessageArray, // message text array
  474. (LPVOID)&dwRawDataDwords[0]); // raw data
  475. }
  476. }
  477. else {
  478. PerfUpdateErrorCount(pObj, 0);
  479. }
  480. }
  481. if (FnStatus != ERROR_SUCCESS) {
  482. // clear fields
  483. pObj->OpenProc = NULL;
  484. pObj->CollectProc = NULL;
  485. pObj->QueryProc = NULL;
  486. pObj->CloseProc = NULL;
  487. if (pObj->hLibrary != NULL) {
  488. FreeLibrary (pObj->hLibrary);
  489. pObj->hLibrary = NULL;
  490. }
  491. Status = FnStatus;
  492. } else {
  493. pObj->llLastUsedTime = GetTimeAsLongLong();
  494. }
  495. } else {
  496. Status = GetLastError();
  497. }
  498. SetErrorMode (nErrorMode);
  499. }
  500. } else {
  501. // else already open so bump the ref count
  502. pObj->llLastUsedTime = GetTimeAsLongLong();
  503. }
  504. return Status;
  505. }