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.

2962 lines
89 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. vadump.c
  5. Abstract:
  6. This module contains the routines to dump the virtual address space
  7. of a process.
  8. Author:
  9. Lou Perazzoli (loup) 22-May-1989
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include <assert.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <memory.h>
  18. #include <search.h>
  19. #include <ntos.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <heap.h>
  23. #include <dbghelp.h>
  24. #include "psapi.h"
  25. #define SYM_HANDLE INVALID_HANDLE_VALUE
  26. #define DEFAULT_INCR (64*1024)
  27. #define P2KB(x) (((x) * SystemInfo.dwPageSize) / 1024)
  28. #define MAX_SYMNAME_SIZE 1024
  29. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  30. PIMAGEHLP_SYMBOL ThisSymbol;
  31. ULONG_PTR SystemRangeStart;
  32. LIST_ENTRY VaList;
  33. ULONG_PTR ProcessId;
  34. PCHAR ExeName;
  35. ULONG_PTR IsSystemWithShareCount = 0;
  36. ULONG_PTR PageSize;
  37. ULONG_PTR PtesPerPage;
  38. ULONG_PTR PteWidth;
  39. PVOID PteBase;
  40. PVOID UserPteMax;
  41. ULONG_PTR VaMappedByPageTable;
  42. #define IS_USER_PAGE_TABLE_PAGE(Va) (((PVOID)(Va) >= PteBase) && ((PVOID)(Va) < UserPteMax))
  43. SYSTEM_INFO SystemInfo;
  44. typedef struct _VAINFO {
  45. LIST_ENTRY Links;
  46. LIST_ENTRY AllocationBaseHead;
  47. MEMORY_BASIC_INFORMATION BasicInfo;
  48. } VAINFO, *PVAINFO;
  49. PVAINFO LastAllocationBase;
  50. SIZE_T ReservedBytes;
  51. SIZE_T FreeBytes;
  52. SIZE_T ImageReservedBytes;
  53. SIZE_T ImageFreeBytes;
  54. SIZE_T Displacement;
  55. #define OPTIONS_CODE_TOO 0x1
  56. #define OPTIONS_RAW_SYMBOLS 0x2
  57. #define OPTIONS_VERBOSE 0x4
  58. #define OPTIONS_WORKING_SET 0x8
  59. #define OPTIONS_WORKING_SET_OLD 0x10
  60. #define OPTIONS_PAGE_TABLES 0x20
  61. ULONG Options;
  62. BOOLEAN fSummary = FALSE;
  63. BOOLEAN fFast = FALSE;
  64. BOOLEAN fRunning = FALSE;
  65. #define NOACCESS 0
  66. #define READONLY 1
  67. #define READWRITE 2
  68. #define WRITECOPY 3
  69. #define EXECUTE 4
  70. #define EXECUTEREAD 5
  71. #define EXECUTEREADWRITE 6
  72. #define EXECUTEWRITECOPY 7
  73. #define MAXPROTECT 8
  74. ULONG_PTR ImageCommit[MAXPROTECT];
  75. ULONG_PTR MappedCommit[MAXPROTECT];
  76. ULONG_PTR PrivateCommit[MAXPROTECT];
  77. CHAR LogFileName[256];
  78. FILE *LogFile;
  79. BOOL InCtrlc = FALSE;
  80. typedef struct _WSINFOCOUNTS {
  81. ULONG_PTR FaultingPc;
  82. ULONG Faults;
  83. } WSINFOCOUNTS, *PWSINFOCOUNTS;
  84. typedef struct _MODINFO {
  85. PVOID BaseAddress;
  86. ULONG VirtualSize;
  87. LPSTR Name;
  88. ULONG_PTR CommitVector[MAXPROTECT];
  89. ULONG WsHits;
  90. ULONG WsSharedHits;
  91. ULONG WsPrivateHits;
  92. BOOL SymbolsLoaded;
  93. } MODINFO, *PMODINFO;
  94. #define MODINFO_SIZE 100
  95. ULONG ModInfoMax;
  96. MODINFO ModInfo[MODINFO_SIZE];
  97. BOOLEAN bHitModuleMax = FALSE;
  98. typedef struct _SYSTEM_PAGE {
  99. ULONG_PTR Va;
  100. PVOID BaseAddress;
  101. ULONG ResidentPages;
  102. } SYSTEM_PAGE, *PSYSTEM_PAGE;
  103. //
  104. // room for 4 million pagefaults
  105. //
  106. #define MAX_RUNNING_WORKING_SET_BUFFER (4*1024*1024)
  107. ULONG_PTR RunningWorkingSetBuffer[MAX_RUNNING_WORKING_SET_BUFFER];
  108. LONG CurrentWsIndex;
  109. #define INITIAL_WORKING_SET_BLOCK_ENTRYS 4000
  110. PMEMORY_WORKING_SET_INFORMATION WorkingSetInfo;
  111. #define WORKING_SET_BUFFER_ENTRYS 64*1024
  112. PROCESS_WS_WATCH_INFORMATION NewWorkingSetBuffer[WORKING_SET_BUFFER_ENTRYS];
  113. const PCHAR ProtectTable[] = {
  114. "NoAccess",
  115. "ReadOnly",
  116. "Execute",
  117. "ExecuteRead",
  118. "ReadWrite",
  119. "WriteCopy",
  120. "ExecuteReadWrite",
  121. "ExecuteWriteCopy",
  122. "NoAccess",
  123. "ReadOnly Nocache",
  124. "Execute Nocache",
  125. "ExecuteRead Nocache",
  126. "ReadWrite Nocache",
  127. "WriteCopy Nocache",
  128. "ExecuteReadWrite Nocache",
  129. "ExecuteWriteCopy Nocache",
  130. "NoAccess",
  131. "ReadOnly Guard",
  132. "Execute Guard",
  133. "ExecuteRead Guard",
  134. "ReadWrite Guard",
  135. "WriteCopy Guard",
  136. "ExecuteReadWrite Guard",
  137. "ExecuteWriteCopy Guard",
  138. "NoAccess",
  139. "ReadOnly Nocache Guard",
  140. "Execute Nocache Guard",
  141. "ExecuteRead Nocache Guard",
  142. "ReadWrite Nocache Guard",
  143. "WriteCopy Nocache Guard",
  144. "ExecuteReadWrite Nocache Guard",
  145. "ExecuteWriteCopy Nocache Guard"
  146. };
  147. const PCHAR SharedTable[] = {
  148. " ",
  149. "Shared" };
  150. LIST_ENTRY LoadedHeapList;
  151. int UnknownHeapCount = 0;
  152. typedef struct _LOADED_HEAP_SEGMENT {
  153. PVOID BaseVa;
  154. ULONG Length;
  155. ULONG HitsFromThisSegment;
  156. } LOADED_HEAP_SEGMENT, *PLOADED_HEAP_SEGMENT;
  157. typedef struct _LOADED_HEAP {
  158. LIST_ENTRY HeapsList;
  159. LPSTR HeapName;
  160. ULONG HitsFromThisHeap;
  161. PVOID HeapAddress;
  162. ULONG HeapClass;
  163. LOADED_HEAP_SEGMENT Segments[ HEAP_MAXIMUM_SEGMENTS ];
  164. } LOADED_HEAP, *PLOADED_HEAP;
  165. typedef struct _LOADED_THREAD {
  166. HANDLE ThreadID;
  167. PBYTE ThreadTEB;
  168. PBYTE StackBase;
  169. PBYTE StackEnd;
  170. ULONG HitsFromThisStack;
  171. } LOADED_THREAD, *PLOADED_THREAD;
  172. ULONG NumberOfThreads = 0;
  173. PLOADED_THREAD TheThreads;
  174. LOGICAL
  175. SetCurrentPrivilege(
  176. IN LPCTSTR Privilege, // Privilege to enable/disable
  177. IN OUT BOOL *bEnablePrivilege // to enable or disable privilege
  178. );
  179. VOID
  180. Usage(
  181. VOID
  182. );
  183. void
  184. ConvertAppToOem (
  185. IN unsigned argc,
  186. IN char* argv[]
  187. )
  188. /*++
  189. Routine Description:
  190. Converts the command line from ANSI to OEM, and force the app
  191. to use OEM APIs.
  192. Arguments:
  193. argc - Standard C argument count.
  194. argv - Standard C argument strings.
  195. Return Value:
  196. None.
  197. --*/
  198. {
  199. ULONG i;
  200. LPSTR pSrc;
  201. LPSTR pDst;
  202. WCHAR Wide;
  203. for (i = 0; i < argc; i += 1) {
  204. pSrc = argv[i];
  205. pDst = argv[i];
  206. do {
  207. //
  208. // Convert Ansi to Unicode and then to OEM.
  209. //
  210. MultiByteToWideChar (CP_ACP,
  211. MB_PRECOMPOSED,
  212. pSrc++,
  213. 1,
  214. &Wide,
  215. 1);
  216. WideCharToMultiByte (CP_OEMCP,
  217. 0,
  218. &Wide,
  219. 1,
  220. pDst++,
  221. 1,
  222. "_",
  223. NULL);
  224. } while (*pSrc);
  225. }
  226. SetFileApisToOEM ();
  227. }
  228. BOOLEAN
  229. FindAndIncHeapContainingThisVa (
  230. IN PVOID Va,
  231. IN ULONG ShareCount
  232. )
  233. {
  234. PLIST_ENTRY Next;
  235. PLOADED_HEAP pHeap;
  236. PLOADED_HEAP_SEGMENT Segment;
  237. PLOADED_HEAP_SEGMENT LastSegment;
  238. Next = LoadedHeapList.Flink;
  239. while (Next != &LoadedHeapList) {
  240. pHeap = CONTAINING_RECORD(Next, LOADED_HEAP, HeapsList);
  241. Segment = pHeap->Segments;
  242. LastSegment = Segment + HEAP_MAXIMUM_SEGMENTS;
  243. Next = Next->Flink;
  244. while (Segment < LastSegment) {
  245. if (Segment->BaseVa == NULL) {
  246. break;
  247. }
  248. if ((Va > Segment->BaseVa) &&
  249. (Va < (PVOID)((ULONG_PTR)Segment->BaseVa + Segment->Length))) {
  250. pHeap->HitsFromThisHeap += 1;
  251. Segment->HitsFromThisSegment += 1;
  252. if (ShareCount > 1) {
  253. fprintf(stderr, "Error: Heap ShareCount > 1, 0x%p\n", Va);
  254. }
  255. if (!fSummary) {
  256. printf("0x%p ", Va);
  257. if (IsSystemWithShareCount) {
  258. printf("(%d) ", ShareCount);
  259. }
  260. printf("%s\n", pHeap->HeapName);
  261. }
  262. return TRUE;
  263. }
  264. Segment += 1;
  265. }
  266. }
  267. return FALSE;
  268. }
  269. VOID
  270. DumpLoadedHeap (
  271. IN PLOADED_HEAP LoadedHeap
  272. )
  273. {
  274. PLOADED_HEAP_SEGMENT Segment;
  275. PLOADED_HEAP_SEGMENT LastSegment;
  276. printf ("%4d pages from %s (class 0x%08x)\n",
  277. LoadedHeap->HitsFromThisHeap,
  278. LoadedHeap->HeapName,
  279. LoadedHeap->HeapClass);
  280. Segment = LoadedHeap->Segments;
  281. LastSegment = Segment + HEAP_MAXIMUM_SEGMENTS;
  282. while (Segment < LastSegment) {
  283. if (Segment->BaseVa == NULL) {
  284. break;
  285. }
  286. printf("\t0x%p - 0x%p %d pages\n",
  287. Segment->BaseVa,
  288. (ULONG_PTR)Segment->BaseVa + Segment->Length,
  289. Segment->HitsFromThisSegment);
  290. Segment += 1;
  291. }
  292. }
  293. VOID
  294. LoadTheHeaps (
  295. IN HANDLE Process
  296. )
  297. {
  298. HEAP TheHeap;
  299. PLOADED_HEAP LoadedHeap;
  300. PHEAP *ProcessHeaps;
  301. HEAP_SEGMENT TheSegment;
  302. BOOL b;
  303. ULONG cb, i, j;
  304. NTSTATUS Status;
  305. PROCESS_BASIC_INFORMATION ProcessInformation;
  306. PEB ThePeb;
  307. InitializeListHead (&LoadedHeapList);
  308. Status = NtQueryInformationProcess (Process,
  309. ProcessBasicInformation,
  310. &ProcessInformation,
  311. sizeof( ProcessInformation ),
  312. NULL);
  313. if (!NT_SUCCESS (Status)) {
  314. fprintf(stderr, "NtQueryInformationProcess for ProcessBasicInformation"
  315. " failed %lx\n", GetLastError());
  316. return;
  317. }
  318. //
  319. // Read the process's PEB.
  320. //
  321. b = ReadProcessMemory (Process,
  322. ProcessInformation.PebBaseAddress,
  323. &ThePeb,sizeof(ThePeb),
  324. NULL);
  325. if (!b) {
  326. return;
  327. }
  328. //
  329. // Allocate space for and read the array of process heap pointers.
  330. //
  331. cb = ThePeb.NumberOfHeaps * sizeof( PHEAP );
  332. ProcessHeaps = LocalAlloc(LMEM_ZEROINIT,cb);
  333. if (ProcessHeaps == NULL) {
  334. return;
  335. }
  336. b = ReadProcessMemory (Process,
  337. ThePeb.ProcessHeaps,
  338. ProcessHeaps,
  339. cb,
  340. NULL);
  341. if (b) {
  342. for (i = 0; i < ThePeb.NumberOfHeaps; i += 1) {
  343. //
  344. // Read the heap.
  345. //
  346. b = ReadProcessMemory (Process,
  347. ProcessHeaps[i],
  348. &TheHeap,
  349. sizeof(TheHeap),
  350. NULL);
  351. if (!b) {
  352. break;
  353. }
  354. //
  355. // We got the heap, now initialize our heap structure
  356. //
  357. LoadedHeap = LocalAlloc (LMEM_ZEROINIT, sizeof(*LoadedHeap));
  358. if (!LoadedHeap) {
  359. break;
  360. }
  361. LoadedHeap->HeapAddress = ProcessHeaps[i];
  362. LoadedHeap->HeapClass = TheHeap.Flags & HEAP_CLASS_MASK;
  363. switch ( LoadedHeap->HeapClass ) {
  364. case HEAP_CLASS_0:
  365. LoadedHeap->HeapName = "Process Heap";
  366. break;
  367. case HEAP_CLASS_1:
  368. LoadedHeap->HeapName = HeapAlloc(GetProcessHeap(),
  369. 0,
  370. sizeof("Private Heap ") + 10); // 10digit number is overkill but...
  371. if (LoadedHeap->HeapName) {
  372. sprintf(LoadedHeap->HeapName,
  373. "Private Heap %d",
  374. UnknownHeapCount++);
  375. } else {
  376. LoadedHeap->HeapName = "Private Heap";
  377. }
  378. break;
  379. case HEAP_CLASS_2:
  380. LoadedHeap->HeapName = "Kernel Heap";
  381. break;
  382. case HEAP_CLASS_3:
  383. LoadedHeap->HeapName = "GDI Heap";
  384. break;
  385. case HEAP_CLASS_4:
  386. LoadedHeap->HeapName = "User Heap";
  387. break;
  388. case HEAP_CLASS_5:
  389. LoadedHeap->HeapName = "Console Heap";
  390. break;
  391. case HEAP_CLASS_6:
  392. LoadedHeap->HeapName = "User Desktop Heap";
  393. break;
  394. case HEAP_CLASS_7:
  395. LoadedHeap->HeapName = "Csrss Shared Heap";
  396. break;
  397. default:
  398. LoadedHeap->HeapName = HeapAlloc(GetProcessHeap(),
  399. 0,
  400. sizeof("UNKNOWN Heap ") + 10);
  401. if (LoadedHeap->HeapName) {
  402. sprintf(LoadedHeap->HeapName,
  403. "UNKNOWN Heap %d",
  404. UnknownHeapCount++);
  405. } else {
  406. LoadedHeap->HeapName = "UNKNOWN Heap";
  407. }
  408. break;
  409. }
  410. //
  411. // Now go through the heap segments to compute the
  412. // area covered by the heap.
  413. //
  414. for (j = 0; j < HEAP_MAXIMUM_SEGMENTS; j += 1) {
  415. if (!TheHeap.Segments[j]) {
  416. break;
  417. }
  418. b = ReadProcessMemory (Process,
  419. TheHeap.Segments[j],
  420. &TheSegment,
  421. sizeof(TheSegment),
  422. NULL);
  423. if (!b) {
  424. break;
  425. }
  426. LoadedHeap->Segments[j].BaseVa = TheSegment.BaseAddress;
  427. LoadedHeap->Segments[j].Length = TheSegment.NumberOfPages *
  428. SystemInfo.dwPageSize;
  429. }
  430. InsertTailList (&LoadedHeapList,&LoadedHeap->HeapsList);
  431. }
  432. }
  433. LocalFree (ProcessHeaps);
  434. return;
  435. }
  436. BOOLEAN
  437. FindAndIncStackContainingThisVa (
  438. IN PBYTE Va,
  439. IN ULONG ShareCount
  440. )
  441. {
  442. ULONG i;
  443. for (i = 0 ; i < NumberOfThreads ; i++) {
  444. if ((Va > TheThreads[i].StackBase) &&
  445. (Va < TheThreads[i].StackEnd)) {
  446. TheThreads[i].HitsFromThisStack++;
  447. if (ShareCount > 1) {
  448. fprintf(stderr, "Error: Stack ShareCount > 1, 0x%p\n", Va);
  449. }
  450. if (!fSummary) {
  451. printf("0x%p ", Va);
  452. if (IsSystemWithShareCount) {
  453. printf("(%d) ", ShareCount);
  454. }
  455. printf("Stack for ThreadID %p\n", TheThreads[i].ThreadID);
  456. }
  457. return TRUE;
  458. }
  459. }
  460. return FALSE;
  461. }
  462. VOID
  463. DumpLoadedStacks (
  464. VOID
  465. )
  466. {
  467. ULONG i;
  468. for (i = 0 ; i < NumberOfThreads ; i++) {
  469. printf("%4d pages from stack for thread %p\n",
  470. TheThreads[i].HitsFromThisStack,
  471. TheThreads[i].ThreadID);
  472. }
  473. return;
  474. }
  475. VOID
  476. LoadTheThreads (
  477. IN HANDLE Process,
  478. IN ULONG_PTR ProcessID
  479. )
  480. {
  481. BOOL b;
  482. ULONG i;
  483. NTSTATUS Status;
  484. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  485. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  486. THREAD_BASIC_INFORMATION ThreadBasicInfo;
  487. TEB TheTeb;
  488. HANDLE Thread;
  489. OBJECT_ATTRIBUTES Obja;
  490. //
  491. // To get the thread IDs of the process, load the system process info
  492. // and look for the matching process. For each thread in it, open the
  493. // thread to get the Teb address, then, read the stack information from
  494. // the Teb in the processes memory.
  495. //
  496. Status = NtQuerySystemInformation(
  497. SystemProcessInformation,
  498. &RunningWorkingSetBuffer, // not in use yet for WS
  499. 512*1024, // don't give the whole thing
  500. // or it will be probed
  501. NULL
  502. );
  503. if (!NT_SUCCESS(Status)) {
  504. fprintf(stderr, "NtQuerySystemInformation for SystemProcessInformation"
  505. " failed %lx\n", GetLastError());
  506. return;
  507. }
  508. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &RunningWorkingSetBuffer;
  509. while (ProcessInfo) {
  510. if (ProcessInfo->UniqueProcessId == (HANDLE)ProcessID) {
  511. break;
  512. }
  513. if (ProcessInfo->NextEntryOffset == 0) {
  514. ProcessInfo = NULL;
  515. break;
  516. }
  517. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) ((PBYTE)ProcessInfo +
  518. ProcessInfo->NextEntryOffset);
  519. }
  520. if (ProcessInfo == NULL) {
  521. fprintf(stderr, "Error: Failed to find process for Stack lookup\n");
  522. return;
  523. }
  524. ThreadInfo = (PSYSTEM_THREAD_INFORMATION) (ProcessInfo + 1);
  525. NumberOfThreads = ProcessInfo->NumberOfThreads;
  526. TheThreads = (PLOADED_THREAD) LocalAlloc(LMEM_ZEROINIT,
  527. sizeof(LOADED_THREAD) * NumberOfThreads);
  528. if (TheThreads == NULL) {
  529. printf("FAILURE: Couldn't allocate memory for thread database\n");
  530. ExitProcess(0);
  531. }
  532. InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
  533. for (i = 0; i < NumberOfThreads; i += 1, ThreadInfo += 1) {
  534. Status = NtOpenThread (&Thread,
  535. MAXIMUM_ALLOWED,
  536. &Obja,
  537. &ThreadInfo->ClientId);
  538. if (!NT_SUCCESS( Status )) {
  539. fprintf(stderr, "NtOpenThread %p failed %lx\n",
  540. ThreadInfo->ClientId.UniqueThread,
  541. GetLastError());
  542. return;
  543. }
  544. Status = NtQueryInformationThread (Thread,
  545. ThreadBasicInformation,
  546. &ThreadBasicInfo,
  547. sizeof( ThreadBasicInfo ),
  548. NULL);
  549. if (!NT_SUCCESS( Status )) {
  550. fprintf(stderr, "NtQueryInformationThread for"
  551. " ThreadBasicInformation failed %lx\n",
  552. GetLastError());
  553. CloseHandle (Thread);
  554. return;
  555. }
  556. //
  557. // Read the threads's TEB.
  558. //
  559. b = ReadProcessMemory (Process,
  560. ThreadBasicInfo.TebBaseAddress,
  561. &TheTeb,
  562. sizeof(TheTeb),
  563. NULL);
  564. if (!b) {
  565. fprintf(stderr, "ReadProcessMemory for"
  566. " TEB %d failed %lx\n",
  567. i,
  568. GetLastError());
  569. CloseHandle (Thread);
  570. return;
  571. }
  572. TheThreads[i].ThreadID = TheTeb.ClientId.UniqueThread;
  573. TheThreads[i].ThreadTEB = (PBYTE)ThreadBasicInfo.TebBaseAddress;
  574. TheThreads[i].StackBase = TheTeb.DeallocationStack;
  575. TheThreads[i].StackEnd = TheTeb.NtTib.StackBase;
  576. CloseHandle(Thread);
  577. }
  578. }
  579. PMODINFO
  580. LocateModInfo(
  581. PVOID Address
  582. )
  583. {
  584. ULONG i;
  585. for (i=0;i<ModInfoMax;i++){
  586. if ( Address >= ModInfo[i].BaseAddress &&
  587. Address <= (PVOID)((ULONG_PTR)ModInfo[i].BaseAddress+ModInfo[i].VirtualSize) ) {
  588. return &ModInfo[i];
  589. }
  590. }
  591. return NULL;
  592. }
  593. VOID
  594. CaptureWorkingSet(
  595. HANDLE Process
  596. )
  597. {
  598. ULONG_PTR NumEntries = INITIAL_WORKING_SET_BLOCK_ENTRYS;
  599. BOOLEAN Done;
  600. SIZE_T Size;
  601. DWORD Error;
  602. Done = FALSE;
  603. while (!Done) {
  604. Size = FIELD_OFFSET(MEMORY_WORKING_SET_INFORMATION, WorkingSetInfo) +
  605. NumEntries * sizeof(MEMORY_WORKING_SET_BLOCK);
  606. WorkingSetInfo = HeapAlloc(GetProcessHeap(), 0, Size);
  607. if (WorkingSetInfo == NULL) {
  608. printf("FAILURE Couldn't allocate working set info buffer\n");
  609. exit(0);
  610. }
  611. if (!QueryWorkingSet(Process, WorkingSetInfo, (DWORD) Size)) {
  612. Error = GetLastError();
  613. if (Error != ERROR_BAD_LENGTH) {
  614. printf("FAILURE query working set %lu\n", Error);
  615. exit(0);
  616. }
  617. }
  618. if (WorkingSetInfo->NumberOfEntries > NumEntries) {
  619. //
  620. // Not big enough so increase the number of entries and
  621. // free the old one.
  622. //
  623. NumEntries = WorkingSetInfo->NumberOfEntries + 100; // Add in some fudge for growth
  624. HeapFree(GetProcessHeap(), 0, WorkingSetInfo);
  625. } else {
  626. Done = TRUE;
  627. }
  628. }
  629. }
  630. int
  631. __cdecl
  632. ulcomp(
  633. const void *e1,
  634. const void *e2
  635. )
  636. {
  637. PULONG p1;
  638. PULONG p2;
  639. p1 = (PULONG)e1;
  640. p2 = (PULONG)e2;
  641. if (*p1 > *p2) {
  642. return 1;
  643. }
  644. if (*p1 < *p2) {
  645. return -1;
  646. }
  647. return 0;
  648. }
  649. int
  650. __cdecl
  651. WSBlockComp(
  652. const void *e1,
  653. const void *e2
  654. )
  655. {
  656. PMEMORY_WORKING_SET_BLOCK p1;
  657. PMEMORY_WORKING_SET_BLOCK p2;
  658. p1 = (PMEMORY_WORKING_SET_BLOCK)e1;
  659. p2 = (PMEMORY_WORKING_SET_BLOCK)e2;
  660. if (p1->VirtualPage > p2->VirtualPage) {
  661. return 1;
  662. }
  663. if (p1->VirtualPage < p2->VirtualPage) {
  664. return -1;
  665. }
  666. return 0;
  667. }
  668. int
  669. __cdecl
  670. wsinfocomp(
  671. const void *e1,
  672. const void *e2
  673. )
  674. {
  675. PWSINFOCOUNTS p1;
  676. PWSINFOCOUNTS p2;
  677. p1 = (PWSINFOCOUNTS)e1;
  678. p2 = (PWSINFOCOUNTS)e2;
  679. return (p1->Faults - p2->Faults);
  680. }
  681. BOOL
  682. CtrlcH (
  683. IN DWORD dwCtrlType
  684. )
  685. {
  686. PWSINFOCOUNTS WsInfoCount;
  687. LONG RunIndex;
  688. LONG CountIndex;
  689. IMAGEHLP_MODULE Mi;
  690. ULONG_PTR Offset;
  691. if ( dwCtrlType != CTRL_C_EVENT ) {
  692. return FALSE;
  693. }
  694. if ((Options & (OPTIONS_WORKING_SET | OPTIONS_WORKING_SET_OLD)) == OPTIONS_WORKING_SET) {
  695. ;
  696. }
  697. else {
  698. return FALSE;
  699. }
  700. Mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  701. InCtrlc = TRUE;
  702. //
  703. // Sort the running working set buffer
  704. //
  705. qsort((void *)RunningWorkingSetBuffer,(size_t)CurrentWsIndex,(size_t)sizeof(ULONG),ulcomp);
  706. WsInfoCount = LocalAlloc(LMEM_ZEROINIT,CurrentWsIndex*sizeof(*WsInfoCount));
  707. if ( !WsInfoCount ) {
  708. ExitProcess(0);
  709. }
  710. //
  711. // Sum unique PC values
  712. //
  713. CountIndex = 0;
  714. RunIndex = 0;
  715. WsInfoCount[CountIndex].FaultingPc = RunningWorkingSetBuffer[RunIndex];
  716. WsInfoCount[CountIndex].Faults++;
  717. for(RunIndex = 1; RunIndex < CurrentWsIndex; RunIndex++){
  718. if ( WsInfoCount[CountIndex].FaultingPc == RunningWorkingSetBuffer[RunIndex] ) {
  719. WsInfoCount[CountIndex].Faults++;
  720. }
  721. else {
  722. CountIndex++;
  723. WsInfoCount[CountIndex].FaultingPc = RunningWorkingSetBuffer[RunIndex];
  724. WsInfoCount[CountIndex].Faults++;
  725. }
  726. }
  727. //
  728. // Now sort the counted pc/fault count pairs
  729. //
  730. qsort(WsInfoCount,CountIndex,sizeof(*WsInfoCount),wsinfocomp);
  731. //
  732. // Now print the sorted pc/fault count pairs
  733. //
  734. for ( RunIndex = CountIndex-1; RunIndex >= 0 ; RunIndex-- ) {
  735. if (!SymGetModuleInfo((HANDLE)ProcessId, WsInfoCount[RunIndex].FaultingPc, &Mi )) {
  736. printf("%8d, 0x%p\n",WsInfoCount[RunIndex].Faults,WsInfoCount[RunIndex].FaultingPc);
  737. if ( LogFile ) {
  738. fprintf(LogFile,"%8d, 0x%p\n",WsInfoCount[RunIndex].Faults,WsInfoCount[RunIndex].FaultingPc);
  739. }
  740. } else {
  741. if (SymGetSymFromAddr((HANDLE)ProcessId, WsInfoCount[RunIndex].FaultingPc, &Displacement, ThisSymbol )) {
  742. Offset = (ULONG_PTR)WsInfoCount[RunIndex].FaultingPc - ThisSymbol->Address;
  743. if ( Offset ) {
  744. printf("%8d, %s+%x\n",WsInfoCount[RunIndex].Faults,ThisSymbol->Name,Offset);
  745. if ( LogFile ) {
  746. fprintf(LogFile,"%8d, %s+%x\n",WsInfoCount[RunIndex].Faults,ThisSymbol->Name,Offset);
  747. }
  748. } else {
  749. printf("%8d, %s\n",WsInfoCount[RunIndex].Faults, ThisSymbol->Name);
  750. if ( LogFile ) {
  751. fprintf(LogFile,"%8d, %s\n",WsInfoCount[RunIndex].Faults, ThisSymbol->Name);
  752. }
  753. }
  754. } else {
  755. printf("%8d, 0x%p\n",WsInfoCount[RunIndex].Faults,WsInfoCount[RunIndex].FaultingPc);
  756. if ( LogFile ) {
  757. fprintf(LogFile,"%8d, 0x%p\n",WsInfoCount[RunIndex].Faults,WsInfoCount[RunIndex].FaultingPc);
  758. }
  759. }
  760. }
  761. }
  762. exit(1);
  763. return FALSE;
  764. }
  765. VOID
  766. DumpWorkingSetSnapshot (
  767. IN HANDLE Process
  768. )
  769. {
  770. LOGICAL NewLine;
  771. PSYSTEM_PAGE SystemPageBase;
  772. ULONG i;
  773. ULONG_PTR BaseVa = 0;
  774. ULONG_PTR Va = 0;
  775. ULONG_PTR PteIndex;
  776. ULONG_PTR BaseAddress;
  777. ULONG SystemPages = 0;
  778. ULONG HeapPages = 0;
  779. ULONG StackPages = 0;
  780. ULONG MappedPages = 0;
  781. ULONG SharedMappedPages = 0;
  782. ULONG PrivateMappedPages = 0;
  783. ULONG DataPages = 0;
  784. ULONG SharedDataPages = 0;
  785. ULONG PrivateDataPages = 0;
  786. ULONG ErrorPages = 0;
  787. ULONG QuickPages = 0;
  788. ULONG LpcPages = 0;
  789. ULONG CsrSharedPages = 0;
  790. ULONG SharedCsrSharedPages = 0;
  791. ULONG TebPages = 0;
  792. ULONG TotalStaticCodeData = 0;
  793. ULONG TotalStaticCodeDataShared = 0;
  794. ULONG TotalStaticCodeDataPrivate = 0;
  795. ULONG TotalDynamicData = 0;
  796. ULONG TotalDynamicDataShared = 0;
  797. ULONG TotalDynamicDataPrivate = 0;
  798. ULONG TotalSystem = 0;
  799. ULONG Total, Shareable, Private, Shared;
  800. PMODINFO Mi;
  801. PLOADED_HEAP pHeap;
  802. PLIST_ENTRY Next;
  803. MEMORY_BASIC_INFORMATION BasicInfo;
  804. BOOL b;
  805. ULONG Mstack[7];
  806. WCHAR FileName[MAX_PATH+1];
  807. PWCHAR pwch;
  808. ULONG ShareCount;
  809. BOOLEAN IsShareable;
  810. PMEMORY_WORKING_SET_BLOCK WorkingSetBlock;
  811. PMEMORY_WORKING_SET_BLOCK LastWorkingSetBlock;
  812. ULONG PageTablePageCount;
  813. ULONG PageTablePageMax;
  814. ULONG_PTR SPBase;
  815. ULONG_PTR MIBase;
  816. ULONG_PTR MIEnd;
  817. ULONG_PTR HSBase;
  818. ULONG_PTR HSEnd;
  819. ULONG_PTR SSBase;
  820. ULONG_PTR SSEnd;
  821. NewLine = FALSE;
  822. if (Options & OPTIONS_RAW_SYMBOLS) {
  823. fSummary = FALSE;
  824. }
  825. qsort (&WorkingSetInfo->WorkingSetInfo[0],
  826. WorkingSetInfo->NumberOfEntries,
  827. sizeof(MEMORY_WORKING_SET_BLOCK),
  828. WSBlockComp);
  829. //
  830. // Count the number of user page table page references that faulted.
  831. //
  832. PageTablePageCount = 0;
  833. WorkingSetBlock = &WorkingSetInfo->WorkingSetInfo[0];
  834. LastWorkingSetBlock = WorkingSetBlock + WorkingSetInfo->NumberOfEntries;
  835. while (WorkingSetBlock < LastWorkingSetBlock) {
  836. Va = WorkingSetBlock->VirtualPage << 12;
  837. if (IS_USER_PAGE_TABLE_PAGE(Va)) {
  838. PageTablePageCount += 1;
  839. }
  840. WorkingSetBlock += 1;
  841. }
  842. //
  843. // Allocate memory to hold the user page table page references.
  844. //
  845. SystemPageBase = NULL;
  846. PageTablePageMax = PageTablePageCount;
  847. if (PageTablePageMax != 0) {
  848. SystemPageBase = LocalAlloc (LMEM_ZEROINIT,
  849. PageTablePageMax * sizeof(SYSTEM_PAGE));
  850. if (SystemPageBase == NULL) {
  851. return;
  852. }
  853. }
  854. PageTablePageCount = 0;
  855. WorkingSetBlock = &WorkingSetInfo->WorkingSetInfo[0];
  856. while (WorkingSetBlock < LastWorkingSetBlock) {
  857. Va = WorkingSetBlock->VirtualPage << 12;
  858. IsSystemWithShareCount |= (ULONG_PTR)WorkingSetBlock->ShareCount;
  859. if (IS_USER_PAGE_TABLE_PAGE(Va)) {
  860. SystemPageBase[PageTablePageCount].Va = Va;
  861. PteIndex = (Va - (ULONG_PTR)PteBase) / PteWidth;
  862. BaseAddress = (PteIndex / PtesPerPage) * VaMappedByPageTable;
  863. SystemPageBase[PageTablePageCount].BaseAddress = (PVOID)BaseAddress;
  864. PageTablePageCount += 1;
  865. }
  866. WorkingSetBlock += 1;
  867. }
  868. //
  869. // Attribute each user space page into the system page that backs it.
  870. //
  871. WorkingSetBlock = &WorkingSetInfo->WorkingSetInfo[0];
  872. LastWorkingSetBlock = WorkingSetBlock + WorkingSetInfo->NumberOfEntries;
  873. while (WorkingSetBlock < LastWorkingSetBlock) {
  874. Va = WorkingSetBlock->VirtualPage << 12;
  875. if (Va < SystemRangeStart) {
  876. for (i = 0; i < PageTablePageCount; i += 1) {
  877. if ((Va >= (ULONG_PTR)SystemPageBase[i].BaseAddress) &&
  878. (Va < ((ULONG_PTR)SystemPageBase[i].BaseAddress + VaMappedByPageTable))) {
  879. SystemPageBase[i].ResidentPages += 1;
  880. break;
  881. }
  882. }
  883. }
  884. WorkingSetBlock += 1;
  885. }
  886. WorkingSetBlock = &WorkingSetInfo->WorkingSetInfo[0];
  887. for ( ; WorkingSetBlock < LastWorkingSetBlock; WorkingSetBlock += 1) {
  888. Va = WorkingSetBlock->VirtualPage << 12;
  889. IsShareable = (BOOLEAN) (WorkingSetBlock->Shared == 1);
  890. ShareCount = (ULONG) WorkingSetBlock->ShareCount;
  891. if (Va >= SystemRangeStart) {
  892. if ((!fSummary || (Options & OPTIONS_PAGE_TABLES)) &&
  893. (IS_USER_PAGE_TABLE_PAGE(Va))) {
  894. //
  895. // For each system page, dump the range spanned, number of
  896. // resident pages, and the modules and heaps covered.
  897. //
  898. for (i = 0; Va != SystemPageBase[i].Va; i += 1) {
  899. ;
  900. }
  901. SPBase = (ULONG_PTR) SystemPageBase[i].BaseAddress;
  902. if (NewLine) {
  903. printf("\n");
  904. NewLine = FALSE;
  905. }
  906. printf("0x%p -> (0x%p : 0x%p) %4d "
  907. "Resident Pages\n",
  908. Va,
  909. SPBase,
  910. SPBase + VaMappedByPageTable - 1,
  911. SystemPageBase[i].ResidentPages);
  912. //
  913. // Figure out which modules are covered by this
  914. // page table page. If the base of the module is
  915. // within the page, or the base+size of the
  916. // module is covered, then it is in the page
  917. //
  918. for (i = 0 ; i < ModInfoMax ; i += 1) {
  919. MIBase = (ULONG_PTR) ModInfo[i].BaseAddress;
  920. MIEnd = MIBase + (ULONG_PTR)ModInfo[i].VirtualSize;
  921. if ((MIEnd >= SPBase) &&
  922. (MIBase < SPBase + VaMappedByPageTable)) {
  923. printf(" (0x%p : 0x%p) "
  924. "-> %s\n",
  925. MIBase,
  926. MIEnd,
  927. ModInfo[i].Name
  928. );
  929. NewLine = TRUE;
  930. }
  931. }
  932. //
  933. // Figure out which heaps are covered by this
  934. // page table page.
  935. //
  936. Next = LoadedHeapList.Flink;
  937. while (Next != &LoadedHeapList) {
  938. pHeap = CONTAINING_RECORD (Next,
  939. LOADED_HEAP,
  940. HeapsList);
  941. Next = Next->Flink;
  942. for (i = 0 ; i < HEAP_MAXIMUM_SEGMENTS ; i += 1) {
  943. if (pHeap->Segments[i].BaseVa == NULL) {
  944. break;
  945. }
  946. HSBase = (ULONG_PTR) pHeap->Segments[i].BaseVa;
  947. HSEnd = HSBase +
  948. (ULONG_PTR)pHeap->Segments[i].Length;
  949. if ((HSEnd >= SPBase) &&
  950. (HSBase < (SPBase + VaMappedByPageTable))) {
  951. printf(" (0x%p : 0x%p) "
  952. "-> %s segment %d\n",
  953. HSBase,
  954. HSEnd,
  955. pHeap->HeapName,
  956. i);
  957. NewLine = TRUE;
  958. }
  959. }
  960. }
  961. //
  962. // Figure out which stacks are covered by this
  963. // page table page.
  964. //
  965. for (i = 0 ; i < NumberOfThreads ; i += 1) {
  966. SSBase = (ULONG_PTR)TheThreads[i].StackBase;
  967. SSEnd = (ULONG_PTR)TheThreads[i].StackEnd;
  968. if ((SSEnd >= SPBase) &&
  969. (SSBase < (SPBase + VaMappedByPageTable))) {
  970. printf(" (0x%p : 0x%p) "
  971. "-> Stack for thread %d\n",
  972. SSBase,
  973. SSEnd,
  974. i);
  975. NewLine = TRUE;
  976. }
  977. }
  978. }
  979. SystemPages += 1;
  980. TotalSystem += 1;
  981. continue;
  982. }
  983. Mi = LocateModInfo ((PVOID)Va);
  984. if (Mi == NULL) {
  985. if (FindAndIncHeapContainingThisVa ((PVOID)Va, ShareCount)) {
  986. HeapPages += 1;
  987. TotalDynamicData += 1;
  988. TotalDynamicDataPrivate += 1;
  989. continue;
  990. }
  991. if (FindAndIncStackContainingThisVa ((PVOID)Va, ShareCount)) {
  992. StackPages += 1;
  993. TotalDynamicData += 1;
  994. TotalDynamicDataPrivate += 1;
  995. continue;
  996. }
  997. if (VirtualQueryEx (Process,
  998. (LPVOID) Va,
  999. &BasicInfo,
  1000. sizeof(BasicInfo)) ) {
  1001. if (BasicInfo.Type == MEM_MAPPED) {
  1002. if (ProcessId == 0xffffffff) {
  1003. //
  1004. // Look to see if this is a quick thread message
  1005. // stack window
  1006. //
  1007. b = ReadProcessMemory(
  1008. Process,
  1009. BasicInfo.AllocationBase,
  1010. &Mstack,
  1011. sizeof(Mstack),
  1012. NULL);
  1013. if (!b) {
  1014. goto unknownmapped;
  1015. }
  1016. if ((Mstack[0] >= Mstack[1]) &&
  1017. (Mstack[2] == 0x10000)) {
  1018. if (!fSummary) {
  1019. printf("0x%p ", Va);
  1020. if (IsSystemWithShareCount) {
  1021. printf("(%d) ", ShareCount);
  1022. }
  1023. printf("CSRQUICK Base 0x%p\n", BasicInfo.AllocationBase);
  1024. }
  1025. QuickPages += 1;
  1026. TotalDynamicData += 1;
  1027. TotalDynamicDataPrivate += 1;
  1028. if (ShareCount > 1) {
  1029. fprintf(stderr, "Error: QuickPage ShareCount > 1, "
  1030. " 0x%x\n", Va);
  1031. }
  1032. continue;
  1033. }
  1034. if ((BasicInfo.AllocationBase == NtCurrentPeb()->ReadOnlySharedMemoryBase) ||
  1035. (Va == (ULONG_PTR)NtCurrentPeb()->ReadOnlySharedMemoryBase)) {
  1036. if (!fSummary) {
  1037. printf("0x%p", Va);
  1038. if (IsSystemWithShareCount) {
  1039. printf("(%d) ", ShareCount);
  1040. }
  1041. printf("CSRSHARED Base 0x%p", BasicInfo.AllocationBase);
  1042. }
  1043. TotalDynamicData++;
  1044. CsrSharedPages++;
  1045. if (IsShareable) {
  1046. if (ShareCount > 1) {
  1047. TotalDynamicDataShared++;
  1048. SharedCsrSharedPages++;
  1049. }
  1050. } else {
  1051. fprintf(stderr, "Error: CsrShared not "
  1052. " sharable, 0x%x\n", Va);
  1053. }
  1054. continue;
  1055. }
  1056. // Fall Through if not found
  1057. }
  1058. //
  1059. // It's mapped but wasn't CSRSS special page.
  1060. //
  1061. unknownmapped:
  1062. if ( !fSummary ) {
  1063. DWORD cch;
  1064. //
  1065. // See if we can figure out the name associated with
  1066. // this mapped region
  1067. //
  1068. cch = GetMappedFileNameW(Process,
  1069. (LPVOID) Va,
  1070. FileName,
  1071. sizeof(FileName) / sizeof(FileName[0]));
  1072. if (cch != 0) {
  1073. //
  1074. // Now go back through the string to
  1075. // find the seperator
  1076. //
  1077. pwch = FileName + cch;
  1078. while ( *pwch != (WCHAR)'\\' ) {
  1079. pwch--;
  1080. }
  1081. pwch++;
  1082. printf("0x%p ", Va);
  1083. if (IsSystemWithShareCount) {
  1084. printf("(%d) ", ShareCount);
  1085. }
  1086. printf("DATAFILE_MAPPED Base 0x%p %ws\n",
  1087. BasicInfo.AllocationBase,
  1088. pwch
  1089. );
  1090. } else {
  1091. printf("0x%p ", Va);
  1092. if (IsSystemWithShareCount) {
  1093. printf("(%d) ", ShareCount);
  1094. }
  1095. printf("UNKNOWN_MAPPED Base 0x%p\n", BasicInfo.AllocationBase);
  1096. }
  1097. }
  1098. TotalDynamicData++;
  1099. MappedPages++;
  1100. if (IsShareable) {
  1101. if (ShareCount > 1) {
  1102. TotalDynamicDataShared++;
  1103. SharedMappedPages++;
  1104. }
  1105. } else {
  1106. TotalDynamicDataPrivate++;
  1107. PrivateMappedPages++;
  1108. }
  1109. continue;
  1110. }
  1111. //
  1112. // Not Mapped section
  1113. //
  1114. for (i = 0 ; i < NumberOfThreads; i += 1) {
  1115. if ((ULONG_PTR) TheThreads[i].ThreadTEB == Va) {
  1116. if (!fSummary) {
  1117. printf("0x%p ", Va);
  1118. if (IsSystemWithShareCount) {
  1119. printf("(%d) ", ShareCount);
  1120. }
  1121. printf("TEB Base 0x%p\n",
  1122. BasicInfo.AllocationBase);
  1123. }
  1124. TotalDynamicData++;
  1125. TebPages++;
  1126. if (ShareCount > 1) {
  1127. fprintf(stderr, "Error: TEB ShareCount > 1, "
  1128. " 0x%x\n", Va);
  1129. }
  1130. TotalDynamicDataPrivate++;
  1131. continue;
  1132. }
  1133. }
  1134. //
  1135. // Wasn't a TEB either it must have been VirtualAlloc'd.
  1136. //
  1137. if (!fSummary) {
  1138. printf("0x%p ", Va);
  1139. if (IsSystemWithShareCount) {
  1140. printf("(%d) ", ShareCount);
  1141. }
  1142. printf("PRIVATE Base 0x%p\n", BasicInfo.AllocationBase );
  1143. }
  1144. TotalDynamicData += 1;
  1145. DataPages += 1;
  1146. if (Va != MM_SHARED_USER_DATA_VA) {
  1147. if (ShareCount > 1) {
  1148. fprintf(stderr, "Error: Private ShareCount > 1, "
  1149. " 0x%x %x\n", Va, ShareCount);
  1150. }
  1151. TotalDynamicDataPrivate += 1;
  1152. PrivateDataPages += 1;
  1153. }
  1154. continue;
  1155. }
  1156. //
  1157. // Hmm, couldn't find out about the page. Say it's data.
  1158. //
  1159. if (!fSummary) {
  1160. printf("0x%p ", Va);
  1161. if (IsSystemWithShareCount) {
  1162. printf("(%d) ", ShareCount);
  1163. }
  1164. printf("UNKOWN\n");
  1165. }
  1166. TotalDynamicData++;
  1167. DataPages++;
  1168. if (IsShareable) {
  1169. if (ShareCount > 1) {
  1170. TotalDynamicDataShared++;
  1171. SharedDataPages++;
  1172. }
  1173. }
  1174. else {
  1175. TotalDynamicDataPrivate++;
  1176. PrivateDataPages++;
  1177. }
  1178. continue;
  1179. }
  1180. //
  1181. // It's from a module.
  1182. //
  1183. Mi->WsHits += 1;
  1184. TotalStaticCodeData += 1;
  1185. if (IsShareable) {
  1186. if (ShareCount > 1) {
  1187. TotalStaticCodeDataShared += 1;
  1188. Mi->WsSharedHits += 1;
  1189. }
  1190. }
  1191. else {
  1192. Mi->WsPrivateHits += 1;
  1193. TotalStaticCodeDataPrivate += 1;
  1194. }
  1195. if ( !fSummary ) {
  1196. printf("0x%p ", Va);
  1197. if (IsSystemWithShareCount) {
  1198. printf("(%d) ", ShareCount);
  1199. }
  1200. printf("%s\n",Mi->Name);
  1201. if (Options & OPTIONS_RAW_SYMBOLS) {
  1202. if (SymGetSymFromAddr((HANDLE)ProcessId,
  1203. Va,
  1204. &Displacement,
  1205. ThisSymbol )) {
  1206. BaseVa = Va;
  1207. if (ThisSymbol->Size) {
  1208. printf("\t(%4x) %s\n",
  1209. ThisSymbol->Size,
  1210. ThisSymbol->Name
  1211. );
  1212. Va += ThisSymbol->Size;
  1213. while ((Va < BaseVa + 4096) &&
  1214. ThisSymbol->Size) {
  1215. if (SymGetSymFromAddr((HANDLE)ProcessId,
  1216. Va,
  1217. &Displacement,
  1218. ThisSymbol)) {
  1219. printf("\t(%4x) %s\n",
  1220. ThisSymbol->Size,
  1221. ThisSymbol->Name
  1222. );
  1223. Va += ThisSymbol->Size;
  1224. }
  1225. else {
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. }
  1231. else {
  1232. ErrorPages++;
  1233. }
  1234. }
  1235. }
  1236. }
  1237. if (!fSummary || (Options & OPTIONS_PAGE_TABLES)) {
  1238. printf("\n");
  1239. }
  1240. if (IsSystemWithShareCount) {
  1241. printf("Category Total Private Shareable Shared\n");
  1242. printf(" Pages KBytes KBytes KBytes KBytes\n");
  1243. } else {
  1244. printf("Category Total Private Shareable\n");
  1245. printf(" Pages KBytes KBytes KBytes\n");
  1246. }
  1247. Total = PageTablePageCount;
  1248. Private = Total;
  1249. Shared = 0;
  1250. Shareable = 0;
  1251. printf(IsSystemWithShareCount ?
  1252. " Page Table Pages %5d %9d %9d %9d %9d\n" :
  1253. " Page Table Pages %5d %9d %9d %9d\n",
  1254. Total,
  1255. P2KB(Total),
  1256. P2KB(Private),
  1257. P2KB(Shareable),
  1258. P2KB(Shared)
  1259. );
  1260. Total = SystemPages - PageTablePageCount;
  1261. Private = Total;
  1262. Shared = 0;
  1263. Shareable = 0;
  1264. printf(IsSystemWithShareCount ?
  1265. " Other System %5d %9d %9d %9d %9d\n" :
  1266. " Other System %5d %9d %9d %9d\n",
  1267. Total,
  1268. P2KB(Total),
  1269. P2KB(Private),
  1270. P2KB(Shareable),
  1271. P2KB(Shared)
  1272. );
  1273. Total = TotalStaticCodeData;
  1274. Private = TotalStaticCodeDataPrivate;
  1275. Shared = TotalStaticCodeDataShared;
  1276. Shareable = Total - Shared - Private;
  1277. printf(IsSystemWithShareCount ?
  1278. " Code/StaticData %5d %9d %9d %9d %9d\n" :
  1279. " Code/StaticData %5d %9d %9d %9d\n",
  1280. Total,
  1281. P2KB(Total),
  1282. P2KB(Private),
  1283. P2KB(Shareable),
  1284. P2KB(Shared)
  1285. );
  1286. Total = HeapPages;
  1287. Private = Total;
  1288. Shared = 0;
  1289. Shareable = 0;
  1290. printf(IsSystemWithShareCount ?
  1291. " Heap %5d %9d %9d %9d %9d\n" :
  1292. " Heap %5d %9d %9d %9d\n",
  1293. Total,
  1294. P2KB(Total),
  1295. P2KB(Private),
  1296. P2KB(Shareable),
  1297. P2KB(Shared)
  1298. );
  1299. Total = StackPages;
  1300. Private = Total;
  1301. Shared = 0;
  1302. Shareable = 0;
  1303. printf(IsSystemWithShareCount ?
  1304. " Stack %5d %9d %9d %9d %9d\n" :
  1305. " Stack %5d %9d %9d %9d\n",
  1306. Total,
  1307. P2KB(Total),
  1308. P2KB(Private),
  1309. P2KB(Shareable),
  1310. P2KB(Shared)
  1311. );
  1312. if ( ProcessId == 0xffffffff ) {
  1313. Total = QuickPages;
  1314. Private = Total;
  1315. Shared = 0;
  1316. Shareable = 0;
  1317. printf(IsSystemWithShareCount ?
  1318. " Quick Thread Stack %5d %9d %9d %9d %9d\n" :
  1319. " Quick Thread Stack %5d %9d %9d %9d\n",
  1320. Total,
  1321. P2KB(Total),
  1322. P2KB(Private),
  1323. P2KB(Shareable),
  1324. P2KB(Shared)
  1325. );
  1326. Total = LpcPages;
  1327. Private = 0;
  1328. Shareable = 0;
  1329. Shared = 0;
  1330. printf(IsSystemWithShareCount ?
  1331. " Lpc Message Windows %5d %9d %9d %9d %9d\n" :
  1332. " Lpc Message Windows %5d %9d %9d %9d\n",
  1333. Total,
  1334. P2KB(Total),
  1335. P2KB(Private),
  1336. P2KB(Shareable),
  1337. P2KB(Shared)
  1338. );
  1339. Total = CsrSharedPages;
  1340. Private = 0;
  1341. Shared = SharedCsrSharedPages;
  1342. Shareable = Total - Shared - Private;
  1343. printf(IsSystemWithShareCount ?
  1344. " Csr Shared Memory %5d %9d %9d %9d %9d\n" :
  1345. " Csr Shared Memory %5d %9d %9d %9d\n",
  1346. Total,
  1347. P2KB(Total),
  1348. P2KB(Private),
  1349. P2KB(Shareable),
  1350. P2KB(Shared)
  1351. );
  1352. }
  1353. Total = TebPages;
  1354. Private = Total;
  1355. Shared = 0;
  1356. Shareable = 0;
  1357. printf(IsSystemWithShareCount ?
  1358. " Teb %5d %9d %9d %9d %9d\n" :
  1359. " Teb %5d %9d %9d %9d\n",
  1360. Total,
  1361. P2KB(Total),
  1362. P2KB(Private),
  1363. P2KB(Shareable),
  1364. P2KB(Shared)
  1365. );
  1366. Total = MappedPages;
  1367. Private = PrivateMappedPages;
  1368. Shared = SharedMappedPages;
  1369. Shareable = Total - Shared - Private;
  1370. printf(IsSystemWithShareCount ?
  1371. " Mapped Data %5d %9d %9d %9d %9d\n" :
  1372. " Mapped Data %5d %9d %9d %9d\n",
  1373. Total,
  1374. P2KB(Total),
  1375. P2KB(Private),
  1376. P2KB(Shareable),
  1377. P2KB(Shared)
  1378. );
  1379. Total = DataPages;
  1380. Private = PrivateDataPages;
  1381. Shared = SharedDataPages;
  1382. Shareable = Total - Shared - Private;
  1383. printf(IsSystemWithShareCount ?
  1384. " Other Data %5d %9d %9d %9d %9d\n" :
  1385. " Other Data %5d %9d %9d %9d\n",
  1386. Total,
  1387. P2KB(Total),
  1388. P2KB(Private),
  1389. P2KB(Shareable),
  1390. P2KB(Shared)
  1391. );
  1392. printf("\n");
  1393. Total = TotalStaticCodeData;
  1394. Private = TotalStaticCodeDataPrivate;
  1395. Shared = TotalStaticCodeDataShared;
  1396. Shareable = Total - Shared - Private;
  1397. printf(IsSystemWithShareCount ?
  1398. " Total Modules %5d %9d %9d %9d %9d\n" :
  1399. " Total Modules %5d %9d %9d %9d\n",
  1400. Total,
  1401. P2KB(Total),
  1402. P2KB(Private),
  1403. P2KB(Shareable),
  1404. P2KB(Shared)
  1405. );
  1406. Total = TotalDynamicData;
  1407. Private = TotalDynamicDataPrivate;
  1408. Shared = TotalDynamicDataShared;
  1409. Shareable = Total - Shared - Private;
  1410. printf(IsSystemWithShareCount ?
  1411. " Total Dynamic Data %5d %9d %9d %9d %9d\n" :
  1412. " Total Dynamic Data %5d %9d %9d %9d\n",
  1413. Total,
  1414. P2KB(Total),
  1415. P2KB(Private),
  1416. P2KB(Shareable),
  1417. P2KB(Shared)
  1418. );
  1419. Total = TotalSystem;
  1420. Private = Total;
  1421. Shared = 0;
  1422. Shareable = 0;
  1423. printf(IsSystemWithShareCount ?
  1424. " Total System %5d %9d %9d %9d %9d\n" :
  1425. " Total System %5d %9d %9d %9d\n",
  1426. Total,
  1427. P2KB(Total),
  1428. P2KB(Private),
  1429. P2KB(Shareable),
  1430. P2KB(Shared)
  1431. );
  1432. Total = TotalSystem + TotalDynamicData + TotalStaticCodeData;
  1433. Private = TotalSystem + TotalDynamicDataPrivate +
  1434. TotalStaticCodeDataPrivate;
  1435. Shared = TotalDynamicDataShared + TotalStaticCodeDataShared;
  1436. Shareable = Total - Shared - Private;
  1437. printf(IsSystemWithShareCount ?
  1438. "Grand Total Working Set %5d %9d %9d %9d %9d\n" :
  1439. "Grand Total Working Set %5d %9d %9d %9d\n",
  1440. Total,
  1441. P2KB(Total),
  1442. P2KB(Private),
  1443. P2KB(Shareable),
  1444. P2KB(Shared)
  1445. );
  1446. printf("\nModule Working Set Contributions in pages\n");
  1447. printf(IsSystemWithShareCount ?
  1448. " Total Private Shareable Shared Module\n" :
  1449. " Total Private Shareable Module\n"
  1450. );
  1451. for (i=0 ; i < ModInfoMax ; i++){
  1452. if ( ModInfo[i].WsHits ) {
  1453. if (IsSystemWithShareCount) {
  1454. printf("%9d %9d %9d %9d %s\n",
  1455. ModInfo[i].WsHits,
  1456. ModInfo[i].WsPrivateHits,
  1457. ModInfo[i].WsHits -
  1458. ModInfo[i].WsSharedHits -
  1459. ModInfo[i].WsPrivateHits,
  1460. ModInfo[i].WsSharedHits,
  1461. ModInfo[i].Name
  1462. );
  1463. }
  1464. else {
  1465. printf("%9d %9d %9d %s\n",
  1466. ModInfo[i].WsHits,
  1467. ModInfo[i].WsPrivateHits,
  1468. ModInfo[i].WsHits -
  1469. ModInfo[i].WsSharedHits -
  1470. ModInfo[i].WsPrivateHits,
  1471. ModInfo[i].Name
  1472. );
  1473. }
  1474. }
  1475. }
  1476. printf("\nHeap Working Set Contributions\n");
  1477. Next = LoadedHeapList.Flink;
  1478. while ( Next != &LoadedHeapList ) {
  1479. pHeap = CONTAINING_RECORD(Next, LOADED_HEAP, HeapsList);
  1480. Next = Next->Flink;
  1481. DumpLoadedHeap(pHeap);
  1482. }
  1483. printf("\nStack Working Set Contributions\n");
  1484. DumpLoadedStacks();
  1485. #if 0
  1486. if ( Options & OPTIONS_VERBOSE ) {
  1487. printf("Raw Working Set Blocks\n\n");
  1488. for (i = 0; i < WorkingSetInfo->NumberOfEntries ; i++) {
  1489. printf("%d %p\n", i, (ULONG_PTR) WorkingSetInfo->WorkingSetInfo[i]);
  1490. i++;
  1491. }
  1492. }
  1493. #endif
  1494. if (SystemPageBase != NULL) {
  1495. LocalFree (SystemPageBase);
  1496. }
  1497. }
  1498. VOID
  1499. DumpWorkingSet (
  1500. IN HANDLE Process
  1501. )
  1502. {
  1503. ULONG i;
  1504. PMODINFO Mi,Mi2;
  1505. NTSTATUS Status;
  1506. ULONG_PTR Offset;
  1507. BOOLEAN didone;
  1508. HANDLE ScreenHandle;
  1509. INPUT_RECORD InputRecord;
  1510. DWORD NumRead;
  1511. ScreenHandle = GetStdHandle (STD_INPUT_HANDLE);
  1512. if (ScreenHandle == NULL) {
  1513. printf("Error obtaining screen handle, error was: 0x%lx\n",
  1514. GetLastError());
  1515. ExitProcess(1);
  1516. }
  1517. Status = NtSetInformationProcess (Process, ProcessWorkingSetWatch, NULL, 0);
  1518. if (!NT_SUCCESS(Status) &&
  1519. !(Status == STATUS_PORT_ALREADY_SET) &&
  1520. !(Status == STATUS_ACCESS_DENIED)) {
  1521. return;
  1522. }
  1523. SetConsoleCtrlHandler(CtrlcH,TRUE);
  1524. EmptyWorkingSet(Process);
  1525. while (TRUE) {
  1526. Status = NtQueryInformationProcess (Process,
  1527. ProcessWorkingSetWatch,
  1528. (PVOID *)&NewWorkingSetBuffer,
  1529. sizeof (NewWorkingSetBuffer),
  1530. NULL);
  1531. if (fFast) {
  1532. fFast = FALSE;
  1533. Status = STATUS_NO_MORE_ENTRIES;
  1534. }
  1535. if ( NT_SUCCESS(Status) ) {
  1536. //
  1537. // For each PC/VA pair, print the pc and referenced VA
  1538. // symbolically
  1539. //
  1540. didone = FALSE;
  1541. i = 0;
  1542. while (NewWorkingSetBuffer[i].FaultingPc) {
  1543. if ( NewWorkingSetBuffer[i].FaultingVa ) {
  1544. if ( InCtrlc ) {
  1545. ExitThread(0);
  1546. }
  1547. Mi2 = LocateModInfo((PVOID)NewWorkingSetBuffer[i].FaultingVa);
  1548. if ( !Mi2 || (Mi2 && (Options & OPTIONS_CODE_TOO))) {
  1549. //
  1550. // Add the pc to the running working set
  1551. // watch buffer
  1552. //
  1553. RunningWorkingSetBuffer[CurrentWsIndex++] = (ULONG_PTR)NewWorkingSetBuffer[i].FaultingPc;
  1554. if ( CurrentWsIndex >= MAX_RUNNING_WORKING_SET_BUFFER ) {
  1555. CtrlcH(CTRL_C_EVENT);
  1556. }
  1557. if ( fRunning ) {
  1558. //
  1559. // Print the PC symbolically.
  1560. //
  1561. didone = TRUE;
  1562. Mi = LocateModInfo((PVOID)NewWorkingSetBuffer[i].FaultingPc);
  1563. if ( !Mi ) {
  1564. printf("0x%p",NewWorkingSetBuffer[i].FaultingPc);
  1565. if ( LogFile ) {
  1566. fprintf(LogFile,"0x%p",NewWorkingSetBuffer[i].FaultingPc);
  1567. }
  1568. }
  1569. else {
  1570. if (SymGetSymFromAddr((HANDLE)ProcessId, (DWORD_PTR)NewWorkingSetBuffer[i].FaultingPc, &Displacement, ThisSymbol )) {
  1571. Offset = (ULONG_PTR)NewWorkingSetBuffer[i].FaultingPc - ThisSymbol->Address;
  1572. if ( Offset ) {
  1573. printf("%s+%x",ThisSymbol->Name,Offset);
  1574. if ( LogFile ) {
  1575. fprintf(LogFile,"%s+%x",ThisSymbol->Name,Offset);
  1576. }
  1577. }
  1578. else {
  1579. printf("%s",ThisSymbol->Name);
  1580. if ( LogFile ) {
  1581. fprintf(LogFile,"%s",ThisSymbol->Name);
  1582. }
  1583. }
  1584. }
  1585. else {
  1586. printf("0x%p",NewWorkingSetBuffer[i].FaultingPc);
  1587. if ( LogFile ) {
  1588. fprintf(LogFile,"0x%p",NewWorkingSetBuffer[i].FaultingPc);
  1589. }
  1590. }
  1591. }
  1592. //
  1593. // Print the VA Symbolically
  1594. //
  1595. Mi = LocateModInfo((PVOID)NewWorkingSetBuffer[i].FaultingVa);
  1596. if ( !Mi ) {
  1597. printf(" : 0x%p",NewWorkingSetBuffer[i].FaultingVa);
  1598. if ( LogFile ) {
  1599. fprintf(LogFile," : 0x%p",NewWorkingSetBuffer[i].FaultingVa);
  1600. }
  1601. }
  1602. else {
  1603. if (SymGetSymFromAddr((HANDLE)ProcessId, (DWORD_PTR)NewWorkingSetBuffer[i].FaultingVa, &Displacement, ThisSymbol )) {
  1604. Offset = (ULONG_PTR)NewWorkingSetBuffer[i].FaultingVa - ThisSymbol->Address;
  1605. if ( Offset ) {
  1606. printf(" : %s+%x",ThisSymbol->Name,Offset);
  1607. if ( LogFile ) {
  1608. fprintf(LogFile," : %s+%x",ThisSymbol->Name,Offset);
  1609. }
  1610. }
  1611. else {
  1612. printf(" : %s",ThisSymbol->Name);
  1613. if ( LogFile ) {
  1614. fprintf(LogFile," : %s",ThisSymbol->Name);
  1615. }
  1616. }
  1617. }
  1618. else {
  1619. printf(" : 0x%p",NewWorkingSetBuffer[i].FaultingVa);
  1620. if ( LogFile ) {
  1621. fprintf(LogFile," : 0x%p",NewWorkingSetBuffer[i].FaultingVa);
  1622. }
  1623. }
  1624. }
  1625. printf("\n");
  1626. if ( LogFile ) {
  1627. fprintf(LogFile,"\n");
  1628. }
  1629. }
  1630. }
  1631. }
  1632. i++;
  1633. }
  1634. if ( didone ) {
  1635. printf("\n");
  1636. if ( LogFile ) {
  1637. fprintf(LogFile,"\n");
  1638. }
  1639. }
  1640. }
  1641. Sleep(1000);
  1642. while (PeekConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead) && NumRead != 0) {
  1643. if (!ReadConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead)) {
  1644. break;
  1645. }
  1646. if (InputRecord.EventType == KEY_EVENT) {
  1647. //
  1648. // Ignore control characters.
  1649. //
  1650. if (InputRecord.Event.KeyEvent.uChar.AsciiChar >= ' ') {
  1651. switch (InputRecord.Event.KeyEvent.uChar.AsciiChar) {
  1652. case 'F':
  1653. case 'f':
  1654. EmptyWorkingSet(Process);
  1655. printf("\n*** Working Set Flushed ***\n\n");
  1656. if ( LogFile ) {
  1657. fprintf(LogFile,"\n*** Working Set Flushed ***\n\n");
  1658. }
  1659. break;
  1660. default:
  1661. break;
  1662. }
  1663. }
  1664. }
  1665. }
  1666. }
  1667. }
  1668. VOID
  1669. ComputeModInfo(
  1670. HANDLE Process,
  1671. DWORD_PTR ProcessId
  1672. )
  1673. {
  1674. HMODULE rghModule[MODINFO_SIZE];
  1675. DWORD cbNeeded;
  1676. ULONG ModInfoNext;
  1677. PVOID BaseAddress;
  1678. IMAGEHLP_MODULE ModuleInfo;
  1679. MODULEINFO PsapiModuleInfo;
  1680. ULONG i;
  1681. ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  1682. SymInitialize((HANDLE)ProcessId, NULL, FALSE );
  1683. SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
  1684. for (i=0 ; i < ModInfoMax ; i++){
  1685. if ( ModInfo[i].BaseAddress &&
  1686. ModInfo[i].BaseAddress != (PVOID)-1 &&
  1687. ModInfo[i].Name
  1688. ) {
  1689. LocalFree(ModInfo[i].Name);
  1690. }
  1691. }
  1692. RtlZeroMemory(ModInfo, sizeof(ModInfo));
  1693. if (!EnumProcessModules(Process, rghModule, sizeof(rghModule), &cbNeeded)) {
  1694. return;
  1695. }
  1696. if (cbNeeded > sizeof(rghModule)) {
  1697. cbNeeded = sizeof(rghModule);
  1698. }
  1699. ModInfoMax = cbNeeded / sizeof(HMODULE);
  1700. for (ModInfoNext = 0; ModInfoNext < ModInfoMax; ModInfoNext++) {
  1701. HMODULE hModule;
  1702. DWORD cch;
  1703. CHAR DllName[MAX_PATH];
  1704. hModule = rghModule[ModInfoNext];
  1705. ModInfo[ModInfoNext].BaseAddress = (PVOID) hModule;
  1706. //
  1707. // Get the base name of the module
  1708. //
  1709. cch = GetModuleBaseName(Process, hModule, DllName, sizeof(DllName));
  1710. if (cch == 0) {
  1711. return;
  1712. }
  1713. ModInfo[ModInfoNext].Name = LocalAlloc(LMEM_ZEROINIT, cch+1);
  1714. if ( !ModInfo[ModInfoNext].Name) {
  1715. return;
  1716. }
  1717. memcpy(ModInfo[ModInfoNext].Name, DllName, cch);
  1718. //
  1719. // Get the full path to the module.
  1720. //
  1721. cch = GetModuleFileNameEx (Process, hModule, DllName, sizeof(DllName));
  1722. if (cch == 0) {
  1723. return;
  1724. }
  1725. GetModuleInformation (Process,
  1726. hModule,
  1727. &PsapiModuleInfo,
  1728. sizeof(MODULEINFO));
  1729. ModInfo[ModInfoNext].VirtualSize = PsapiModuleInfo.SizeOfImage;
  1730. BaseAddress = (PVOID)SymLoadModule ((HANDLE)ProcessId,
  1731. NULL,
  1732. DllName,
  1733. NULL,
  1734. (DWORD_PTR)hModule,
  1735. PsapiModuleInfo.SizeOfImage);
  1736. if ((ModInfo[ModInfoNext].BaseAddress) &&
  1737. (ModInfo[ModInfoNext].BaseAddress == BaseAddress)) {
  1738. SymGetModuleInfo(
  1739. (HANDLE)ProcessId,
  1740. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress,
  1741. &ModuleInfo
  1742. );
  1743. if (ModuleInfo.SymType == SymNone) {
  1744. ModInfo[ModInfoNext].SymbolsLoaded = FALSE;
  1745. if (Options & OPTIONS_VERBOSE) {
  1746. fprintf(stderr, "Could not load symbols: %p : %p %s\n",
  1747. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress,
  1748. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress +
  1749. ModInfo[ModInfoNext].VirtualSize,
  1750. ModInfo[ModInfoNext].Name
  1751. );
  1752. }
  1753. } else {
  1754. ModInfo[ModInfoNext].SymbolsLoaded = TRUE;
  1755. if (Options & OPTIONS_VERBOSE) {
  1756. fprintf(stderr, "Symbols loaded: %p : %p %s\n",
  1757. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress,
  1758. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress +
  1759. ModInfo[ModInfoNext].VirtualSize,
  1760. ModInfo[ModInfoNext].Name
  1761. );
  1762. }
  1763. }
  1764. } else {
  1765. ModInfo[ModInfoNext].SymbolsLoaded = FALSE;
  1766. if (Options & OPTIONS_VERBOSE) {
  1767. fprintf(stderr, "Symbols not loaded and conflicting Base: %p (%p) : %p %s\n",
  1768. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress,
  1769. BaseAddress,
  1770. (DWORD_PTR)ModInfo[ModInfoNext].BaseAddress +
  1771. ModInfo[ModInfoNext].VirtualSize,
  1772. ModInfo[ModInfoNext].Name
  1773. );
  1774. }
  1775. }
  1776. }
  1777. if (bHitModuleMax) {
  1778. fprintf(stderr, "\nERROR: The number of modules in the process more than the buffer size\n");
  1779. }
  1780. }
  1781. ProtectionToIndex(
  1782. ULONG Protection
  1783. )
  1784. {
  1785. Protection &= ~PAGE_GUARD;
  1786. switch ( Protection ) {
  1787. case PAGE_NOACCESS:
  1788. return NOACCESS;
  1789. case PAGE_READONLY:
  1790. return READONLY;
  1791. case PAGE_READWRITE:
  1792. return READWRITE;
  1793. case PAGE_WRITECOPY:
  1794. return WRITECOPY;
  1795. case PAGE_EXECUTE:
  1796. return EXECUTE;
  1797. case PAGE_EXECUTE_READ:
  1798. return EXECUTEREAD;
  1799. case PAGE_EXECUTE_READWRITE:
  1800. return EXECUTEREADWRITE;
  1801. case PAGE_EXECUTE_WRITECOPY:
  1802. return EXECUTEWRITECOPY;
  1803. default:
  1804. return 0;
  1805. }
  1806. }
  1807. VOID
  1808. DumpCommit (
  1809. PSZ Header,
  1810. ULONG_PTR *CommitVector
  1811. )
  1812. {
  1813. ULONG_PTR TotalCommitCount;
  1814. ULONG i;
  1815. TotalCommitCount = 0;
  1816. for ( i=0;i<MAXPROTECT;i++){
  1817. TotalCommitCount += CommitVector[i];
  1818. }
  1819. printf("\nTotal %s Commitment %8ld\n",Header,TotalCommitCount);
  1820. if ( CommitVector[NOACCESS] ) {
  1821. printf(" NOACCESS: %9ld\n",CommitVector[NOACCESS]);
  1822. }
  1823. if ( CommitVector[READONLY] ) {
  1824. printf(" READONLY: %9ld\n",CommitVector[READONLY]);
  1825. }
  1826. if ( CommitVector[READWRITE] ) {
  1827. printf(" READWRITE: %9ld\n",CommitVector[READWRITE]);
  1828. }
  1829. if ( CommitVector[WRITECOPY] ) {
  1830. printf(" WRITECOPY: %9ld\n",CommitVector[WRITECOPY]);
  1831. }
  1832. if ( CommitVector[EXECUTE] ) {
  1833. printf(" EXECUTE: %9ld\n",CommitVector[EXECUTE]);
  1834. }
  1835. if ( CommitVector[EXECUTEREAD] ) {
  1836. printf(" EXECUTEREAD: %9ld\n",CommitVector[EXECUTEREAD]);
  1837. }
  1838. if ( CommitVector[EXECUTEREADWRITE] ) {
  1839. printf(" EXECUTEREADWRITE: %9ld\n",CommitVector[EXECUTEREADWRITE]);
  1840. }
  1841. if ( CommitVector[EXECUTEWRITECOPY] ) {
  1842. printf(" EXECUTEWRITECOPY: %9ld\n",CommitVector[EXECUTEWRITECOPY]);
  1843. }
  1844. }
  1845. VOID
  1846. DumpModInfo (
  1847. )
  1848. {
  1849. ULONG i;
  1850. for (i=0 ; i < ModInfoMax ; i++){
  1851. DumpCommit(ModInfo[i].Name, &ModInfo[i].CommitVector[0]);
  1852. }
  1853. }
  1854. VOID
  1855. CaptureVaSpace (
  1856. IN HANDLE Process
  1857. )
  1858. {
  1859. PVOID BaseAddress;
  1860. PVAINFO VaInfo;
  1861. PMODINFO Mod;
  1862. BaseAddress = NULL;
  1863. LastAllocationBase = NULL;
  1864. InitializeListHead(&VaList);
  1865. while ( (ULONG_PTR)BaseAddress < SystemRangeStart ) {
  1866. VaInfo = LocalAlloc(LMEM_ZEROINIT, sizeof(*VaInfo));
  1867. if (!VaInfo) {
  1868. return;
  1869. }
  1870. if ( !VirtualQueryEx(Process,
  1871. BaseAddress,
  1872. &VaInfo->BasicInfo,
  1873. sizeof(VaInfo->BasicInfo)) ) {
  1874. LocalFree (VaInfo);
  1875. return;
  1876. }
  1877. switch (VaInfo->BasicInfo.State ) {
  1878. case MEM_COMMIT :
  1879. if ( VaInfo->BasicInfo.Type == MEM_IMAGE ) {
  1880. ImageCommit[ProtectionToIndex(VaInfo->BasicInfo.Protect)] += VaInfo->BasicInfo.RegionSize;
  1881. Mod = LocateModInfo(BaseAddress);
  1882. if ( Mod ) {
  1883. Mod->CommitVector[ProtectionToIndex(VaInfo->BasicInfo.Protect)] += VaInfo->BasicInfo.RegionSize;
  1884. }
  1885. }
  1886. else {
  1887. if ( VaInfo->BasicInfo.Type == MEM_MAPPED ) {
  1888. MappedCommit[ProtectionToIndex(VaInfo->BasicInfo.Protect)] += VaInfo->BasicInfo.RegionSize;
  1889. }
  1890. else {
  1891. PrivateCommit[ProtectionToIndex(VaInfo->BasicInfo.Protect)] += VaInfo->BasicInfo.RegionSize;
  1892. }
  1893. }
  1894. break;
  1895. case MEM_RESERVE :
  1896. if ( VaInfo->BasicInfo.Type == MEM_IMAGE ) {
  1897. ImageReservedBytes += VaInfo->BasicInfo.RegionSize;
  1898. }
  1899. else {
  1900. ReservedBytes += VaInfo->BasicInfo.RegionSize;
  1901. }
  1902. break;
  1903. case MEM_FREE :
  1904. if ( VaInfo->BasicInfo.Type == MEM_IMAGE ) {
  1905. ImageFreeBytes += VaInfo->BasicInfo.RegionSize;
  1906. }
  1907. else {
  1908. FreeBytes += VaInfo->BasicInfo.RegionSize;
  1909. }
  1910. break;
  1911. }
  1912. if ( LastAllocationBase ) {
  1913. //
  1914. // Normal case
  1915. //
  1916. //
  1917. // See if last one is 0, or if this one doesn't match the
  1918. // last one.
  1919. //
  1920. if ( LastAllocationBase->BasicInfo.AllocationBase == NULL ||
  1921. LastAllocationBase->BasicInfo.AllocationBase != VaInfo->BasicInfo.AllocationBase ) {
  1922. LastAllocationBase = VaInfo;
  1923. InsertTailList(&VaList,&VaInfo->Links);
  1924. InitializeListHead(&VaInfo->AllocationBaseHead);
  1925. }
  1926. else {
  1927. //
  1928. // Current Entry Matches
  1929. //
  1930. InsertTailList(&LastAllocationBase->AllocationBaseHead,&VaInfo->Links);
  1931. }
  1932. }
  1933. else {
  1934. LastAllocationBase = VaInfo;
  1935. InsertTailList(&VaList,&VaInfo->Links);
  1936. InitializeListHead(&VaInfo->AllocationBaseHead);
  1937. }
  1938. BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + VaInfo->BasicInfo.RegionSize);
  1939. }
  1940. }
  1941. PSZ
  1942. MemProtect(
  1943. IN ULONG Protection
  1944. )
  1945. {
  1946. switch ( Protection ) {
  1947. case PAGE_NOACCESS:
  1948. return "No Access";
  1949. case PAGE_READONLY:
  1950. return "Read Only";
  1951. case PAGE_READWRITE:
  1952. return "Read/Write";
  1953. case PAGE_WRITECOPY:
  1954. return "Write Copy";
  1955. case PAGE_EXECUTE:
  1956. return "Execute";
  1957. case PAGE_EXECUTE_READ:
  1958. return "Execute Read";
  1959. case PAGE_EXECUTE_READWRITE:
  1960. return "Execute Read/Write";
  1961. case PAGE_EXECUTE_WRITECOPY:
  1962. return "Execute Write Copy";
  1963. default :
  1964. if ( Protection & PAGE_GUARD ) {
  1965. switch ( Protection & 0xff ) {
  1966. case PAGE_NOACCESS:
  1967. return "-- GUARD -- No Access";
  1968. case PAGE_READONLY:
  1969. return "-- GUARD -- Read Only";
  1970. case PAGE_READWRITE:
  1971. return "-- GUARD -- Read/Write";
  1972. case PAGE_WRITECOPY:
  1973. return "-- GUARD -- Write Copy";
  1974. case PAGE_EXECUTE:
  1975. return "-- GUARD -- Execute";
  1976. case PAGE_EXECUTE_READ:
  1977. return "-- GUARD -- Execute Read";
  1978. case PAGE_EXECUTE_READWRITE:
  1979. return "-- GUARD -- Execute Read/Write";
  1980. case PAGE_EXECUTE_WRITECOPY:
  1981. return "-- GUARD -- Execute Write Copy";
  1982. default:
  1983. return "-- GUARD -- Unknown";
  1984. }
  1985. }
  1986. return "Unknown";
  1987. }
  1988. }
  1989. PSZ
  1990. MemState(
  1991. IN ULONG State
  1992. )
  1993. {
  1994. switch ( State ) {
  1995. case MEM_COMMIT :
  1996. return "Committed";
  1997. case MEM_RESERVE :
  1998. return "Reserved";
  1999. case MEM_FREE :
  2000. return "Free";
  2001. default:
  2002. return "Unknown State";
  2003. }
  2004. }
  2005. PSZ
  2006. MemType(
  2007. IN ULONG Type
  2008. )
  2009. {
  2010. switch ( Type ) {
  2011. case MEM_PRIVATE :
  2012. return "Private";
  2013. case MEM_MAPPED :
  2014. return "Mapped";
  2015. case MEM_IMAGE :
  2016. return "Image";
  2017. default:
  2018. return "Unknown Type";
  2019. }
  2020. }
  2021. VOID
  2022. DumpVaSpace(
  2023. VOID
  2024. )
  2025. {
  2026. PLIST_ENTRY Next;
  2027. PVAINFO VaInfo;
  2028. ULONG_PTR VirtualSize;
  2029. Next = VaList.Flink;
  2030. while ( Next != &VaList) {
  2031. VaInfo = (PVAINFO)(CONTAINING_RECORD(Next,VAINFO,Links));
  2032. printf("\n");
  2033. if ( !IsListEmpty(&VaInfo->AllocationBaseHead) ) {
  2034. PLIST_ENTRY xNext;
  2035. PVAINFO xVaInfo;
  2036. VirtualSize = VaInfo->BasicInfo.RegionSize;
  2037. xNext = VaInfo->AllocationBaseHead.Flink;
  2038. while ( xNext != &VaInfo->AllocationBaseHead) {
  2039. xVaInfo = (PVAINFO)(CONTAINING_RECORD(xNext,VAINFO,Links));
  2040. VirtualSize += xVaInfo->BasicInfo.RegionSize;
  2041. xNext = xNext->Flink;
  2042. }
  2043. }
  2044. else {
  2045. VirtualSize = 0;
  2046. }
  2047. printf("Address: %p Size: %p",
  2048. VaInfo->BasicInfo.BaseAddress,
  2049. VaInfo->BasicInfo.RegionSize);
  2050. if ( VirtualSize ) {
  2051. printf(" RegionSize: %lx\n",VirtualSize);
  2052. }
  2053. else {
  2054. printf("\n");
  2055. }
  2056. printf(" State %s\n",MemState(VaInfo->BasicInfo.State));
  2057. if ( VaInfo->BasicInfo.State == MEM_COMMIT ) {
  2058. printf(" Protect %s\n",MemProtect(VaInfo->BasicInfo.Protect));
  2059. }
  2060. if ( VaInfo->BasicInfo.State == MEM_COMMIT ||
  2061. VaInfo->BasicInfo.State == MEM_RESERVE ) {
  2062. printf(" Type %s\n",MemType(VaInfo->BasicInfo.Type));
  2063. }
  2064. if ( Options & OPTIONS_VERBOSE ) {
  2065. if ( !IsListEmpty(&VaInfo->AllocationBaseHead) ) {
  2066. PLIST_ENTRY xNext;
  2067. PVAINFO xVaInfo;
  2068. xNext = VaInfo->AllocationBaseHead.Flink;
  2069. while ( xNext != &VaInfo->AllocationBaseHead) {
  2070. xVaInfo = (PVAINFO)(CONTAINING_RECORD(xNext,VAINFO,Links));
  2071. printf("\n");
  2072. printf(" Address: %p Size: %p\n",
  2073. xVaInfo->BasicInfo.BaseAddress,
  2074. xVaInfo->BasicInfo.RegionSize
  2075. );
  2076. printf(" RegionSize %p\n",xVaInfo->BasicInfo.RegionSize);
  2077. printf(" State %s\n",MemState(xVaInfo->BasicInfo.State));
  2078. if ( xVaInfo->BasicInfo.State == MEM_COMMIT ) {
  2079. printf(" Protect %s\n",MemProtect(xVaInfo->BasicInfo.Protect));
  2080. }
  2081. if ( xVaInfo->BasicInfo.State == MEM_COMMIT ||
  2082. xVaInfo->BasicInfo.State == MEM_RESERVE ) {
  2083. printf(" Type %s\n",MemType(xVaInfo->BasicInfo.Type));
  2084. }
  2085. xNext = xNext->Flink;
  2086. }
  2087. }
  2088. }
  2089. Next = Next->Flink;
  2090. }
  2091. }
  2092. int
  2093. __cdecl
  2094. main(
  2095. int argc,
  2096. char *argv[],
  2097. char *envp[]
  2098. )
  2099. {
  2100. HANDLE Process;
  2101. OBJECT_ATTRIBUTES Obja;
  2102. UNICODE_STRING Unicode;
  2103. NTSTATUS Status;
  2104. LPSTR lpstrCmd;
  2105. CHAR ch;
  2106. ULONG_PTR Temp;
  2107. VM_COUNTERS VmCounters;
  2108. LPSTR p;
  2109. SYSTEM_BASIC_INFORMATION SystemInformation;
  2110. BOOL bEnabledDebugPriv;
  2111. UNREFERENCED_PARAMETER (envp);
  2112. ExeName = argv[0];
  2113. if (argc == 1) {
  2114. Usage();
  2115. }
  2116. if (!NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation,
  2117. &SystemInformation,
  2118. sizeof(SystemInformation),
  2119. NULL))) {
  2120. fprintf(stderr, "Failed to get system basic information\n");
  2121. return 1;
  2122. }
  2123. PageSize = SystemInformation.PageSize;
  2124. if (!NT_SUCCESS(NtQuerySystemInformation(SystemRangeStartInformation,
  2125. &SystemRangeStart,
  2126. sizeof(SystemRangeStart),
  2127. NULL))) {
  2128. // assume usermode is the low half of the address space
  2129. SystemRangeStart = (ULONG_PTR)MAXLONG_PTR;
  2130. }
  2131. #if defined (_X86_)
  2132. PteWidth = 4;
  2133. PteBase = (PVOID)0xC0000000;
  2134. #else
  2135. PteWidth = 8;
  2136. PteBase = (PVOID)0x1FFFFF0000000000;
  2137. #endif
  2138. if ((USER_SHARED_DATA) && (USER_SHARED_DATA->ProcessorFeatures[PF_PAE_ENABLED])) {
  2139. PteWidth = 8;
  2140. }
  2141. PtesPerPage = PageSize / PteWidth;
  2142. VaMappedByPageTable = PtesPerPage * PageSize;
  2143. UserPteMax = (PVOID)((ULONG_PTR)PteBase + (SystemRangeStart / PageSize) * PteWidth);
  2144. ThisSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
  2145. ThisSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  2146. ProcessId = 0;
  2147. GetSystemInfo(&SystemInfo);
  2148. ConvertAppToOem( argc, argv );
  2149. lpstrCmd = GetCommandLine();
  2150. if( lpstrCmd != NULL ) {
  2151. CharToOem( lpstrCmd, lpstrCmd );
  2152. }
  2153. do {
  2154. ch = *lpstrCmd++;
  2155. } while (ch != ' ' && ch != '\t' && ch != '\0');
  2156. while (ch == ' ' || ch == '\t') {
  2157. ch = *lpstrCmd++;
  2158. }
  2159. while (ch == '-') {
  2160. ch = *lpstrCmd++;
  2161. // process multiple switch characters as needed
  2162. do {
  2163. switch (ch) {
  2164. case '?':
  2165. Usage();
  2166. case 'C':
  2167. case 'c':
  2168. Options |= OPTIONS_CODE_TOO;
  2169. ch = *lpstrCmd++;
  2170. break;
  2171. case 'F':
  2172. case 'f':
  2173. fFast = TRUE;
  2174. ch = *lpstrCmd++;
  2175. break;
  2176. case 'L':
  2177. case 'l':
  2178. //
  2179. // l takes log-file-name as argument.
  2180. //
  2181. do
  2182. ch = *lpstrCmd++;
  2183. while (ch == ' ' || ch == '\t');
  2184. p = LogFileName;
  2185. while (ch && (ch != ' ' && ch != '\t')) {
  2186. *p++ = ch;
  2187. ch = *lpstrCmd++;
  2188. }
  2189. LogFile = fopen(LogFileName,"wt");
  2190. break;
  2191. case 'M':
  2192. case 'm':
  2193. Options |= OPTIONS_RAW_SYMBOLS;
  2194. ch = *lpstrCmd++;
  2195. break;
  2196. case 'P':
  2197. case 'p':
  2198. //
  2199. // pid takes a decimal argument.
  2200. //
  2201. do {
  2202. ch = *lpstrCmd++;
  2203. } while (ch == ' ' || ch == '\t');
  2204. if (ch == '-') {
  2205. ch = *lpstrCmd++;
  2206. if (ch == '1') {
  2207. ProcessId = 0xffffffff;
  2208. ch = *lpstrCmd++;
  2209. }
  2210. }
  2211. else {
  2212. while (ch >= '0' && ch <= '9') {
  2213. Temp = ProcessId * 10 + ch - '0';
  2214. if (Temp < ProcessId) {
  2215. fprintf(stderr, "pid number overflow\n");
  2216. ExitProcess(1);
  2217. }
  2218. ProcessId = Temp;
  2219. ch = *lpstrCmd++;
  2220. }
  2221. }
  2222. if (!ProcessId) {
  2223. fprintf(stderr, "bad pid '%ld'\n", ProcessId);
  2224. ExitProcess(1);
  2225. }
  2226. break;
  2227. case 'R':
  2228. case 'r':
  2229. fRunning = TRUE;
  2230. ch = *lpstrCmd++;
  2231. break;
  2232. case 'S':
  2233. case 's':
  2234. fSummary = TRUE;
  2235. ch = *lpstrCmd++;
  2236. break;
  2237. case 'T':
  2238. case 't':
  2239. Options |= OPTIONS_PAGE_TABLES;
  2240. ch = *lpstrCmd++;
  2241. break;
  2242. case 'O':
  2243. case 'o':
  2244. Options |= OPTIONS_WORKING_SET_OLD;
  2245. //
  2246. // Fall through ...
  2247. //
  2248. case 'W':
  2249. case 'w':
  2250. Options |= OPTIONS_WORKING_SET;
  2251. ch = *lpstrCmd++;
  2252. break;
  2253. case 'V':
  2254. case 'v':
  2255. Options |= OPTIONS_VERBOSE;
  2256. ch = *lpstrCmd++;
  2257. break;
  2258. default:
  2259. Usage();
  2260. }
  2261. } while (ch != ' ' && ch != '\t' && ch != '\0');
  2262. // skip over any following white space
  2263. while (ch == ' ' || ch == '\t') {
  2264. ch = *lpstrCmd++;
  2265. }
  2266. }
  2267. //
  2268. // try to enable SeDebugPrivilege to allow opening any process
  2269. //
  2270. bEnabledDebugPriv = TRUE;
  2271. if (!SetCurrentPrivilege(SE_DEBUG_NAME, &bEnabledDebugPriv)) {
  2272. fprintf(stderr, "Failed to set debug privilege\n");
  2273. return 1;
  2274. }
  2275. if ( ProcessId == 0 || ProcessId == 0xffffffff ) {
  2276. ProcessId = 0xffffffff;
  2277. RtlInitUnicodeString(&Unicode,L"\\WindowsSS");
  2278. InitializeObjectAttributes(
  2279. &Obja,
  2280. &Unicode,
  2281. 0,
  2282. NULL,
  2283. NULL
  2284. );
  2285. Status = NtOpenProcess(
  2286. &Process,
  2287. MAXIMUM_ALLOWED, //PROCESS_VM_READ | PROCESS_VM_OPERATION | PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION,
  2288. &Obja,
  2289. NULL
  2290. );
  2291. if ( !NT_SUCCESS(Status) ) {
  2292. fprintf(stderr, "OpenProcess Failed %lx\n",Status);
  2293. return 1;
  2294. }
  2295. }
  2296. else {
  2297. Process = OpenProcess (PROCESS_ALL_ACCESS,FALSE, (ULONG)ProcessId);
  2298. if ( !Process ) {
  2299. fprintf(stderr, "OpenProcess %ld failed %lx\n",ProcessId,GetLastError());
  2300. return 1;
  2301. }
  2302. }
  2303. if (Options & OPTIONS_WORKING_SET_OLD) {
  2304. CaptureWorkingSet (Process);
  2305. LoadTheHeaps (Process);
  2306. LoadTheThreads (Process, ProcessId);
  2307. }
  2308. ComputeModInfo (Process, ProcessId);
  2309. CaptureVaSpace (Process);
  2310. //
  2311. // disable the SeDebugPrivilege if we enabled it above
  2312. //
  2313. if(bEnabledDebugPriv) {
  2314. bEnabledDebugPriv = FALSE;
  2315. SetCurrentPrivilege (SE_DEBUG_NAME, &bEnabledDebugPriv);
  2316. }
  2317. if (Options & OPTIONS_WORKING_SET) {
  2318. if (Options & OPTIONS_WORKING_SET_OLD) {
  2319. DumpWorkingSetSnapshot (Process);
  2320. }
  2321. else {
  2322. DumpWorkingSet (Process);
  2323. }
  2324. return 1;
  2325. }
  2326. if ( !fSummary ) {
  2327. DumpVaSpace();
  2328. }
  2329. DumpCommit(" Image",ImageCommit);
  2330. DumpModInfo();
  2331. DumpCommit("Mapped",MappedCommit);
  2332. DumpCommit(" Priv",PrivateCommit);
  2333. printf("\n");
  2334. printf("Dynamic Reserved Memory %ld\n",
  2335. ReservedBytes
  2336. );
  2337. Status = NtQueryInformationProcess(
  2338. Process,
  2339. ProcessVmCounters,
  2340. (PVOID)&VmCounters,
  2341. sizeof(VmCounters),
  2342. NULL
  2343. );
  2344. if ( !NT_SUCCESS(Status) ) {
  2345. return 1;
  2346. }
  2347. printf("\n");
  2348. printf("PageFaults: %9ld\n",VmCounters.PageFaultCount);
  2349. printf("PeakWorkingSetSize %9ld\n",VmCounters.PeakWorkingSetSize);
  2350. printf("WorkingSetSize %9ld\n",VmCounters.WorkingSetSize);
  2351. printf("PeakPagedPoolUsage %9ld\n",VmCounters.QuotaPeakPagedPoolUsage);
  2352. printf("PagedPoolUsage %9ld\n",VmCounters.QuotaPagedPoolUsage);
  2353. printf("PeakNonPagedPoolUsage %9ld\n",VmCounters.QuotaPeakNonPagedPoolUsage);
  2354. printf("NonPagedPoolUsage %9ld\n",VmCounters.QuotaNonPagedPoolUsage);
  2355. printf("PagefileUsage %9ld\n",VmCounters.PagefileUsage);
  2356. printf("PeakPagefileUsage %9ld\n",VmCounters.PeakPagefileUsage);
  2357. return 0;
  2358. }
  2359. VOID
  2360. Usage (
  2361. VOID
  2362. )
  2363. {
  2364. fprintf(stderr, "Usage:\n"
  2365. " Dump the address space:\n"
  2366. " %s [-sv] -p decimal_process_id\n"
  2367. "\n"
  2368. " Dump the current workingset:\n"
  2369. " %s -o [-msv] [-l logfile] -p decimal_process_id\n"
  2370. "\n"
  2371. " Dump new additions to the workingset (Stop with ^C):\n"
  2372. " %s -w [-crv] [-l logfile] -p decimal_process_id\n"
  2373. "\n"
  2374. " -c Include code faults faulting PC summary\n"
  2375. " -m Show all code symbols on page\n"
  2376. " -o Workingset snapshot w/ summary\n"
  2377. " -r Print info on individual faults\n"
  2378. " -s Summary info only\n"
  2379. " -t Include pagetable info in summary\n"
  2380. " -w Track new working set additions\n"
  2381. " -v Verbose\n",
  2382. ExeName,
  2383. ExeName,
  2384. ExeName);
  2385. ExitProcess(1);
  2386. }
  2387. LOGICAL
  2388. SetCurrentPrivilege (
  2389. IN LPCTSTR Privilege, // Privilege to enable/disable
  2390. IN OUT BOOL *bEnablePrivilege // to enable or disable privilege
  2391. )
  2392. /*
  2393. If successful, *bEnablePrivlege is set to the new state.
  2394. If NOT successful, bEnablePrivlege is invalid
  2395. Returns:
  2396. TRUE - success
  2397. FALSE - failure
  2398. */
  2399. {
  2400. HANDLE hToken;
  2401. TOKEN_PRIVILEGES tp;
  2402. LUID luid;
  2403. TOKEN_PRIVILEGES tpPrevious;
  2404. DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
  2405. LOGICAL bSuccess;
  2406. BOOL bEnableIt;
  2407. bEnableIt = *bEnablePrivilege;
  2408. if (!LookupPrivilegeValue(NULL, Privilege, &luid)) {
  2409. return FALSE;
  2410. }
  2411. if(!OpenProcessToken(
  2412. GetCurrentProcess(),
  2413. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  2414. &hToken
  2415. )) {
  2416. return FALSE;
  2417. }
  2418. //
  2419. // first pass. get current privilege setting
  2420. //
  2421. tp.PrivilegeCount = 1;
  2422. tp.Privileges[0].Luid = luid;
  2423. tp.Privileges[0].Attributes = 0;
  2424. AdjustTokenPrivileges(
  2425. hToken,
  2426. FALSE,
  2427. &tp,
  2428. sizeof(TOKEN_PRIVILEGES),
  2429. &tpPrevious,
  2430. &cbPrevious
  2431. );
  2432. bSuccess = FALSE;
  2433. if(GetLastError() == ERROR_SUCCESS) {
  2434. //
  2435. // second pass. set privilege based on previous setting
  2436. //
  2437. tpPrevious.PrivilegeCount = 1;
  2438. tpPrevious.Privileges[0].Luid = luid;
  2439. *bEnablePrivilege = tpPrevious.Privileges[0].Attributes | (SE_PRIVILEGE_ENABLED);
  2440. if(bEnableIt) {
  2441. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  2442. }
  2443. else {
  2444. tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
  2445. tpPrevious.Privileges[0].Attributes);
  2446. }
  2447. AdjustTokenPrivileges(
  2448. hToken,
  2449. FALSE,
  2450. &tpPrevious,
  2451. cbPrevious,
  2452. NULL,
  2453. NULL
  2454. );
  2455. if (GetLastError() == ERROR_SUCCESS) {
  2456. bSuccess=TRUE;
  2457. }
  2458. }
  2459. CloseHandle(hToken);
  2460. return bSuccess;
  2461. }