Leaked source code of windows server 2003
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.

990 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perfsprc.c
  5. Abstract:
  6. Author:
  7. Bob Watson (a-robw) Aug 95
  8. Revision History:
  9. --*/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <wchar.h>
  15. #include <winperf.h>
  16. #include <ntprfctr.h>
  17. #define PERF_HEAP hLibHeap
  18. #include <perfutil.h>
  19. #include "perfsprc.h"
  20. #include "procmsg.h"
  21. #include "dataheap.h"
  22. // bit field definitions for collect function flags
  23. #define POS_READ_SYS_PROCESS_DATA ((DWORD)0x00010000)
  24. #define POS_READ_PROCESS_VM_DATA ((DWORD)0x00020000)
  25. #define POS_READ_JOB_OBJECT_DATA ((DWORD)0x00040000)
  26. #define POS_READ_JOB_DETAIL_DATA ((DWORD)0x00080000)
  27. #define POS_READ_HEAP_DATA ((DWORD)0x00100000)
  28. #define POS_COLLECT_PROCESS_DATA ((DWORD)0x00010001)
  29. #define POS_COLLECT_THREAD_DATA ((DWORD)0x00010003)
  30. #define POS_COLLECT_EXPROCESS_DATA ((DWORD)0x00030004)
  31. #define POS_COLLECT_IMAGE_DATA ((DWORD)0x0003000C)
  32. #define POS_COLLECT_LONG_IMAGE_DATA ((DWORD)0x00030014)
  33. #define POS_COLLECT_THREAD_DETAILS_DATA ((DWORD)0x00030024)
  34. #define POS_COLLECT_JOB_OBJECT_DATA ((DWORD)0x00050040)
  35. #define POS_COLLECT_JOB_DETAIL_DATA ((DWORD)0x000D00C1)
  36. #define POS_COLLECT_HEAP_DATA ((DWORD)0x00110101)
  37. #define POS_COLLECT_FUNCTION_MASK ((DWORD)0x000001FF)
  38. #define POS_COLLECT_GLOBAL_DATA ((DWORD)0x001501C3)
  39. #define POS_COLLECT_GLOBAL_NO_HEAP ((DWORD)0x000500C3)
  40. #define POS_COLLECT_FOREIGN_DATA ((DWORD)0)
  41. #define POS_COLLECT_COSTLY_DATA ((DWORD)0x0003003C)
  42. // global variables to this DLL
  43. HANDLE hEventLog = NULL;
  44. LPWSTR wszTotal = NULL;
  45. HANDLE hLibHeap = NULL;
  46. LPBYTE pProcessBuffer = NULL;
  47. PPROCESS_VA_INFO pProcessVaInfo = NULL;
  48. PUNICODE_STRING pusLocalProcessNameBuffer = NULL;
  49. LARGE_INTEGER PerfTime = {0,0};
  50. const WCHAR IDLE_PROCESS[] = L"Idle";
  51. const WCHAR SYSTEM_PROCESS[] = L"System";
  52. const WCHAR szPerflibSubKey[] = L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  53. const WCHAR szPerfProcSubKey[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\PerfProc\\Performance";
  54. const WCHAR szDisplayHeapPerfObject[] = L"DisplayHeapPerfObject";
  55. const WCHAR szProcessNameFormat[] = L"ProcessNameFormat";
  56. const WCHAR szThreadNameFormat[] = L"ThreadNameFormat";
  57. const WCHAR szExe[] = L".EXE";
  58. BOOL PerfSprc_DisplayHeapPerfObject = FALSE;
  59. DWORD PerfSprc_dwProcessNameFormat = NAME_FORMAT_DEFAULT;
  60. DWORD PerfSprc_dwThreadNameFormat = NAME_FORMAT_DEFAULT;
  61. extern DWORD bOpenJobErrorLogged;
  62. // variables local to this module
  63. POS_FUNCTION_INFO posDataFuncInfo[] = {
  64. {PROCESS_OBJECT_TITLE_INDEX, POS_COLLECT_PROCESS_DATA, 0, CollectProcessObjectData},
  65. {THREAD_OBJECT_TITLE_INDEX, POS_COLLECT_THREAD_DATA, 0, CollectThreadObjectData},
  66. {EXPROCESS_OBJECT_TITLE_INDEX, POS_COLLECT_EXPROCESS_DATA, 0, CollectExProcessObjectData},
  67. {IMAGE_OBJECT_TITLE_INDEX, POS_COLLECT_IMAGE_DATA, 0, CollectImageObjectData},
  68. {LONG_IMAGE_OBJECT_TITLE_INDEX, POS_COLLECT_LONG_IMAGE_DATA,0, CollectLongImageObjectData},
  69. {THREAD_DETAILS_OBJECT_TITLE_INDEX, POS_COLLECT_THREAD_DETAILS_DATA, 0, CollectThreadDetailsObjectData},
  70. {JOB_OBJECT_TITLE_INDEX, POS_COLLECT_JOB_OBJECT_DATA, 0, CollectJobObjectData},
  71. {JOB_DETAILS_OBJECT_TITLE_INDEX, POS_COLLECT_JOB_DETAIL_DATA, 0, CollectJobDetailData},
  72. {HEAP_OBJECT_TITLE_INDEX, POS_COLLECT_HEAP_DATA, 0, CollectHeapObjectData}
  73. };
  74. #define POS_NUM_FUNCS (sizeof(posDataFuncInfo) / sizeof(posDataFuncInfo[1]))
  75. BOOL bInitOk = FALSE;
  76. DWORD dwOpenCount = 0;
  77. DWORD ProcessBufSize = LARGE_BUFFER_SIZE;
  78. PM_OPEN_PROC OpenSysProcessObject;
  79. PM_COLLECT_PROC CollecSysProcessObjectData;
  80. PM_CLOSE_PROC CloseSysProcessObject;
  81. __inline
  82. VOID
  83. PerfpQuerySystemTime(
  84. IN PLARGE_INTEGER SystemTime
  85. )
  86. {
  87. do {
  88. SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time;
  89. SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart;
  90. } while (SystemTime->HighPart != USER_SHARED_DATA->SystemTime.High2Time);
  91. }
  92. VOID
  93. PerfProcGlobalSettings (
  94. VOID
  95. )
  96. {
  97. NTSTATUS Status;
  98. HANDLE hPerfProcKey;
  99. OBJECT_ATTRIBUTES oaPerfProcKey;
  100. UNICODE_STRING PerfProcSubKeyString;
  101. UNICODE_STRING NameInfoValueString;
  102. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
  103. DWORD dwBufLen;
  104. DWORD dwRetBufLen;
  105. PDWORD pdwValue;
  106. PerfpQuerySystemTime(&PerfTime);
  107. RtlInitUnicodeString (
  108. &PerfProcSubKeyString,
  109. szPerfProcSubKey);
  110. InitializeObjectAttributes(
  111. &oaPerfProcKey,
  112. &PerfProcSubKeyString,
  113. OBJ_CASE_INSENSITIVE,
  114. NULL,
  115. NULL
  116. );
  117. Status = NtOpenKey(
  118. &hPerfProcKey,
  119. MAXIMUM_ALLOWED,
  120. &oaPerfProcKey
  121. );
  122. if (NT_SUCCESS (Status)) {
  123. // registry key opened, now read value.
  124. // allocate enough room for the structure, - the last
  125. // UCHAR in the struct, but + the data buffer (a dword)
  126. dwBufLen = sizeof(KEY_VALUE_PARTIAL_INFORMATION) -
  127. sizeof(UCHAR) + sizeof (DWORD);
  128. pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ALLOCMEM (dwBufLen);
  129. if (pKeyInfo != NULL) {
  130. // initialize value name string
  131. RtlInitUnicodeString (
  132. &NameInfoValueString,
  133. szDisplayHeapPerfObject);
  134. dwRetBufLen = 0;
  135. Status = NtQueryValueKey (
  136. hPerfProcKey,
  137. &NameInfoValueString,
  138. KeyValuePartialInformation,
  139. (PVOID)pKeyInfo,
  140. dwBufLen,
  141. &dwRetBufLen);
  142. if (NT_SUCCESS(Status)) {
  143. // check value of return data buffer
  144. pdwValue = (PDWORD)&pKeyInfo->Data[0];
  145. if (*pdwValue == 1) {
  146. PerfSprc_DisplayHeapPerfObject = TRUE;
  147. } else {
  148. // all other values will cause this routine to return
  149. // the default value of FALSE
  150. }
  151. }
  152. RtlInitUnicodeString(
  153. &NameInfoValueString,
  154. szProcessNameFormat);
  155. dwRetBufLen = 0;
  156. Status = NtQueryValueKey(
  157. hPerfProcKey,
  158. &NameInfoValueString,
  159. KeyValuePartialInformation,
  160. (PVOID)pKeyInfo,
  161. dwBufLen,
  162. &dwRetBufLen);
  163. if (NT_SUCCESS(Status)) {
  164. pdwValue = (PDWORD) &pKeyInfo->Data[0];
  165. PerfSprc_dwProcessNameFormat = *pdwValue;
  166. }
  167. RtlInitUnicodeString(
  168. &NameInfoValueString,
  169. szThreadNameFormat);
  170. dwRetBufLen = 0;
  171. Status = NtQueryValueKey(
  172. hPerfProcKey,
  173. &NameInfoValueString,
  174. KeyValuePartialInformation,
  175. (PVOID)pKeyInfo,
  176. dwBufLen,
  177. &dwRetBufLen);
  178. if (NT_SUCCESS(Status)) {
  179. pdwValue = (PDWORD) &pKeyInfo->Data[0];
  180. PerfSprc_dwThreadNameFormat = *pdwValue;
  181. }
  182. FREEMEM (pKeyInfo);
  183. }
  184. // close handle
  185. NtClose (hPerfProcKey);
  186. }
  187. if ((PerfSprc_dwProcessNameFormat < NAME_FORMAT_BLANK) ||
  188. (PerfSprc_dwProcessNameFormat > NAME_FORMAT_ID))
  189. PerfSprc_dwProcessNameFormat = NAME_FORMAT_DEFAULT;
  190. if ((PerfSprc_dwThreadNameFormat < NAME_FORMAT_BLANK) ||
  191. (PerfSprc_dwThreadNameFormat > NAME_FORMAT_ID))
  192. PerfSprc_dwThreadNameFormat = NAME_FORMAT_DEFAULT;
  193. }
  194. BOOL
  195. DllProcessAttach (
  196. IN HANDLE DllHandle
  197. )
  198. /*++
  199. Description:
  200. perform any initialization function that apply to all object
  201. modules
  202. --*/
  203. {
  204. BOOL bReturn = TRUE;
  205. WCHAR wszTempBuffer[MAX_PATH];
  206. LONG lStatus;
  207. DWORD dwBufferSize;
  208. UNREFERENCED_PARAMETER (DllHandle);
  209. // open handle to the event log
  210. if (hEventLog == NULL) {
  211. hEventLog = MonOpenEventLog((LPWSTR)L"PerfProc");
  212. // create the local heap
  213. hLibHeap = HeapCreate (0, 1, 0);
  214. if (hLibHeap == NULL) {
  215. return FALSE;
  216. }
  217. }
  218. wszTempBuffer[0] = 0;
  219. wszTempBuffer[MAX_PATH-1] = UNICODE_NULL;
  220. lStatus = GetPerflibKeyValue (
  221. szTotalValue,
  222. REG_SZ,
  223. sizeof(wszTempBuffer) - sizeof(WCHAR),
  224. (LPVOID)&wszTempBuffer[0],
  225. DEFAULT_TOTAL_STRING_LEN,
  226. (LPVOID)&szDefaultTotalString[0]);
  227. if (lStatus == ERROR_SUCCESS) {
  228. // then a string was returned in the temp buffer
  229. dwBufferSize = lstrlenW (wszTempBuffer) + 1;
  230. dwBufferSize *= sizeof (WCHAR);
  231. wszTotal = ALLOCMEM (dwBufferSize);
  232. if (wszTotal == NULL) {
  233. // unable to allocate buffer so use static buffer
  234. wszTotal = (LPWSTR)&szDefaultTotalString[0];
  235. } else {
  236. memcpy (wszTotal, wszTempBuffer, dwBufferSize);
  237. }
  238. } else {
  239. // unable to get string from registry so just use static buffer
  240. wszTotal = (LPWSTR)&szDefaultTotalString[0];
  241. }
  242. return bReturn;
  243. }
  244. BOOL
  245. DllProcessDetach (
  246. IN HANDLE DllHandle
  247. )
  248. {
  249. UNREFERENCED_PARAMETER (DllHandle);
  250. if (dwOpenCount > 0) {
  251. // the Library is being unloaded before it was
  252. // closed so close it now as this is the last
  253. // chance to do it before the library is tossed.
  254. // if the value of dwOpenCount is > 1, set it to
  255. // one to insure everything will be closed when
  256. // the close function is called.
  257. if (dwOpenCount > 1) dwOpenCount = 1;
  258. CloseSysProcessObject();
  259. }
  260. if ((wszTotal != NULL) && (wszTotal != &szDefaultTotalString[0])) {
  261. FREEMEM (wszTotal);
  262. wszTotal = NULL;
  263. }
  264. if (HeapDestroy (hLibHeap)) hLibHeap = NULL;
  265. if (hEventLog != NULL) {
  266. MonCloseEventLog ();
  267. }
  268. return TRUE;
  269. }
  270. BOOL
  271. __stdcall
  272. DllInit(
  273. IN HANDLE DLLHandle,
  274. IN DWORD Reason,
  275. IN LPVOID ReservedAndUnused
  276. )
  277. {
  278. ReservedAndUnused;
  279. // this will prevent the DLL from getting
  280. // the DLL_THREAD_* messages
  281. DisableThreadLibraryCalls (DLLHandle);
  282. switch(Reason) {
  283. case DLL_PROCESS_ATTACH:
  284. return DllProcessAttach (DLLHandle);
  285. case DLL_PROCESS_DETACH:
  286. return DllProcessDetach (DLLHandle);
  287. case DLL_THREAD_ATTACH:
  288. case DLL_THREAD_DETACH:
  289. default:
  290. return TRUE;
  291. }
  292. }
  293. PUNICODE_STRING
  294. GetProcessShortName (
  295. PSYSTEM_PROCESS_INFORMATION pProcess
  296. )
  297. /*++
  298. GetProcessShortName
  299. Inputs:
  300. PSYSTEM_PROCESS_INFORMATION pProcess
  301. address of System Process Information data structure.
  302. Outputs:
  303. None
  304. Returns:
  305. Pointer to an initialized Unicode string (created by this routine)
  306. that contains the short name of the process image or a numeric ID
  307. if no name is found.
  308. If unable to allocate memory for structure, then NULL is returned.
  309. --*/
  310. {
  311. PWCHAR pSlash;
  312. PWCHAR pPeriod;
  313. PWCHAR pThisChar;
  314. WORD wStringSize;
  315. WORD wThisChar;
  316. ULONG ProcessId;
  317. WORD wLength;
  318. // this routine assumes that the allocated memory has been zero'd
  319. if (pusLocalProcessNameBuffer == NULL) {
  320. // allocate Unicode String Structure and adjacent buffer first
  321. wLength = MAX_INSTANCE_NAME * sizeof(WCHAR);
  322. if (pProcess->ImageName.Length > 0) {
  323. if (wLength < pProcess->ImageName.Length) {
  324. wLength = pProcess->ImageName.Length;
  325. }
  326. }
  327. wStringSize = sizeof(UNICODE_STRING) + wLength + 64 + (WORD) sizeof(UNICODE_NULL);
  328. pusLocalProcessNameBuffer =
  329. ALLOCMEM ((DWORD)wStringSize);
  330. if (pusLocalProcessNameBuffer == NULL) {
  331. return NULL;
  332. } else {
  333. pusLocalProcessNameBuffer->MaximumLength = (WORD)(wStringSize - (WORD)sizeof (UNICODE_STRING));
  334. }
  335. }
  336. else if (pusLocalProcessNameBuffer->Buffer == NULL || pusLocalProcessNameBuffer->MaximumLength == 0) {
  337. // something wrong here. Return immediately.
  338. SetLastError(ERROR_INVALID_DATA);
  339. return NULL;
  340. }
  341. else {
  342. wStringSize = pusLocalProcessNameBuffer->MaximumLength;
  343. }
  344. pusLocalProcessNameBuffer->Length = 0;
  345. pusLocalProcessNameBuffer->Buffer = (PWCHAR)&pusLocalProcessNameBuffer[1];
  346. memset ( // buffer must be zero'd so we'll have a NULL Term
  347. pusLocalProcessNameBuffer->Buffer, 0,
  348. (DWORD)pusLocalProcessNameBuffer->MaximumLength);
  349. ProcessId = HandleToUlong(pProcess->UniqueProcessId);
  350. if (pProcess->ImageName.Buffer) { // some name has been defined
  351. pSlash = (PWCHAR)pProcess->ImageName.Buffer;
  352. pPeriod = (PWCHAR)pProcess->ImageName.Buffer;
  353. pThisChar = (PWCHAR)pProcess->ImageName.Buffer;
  354. wThisChar = 0;
  355. //
  356. // go from beginning to end and find last backslash and
  357. // last period in name
  358. //
  359. while (*pThisChar != 0) { // go until null
  360. if (*pThisChar == L'\\') {
  361. pSlash = pThisChar;
  362. } else if (*pThisChar == L'.') {
  363. pPeriod = pThisChar;
  364. }
  365. pThisChar++; // point to next char
  366. wThisChar += sizeof(WCHAR);
  367. if (wThisChar >= pProcess->ImageName.Length) {
  368. break;
  369. }
  370. }
  371. // if pPeriod is still pointing to the beginning of the
  372. // string, then no period was found
  373. if (pPeriod == (PWCHAR)pProcess->ImageName.Buffer) {
  374. pPeriod = pThisChar; // set to end of string;
  375. } else {
  376. // if a period was found, then see if the extension is
  377. // .EXE, if so leave it, if not, then use end of string
  378. // (i.e. include extension in name)
  379. if (lstrcmpiW(pPeriod, szExe) != 0) {
  380. pPeriod = pThisChar;
  381. }
  382. }
  383. if (*pSlash == L'\\') { // if pSlash is pointing to a slash, then
  384. pSlash++; // point to character next to slash
  385. }
  386. // copy characters between period (or end of string) and
  387. // slash (or start of string) to make image name
  388. wStringSize = (WORD)((PCHAR)pPeriod - (PCHAR)pSlash); // size in bytes
  389. wLength = pusLocalProcessNameBuffer->MaximumLength - sizeof(UNICODE_NULL);
  390. if (wStringSize >= wLength) {
  391. wStringSize = wLength;
  392. }
  393. memcpy (pusLocalProcessNameBuffer->Buffer, pSlash, wStringSize);
  394. // null terminate is
  395. // not necessary because allocated memory is zero-init'd
  396. pPeriod = (PWCHAR) ((PCHAR) pusLocalProcessNameBuffer->Buffer + wStringSize);
  397. if (PerfSprc_dwProcessNameFormat == NAME_FORMAT_ID) {
  398. ULONG Length;
  399. Length = PerfIntegerToWString(
  400. ProcessId,
  401. 10,
  402. (pusLocalProcessNameBuffer->MaximumLength - wStringSize)
  403. / sizeof(WCHAR),
  404. pPeriod+1);
  405. if (Length > 0)
  406. *pPeriod = L'_';
  407. wStringSize = wStringSize + (WORD) (Length * sizeof(WCHAR));
  408. }
  409. pusLocalProcessNameBuffer->Length = wStringSize;
  410. } else { // no name defined so use Process #
  411. // check to see if this is a system process and give it
  412. // a name
  413. switch (ProcessId) {
  414. case IDLE_PROCESS_ID:
  415. RtlAppendUnicodeToString (pusLocalProcessNameBuffer,
  416. (LPWSTR)IDLE_PROCESS);
  417. break;
  418. case SYSTEM_PROCESS_ID:
  419. RtlAppendUnicodeToString (pusLocalProcessNameBuffer,
  420. (LPWSTR)SYSTEM_PROCESS);
  421. break;
  422. // if the id is not a system process, then use the id as the name
  423. default:
  424. if (!NT_SUCCESS(RtlIntegerToUnicodeString (ProcessId,
  425. 10,
  426. pusLocalProcessNameBuffer))) {
  427. pusLocalProcessNameBuffer->Length = 2 * sizeof(WCHAR);
  428. memcpy(pusLocalProcessNameBuffer->Buffer, L"-1",
  429. pusLocalProcessNameBuffer->Length);
  430. pusLocalProcessNameBuffer->Buffer[2] = UNICODE_NULL;
  431. }
  432. break;
  433. }
  434. }
  435. return pusLocalProcessNameBuffer;
  436. }
  437. #pragma warning (disable : 4706)
  438. DWORD
  439. GetSystemProcessData (
  440. )
  441. {
  442. DWORD dwReturnedBufferSize;
  443. NTSTATUS Status;
  444. DWORD WinError;
  445. //
  446. // Get process data from system.
  447. // if bGotProcessInfo is TRUE, that means we have the process
  448. // info. collected earlier when we are checking for costly
  449. // object types.
  450. //
  451. if (pProcessBuffer == NULL) {
  452. // allocate a new block
  453. pProcessBuffer = ALLOCMEM (ProcessBufSize);
  454. if (pProcessBuffer == NULL) {
  455. return ERROR_OUTOFMEMORY;
  456. }
  457. }
  458. PerfpQuerySystemTime(&PerfTime);
  459. while( (Status = NtQuerySystemInformation(
  460. SystemProcessInformation,
  461. pProcessBuffer,
  462. ProcessBufSize,
  463. &dwReturnedBufferSize)) == STATUS_INFO_LENGTH_MISMATCH ) {
  464. // expand buffer & retry
  465. if (ProcessBufSize < dwReturnedBufferSize) {
  466. ProcessBufSize = dwReturnedBufferSize;
  467. }
  468. ProcessBufSize = PAGESIZE_MULTIPLE(ProcessBufSize + INCREMENT_BUFFER_SIZE);
  469. FREEMEM(pProcessBuffer);
  470. if ( !(pProcessBuffer = ALLOCMEM(ProcessBufSize)) ) {
  471. return (ERROR_OUTOFMEMORY);
  472. }
  473. }
  474. if ( !NT_SUCCESS(Status) ) {
  475. // convert to win32 error
  476. WinError = (DWORD)RtlNtStatusToDosError(Status);
  477. }
  478. else {
  479. WinError = ERROR_SUCCESS;
  480. }
  481. return (WinError);
  482. }
  483. #pragma warning (default : 4706)
  484. DWORD APIENTRY
  485. OpenSysProcessObject (
  486. LPWSTR lpDeviceNames
  487. )
  488. /*++
  489. Routine Description:
  490. This routine will initialize the data structures used to pass
  491. data back to the registry
  492. Arguments:
  493. Pointer to object ID of each device to be opened (PerfGen)
  494. Return Value:
  495. None.
  496. --*/
  497. {
  498. UNREFERENCED_PARAMETER (lpDeviceNames);
  499. if (dwOpenCount == 0) {
  500. // clear the job object open error flag
  501. bOpenJobErrorLogged = FALSE;
  502. PerfProcGlobalSettings();
  503. }
  504. dwOpenCount++;
  505. bInitOk = TRUE;
  506. return ERROR_SUCCESS;
  507. }
  508. DWORD APIENTRY
  509. CollectSysProcessObjectData (
  510. IN LPWSTR lpValueName,
  511. IN OUT LPVOID *lppData,
  512. IN OUT LPDWORD lpcbTotalBytes,
  513. IN OUT LPDWORD lpNumObjectTypes
  514. )
  515. /*++
  516. Routine Description:
  517. This routine will return the data for the processor object
  518. Arguments:
  519. IN LPWSTR lpValueName
  520. pointer to a wide character string passed by registry.
  521. IN OUT LPVOID *lppData
  522. IN: pointer to the address of the buffer to receive the completed
  523. PerfDataBlock and subordinate structures. This routine will
  524. append its data to the buffer starting at the point referenced
  525. by *lppData.
  526. OUT: points to the first byte after the data structure added by this
  527. routine. This routine updated the value at lppdata after appending
  528. its data.
  529. IN OUT LPDWORD lpcbTotalBytes
  530. IN: the address of the DWORD that tells the size in bytes of the
  531. buffer referenced by the lppData argument
  532. OUT: the number of bytes added by this routine is writted to the
  533. DWORD pointed to by this argument
  534. IN OUT LPDWORD NumObjectTypes
  535. IN: the address of the DWORD to receive the number of objects added
  536. by this routine
  537. OUT: the number of objects added by this routine is writted to the
  538. DWORD pointed to by this argument
  539. Returns:
  540. 0 if successful, else Win 32 error code of failure
  541. --*/
  542. {
  543. LONG lReturn = ERROR_SUCCESS;
  544. NTSTATUS status;
  545. // build bit mask of functions to call
  546. DWORD dwQueryType;
  547. DWORD FunctionCallMask = 0;
  548. DWORD FunctionIndex;
  549. DWORD dwNumObjectsFromFunction;
  550. DWORD dwOrigBuffSize;
  551. DWORD dwByteSize;
  552. #if DBG
  553. LPVOID lpPrev = NULL;
  554. ULONGLONG llRemain = 0;
  555. #endif
  556. if (!bInitOk) {
  557. ReportEvent (hEventLog,
  558. EVENTLOG_ERROR_TYPE,
  559. 0,
  560. PERFPROC_NOT_OPEN,
  561. NULL,
  562. 0,
  563. 0,
  564. NULL,
  565. NULL);
  566. *lpcbTotalBytes = (DWORD) 0;
  567. *lpNumObjectTypes = (DWORD) 0;
  568. lReturn = ERROR_SUCCESS;
  569. goto COLLECT_BAIL_OUT;
  570. }
  571. dwQueryType = GetQueryType (lpValueName);
  572. switch (dwQueryType) {
  573. case QUERY_ITEMS:
  574. for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
  575. if (IsNumberInUnicodeList (
  576. posDataFuncInfo[FunctionIndex].dwObjectId, lpValueName)) {
  577. FunctionCallMask |=
  578. posDataFuncInfo[FunctionIndex].dwCollectFunctionBit;
  579. }
  580. }
  581. break;
  582. case QUERY_GLOBAL:
  583. // only return the HEAP data in a global query if it's enabled
  584. // if they ask for it specifically, then it's OK
  585. if (PerfSprc_DisplayHeapPerfObject) {
  586. FunctionCallMask = POS_COLLECT_GLOBAL_DATA;
  587. } else {
  588. // filter out the heap perf object
  589. FunctionCallMask = POS_COLLECT_GLOBAL_NO_HEAP;
  590. }
  591. break;
  592. case QUERY_FOREIGN:
  593. FunctionCallMask = POS_COLLECT_FOREIGN_DATA;
  594. break;
  595. case QUERY_COSTLY:
  596. FunctionCallMask = POS_COLLECT_COSTLY_DATA;
  597. break;
  598. default:
  599. FunctionCallMask = POS_COLLECT_COSTLY_DATA;
  600. break;
  601. }
  602. // collect data from system
  603. if (FunctionCallMask & POS_READ_SYS_PROCESS_DATA) {
  604. status = GetSystemProcessData ();
  605. if (!NT_SUCCESS(status)) {
  606. ReportEvent (hEventLog,
  607. EVENTLOG_ERROR_TYPE,
  608. 0,
  609. PERFPROC_UNABLE_QUERY_PROCESS_INFO,
  610. NULL,
  611. 0,
  612. sizeof(DWORD),
  613. NULL,
  614. (LPVOID)&status);
  615. }
  616. } else {
  617. status = ERROR_SUCCESS;
  618. }
  619. // collect data from system
  620. if ((status == ERROR_SUCCESS) &&
  621. (pProcessBuffer != NULL) &&
  622. (FunctionCallMask & POS_READ_PROCESS_VM_DATA)) {
  623. pProcessVaInfo = GetSystemVaData (
  624. (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer);
  625. // call function
  626. if (pProcessVaInfo == NULL) {
  627. ReportEvent (hEventLog,
  628. EVENTLOG_ERROR_TYPE,
  629. 0,
  630. PERFPROC_UNABLE_QUERY_VM_INFO,
  631. NULL,
  632. 0,
  633. sizeof(DWORD),
  634. NULL,
  635. (LPVOID)&status);
  636. // zero buffer
  637. }
  638. } else {
  639. // zero buffer
  640. }
  641. // collect data
  642. *lpNumObjectTypes = 0;
  643. dwOrigBuffSize = dwByteSize = *lpcbTotalBytes;
  644. *lpcbTotalBytes = 0;
  645. // remove query bits
  646. FunctionCallMask &= POS_COLLECT_FUNCTION_MASK;
  647. #if DBG
  648. lpPrev = * lppData;
  649. if (((ULONG_PTR) (* lppData) & 0x00000007) != 0) {
  650. DbgPrint("CollectSysProcessObjectData received misaligned buffer %p\n", lpPrev);
  651. }
  652. #endif
  653. for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
  654. if ((posDataFuncInfo[FunctionIndex].dwCollectFunctionBit & FunctionCallMask) ==
  655. (posDataFuncInfo[FunctionIndex].dwCollectFunctionBit & POS_COLLECT_FUNCTION_MASK)) {
  656. dwNumObjectsFromFunction = 0;
  657. lReturn = (*posDataFuncInfo[FunctionIndex].pCollectFunction) (
  658. lppData,
  659. &dwByteSize,
  660. &dwNumObjectsFromFunction);
  661. #if DBG
  662. llRemain = (ULONGLONG) (((LPBYTE) (* lppData)) - ((LPBYTE) lpPrev));
  663. if ((llRemain & 0x0000000000000007) != 0) {
  664. DbgPrint("CollectSysProcessObjectData function %d returned misaligned buffer size (%p,%p)\n",
  665. FunctionIndex, lpPrev, * lppData);
  666. ASSERT ((llRemain & 0x0000000000000007) == 0);
  667. }
  668. else if (((ULONG_PTR) (* lppData) & 0x00000007) != 0) {
  669. DbgPrint("CollectSysProcessObjectData function %d returned misaligned buffer %X\n",
  670. FunctionIndex, *lppData);
  671. }
  672. lpPrev = * lppData;
  673. #endif
  674. if (lReturn == ERROR_SUCCESS) {
  675. *lpNumObjectTypes += dwNumObjectsFromFunction;
  676. *lpcbTotalBytes += dwByteSize;
  677. dwOrigBuffSize -= dwByteSize;
  678. dwByteSize = dwOrigBuffSize;
  679. } else {
  680. break;
  681. }
  682. }
  683. }
  684. // this list of data must be freed after use
  685. if (pProcessVaInfo != NULL) {
  686. FreeSystemVaData (pProcessVaInfo);
  687. pProcessVaInfo = NULL;
  688. }
  689. // *lppData is updated by each function
  690. // *lpcbTotalBytes is updated after each successful function
  691. // *lpNumObjects is updated after each successful function
  692. COLLECT_BAIL_OUT:
  693. return lReturn;
  694. }
  695. DWORD APIENTRY
  696. CloseSysProcessObject (
  697. )
  698. /*++
  699. Routine Description:
  700. This routine closes the open handles to the Signal Gen counters.
  701. Arguments:
  702. None.
  703. Return Value:
  704. ERROR_SUCCESS
  705. --*/
  706. {
  707. DWORD status = ERROR_SUCCESS;
  708. PVOID buffer;
  709. if (!bInitOk) {
  710. return status;
  711. }
  712. if (--dwOpenCount == 0) {
  713. if (hLibHeap != NULL) {
  714. // close
  715. if (pProcessBuffer != NULL) {
  716. buffer = pProcessBuffer;
  717. pProcessBuffer = NULL;
  718. FREEMEM (buffer);
  719. }
  720. if (pusLocalProcessNameBuffer != NULL) {
  721. buffer = pusLocalProcessNameBuffer;
  722. pusLocalProcessNameBuffer = NULL;
  723. FREEMEM (buffer);
  724. }
  725. }
  726. }
  727. return status;
  728. }
  729. const CHAR PerfpIntegerWChars[] = {L'0', L'1', L'2', L'3', L'4', L'5',
  730. L'6', L'7', L'8', L'9', L'A', L'B',
  731. L'C', L'D', L'E', L'F'};
  732. ULONG
  733. PerfIntegerToWString(
  734. IN ULONG Value,
  735. IN ULONG Base,
  736. IN LONG OutputLength,
  737. OUT LPWSTR String
  738. )
  739. /*++
  740. Routine Description:
  741. Arguments:
  742. Return Value:
  743. --*/
  744. {
  745. WCHAR Result[ 33 ], *s;
  746. ULONG Shift, Mask, Digit, Length;
  747. Mask = 0;
  748. Shift = 0;
  749. switch( Base ) {
  750. case 16: Shift = 4; break;
  751. case 8: Shift = 3; break;
  752. case 2: Shift = 1; break;
  753. case 0: Base = 10;
  754. case 10: Shift = 0; break;
  755. default: Base = 10; Shift = 0; // Default to 10
  756. }
  757. if (Shift != 0) {
  758. Mask = 0xF >> (4 - Shift);
  759. }
  760. s = &Result[ 32 ];
  761. *s = L'\0';
  762. do {
  763. if (Shift != 0) {
  764. Digit = Value & Mask;
  765. Value >>= Shift;
  766. }
  767. else {
  768. Digit = Value % Base;
  769. Value = Value / Base;
  770. }
  771. *--s = PerfpIntegerWChars[ Digit ];
  772. } while (Value != 0);
  773. Length = (ULONG) (&Result[ 32 ] - s);
  774. if (OutputLength < 0) {
  775. OutputLength = -OutputLength;
  776. while ((LONG)Length < OutputLength) {
  777. *--s = L'0';
  778. Length++;
  779. }
  780. }
  781. if ((LONG)Length > OutputLength) {
  782. return( 0 );
  783. }
  784. else {
  785. try {
  786. RtlMoveMemory( String, s, Length*sizeof(WCHAR) );
  787. if ((LONG)Length < OutputLength) {
  788. String[ Length ] = L'\0';
  789. }
  790. }
  791. except( EXCEPTION_EXECUTE_HANDLER ) {
  792. return( 0 );
  793. }
  794. return( Length );
  795. }
  796. }