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.

5880 lines
176 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. memory.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Lou Perazzoli (loup)
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define PACKET_MAX_SIZE 4000
  16. #define USAGE_ALLOC_SIZE 256*1024
  17. #ifdef _KB
  18. #undef _KB
  19. #endif
  20. #define _KB (PageSize/1024)
  21. #define PFN_MAPPED_FILE 0x1
  22. #define PFN_MAPPED_PAGEFILE 0x2
  23. #define PFN_PRIVATE 0x4
  24. #define PFN_AWE 0x8
  25. typedef struct _PFN_INFO {
  26. ULONG64 Master;
  27. ULONG64 OriginalPte;
  28. ULONG Type;
  29. ULONG ValidCount;
  30. ULONG StandbyCount;
  31. ULONG ModifiedCount;
  32. ULONG SharedCount;
  33. ULONG LockedCount;
  34. ULONG PageTableCount;
  35. struct _PFN_INFO *Next;
  36. } PFN_INFO, *PPFN_INFO;
  37. typedef struct _KERN_MAP1 {
  38. ULONG64 StartVa;
  39. ULONG64 EndVa;
  40. ULONG ValidCount;
  41. ULONG StandbyCount;
  42. ULONG ModifiedCount;
  43. ULONG SharedCount;
  44. ULONG LockedCount;
  45. ULONG PageTableCount;
  46. WCHAR Name[256];
  47. } KERN_MAP1, *PKERN_MAP1;
  48. typedef struct _KERN_MAP {
  49. ULONG Count;
  50. KERN_MAP1 Item[500];
  51. } KERN_MAP, *PKERN_MAP;
  52. typedef struct _MMPFN_READ {
  53. MMPFNENTRY u3_e1;
  54. ULONG u3_e2_ReferenceCount;
  55. ULONG64 u1_Flink, u2_Blink, PteAddress, OriginalPte, PteFrame;
  56. } MMPFN_READ, *PMMPFN_READ;
  57. typedef struct _PFN_DUMP_CTXT {
  58. BOOL PrintIndex;
  59. ULONG64 index;
  60. BOOL ZeroAfterPrint;
  61. PMMPFN_READ pReadPfn;
  62. } PFN_DUMP_CTXT, *PPFN_DUMP_CTXT;
  63. UCHAR *PageLocationList[] = {
  64. (PUCHAR)"Zeroed ",
  65. (PUCHAR)"Free ",
  66. (PUCHAR)"Standby ",
  67. (PUCHAR)"Modified",
  68. (PUCHAR)"ModNoWrt",
  69. (PUCHAR)"Bad ",
  70. (PUCHAR)"Active ",
  71. (PUCHAR)"Trans "
  72. };
  73. UCHAR *PageAttribute[] = {
  74. (PUCHAR)"NonCached",
  75. (PUCHAR)"Cached ",
  76. (PUCHAR)"WriteComb",
  77. (PUCHAR)"NotMapped"
  78. };
  79. ULONG64 MmSubsectionBase;
  80. ULONG64 MaxDirbase;
  81. #define MAX_DIRBASEVECTOR 256
  82. ULONG64 DirBases[MAX_DIRBASEVECTOR];
  83. UCHAR Names[MAX_DIRBASEVECTOR][64];
  84. VOID
  85. FileTimeToString(
  86. IN LARGE_INTEGER Time,
  87. IN BOOLEAN TimeZone,
  88. OUT PCHAR Buffer
  89. );
  90. VOID
  91. PrintPfn64 (
  92. IN ULONG64 PfnAddress
  93. );
  94. VOID
  95. DumpMmThreads (
  96. VOID
  97. );
  98. VOID DumpWholePfn(
  99. IN ULONG64 Address,
  100. IN ULONG Flags
  101. );
  102. PUCHAR
  103. DirbaseToImage(
  104. IN ULONG64 DirBase
  105. );
  106. NTSTATUS
  107. BuildDirbaseList( VOID );
  108. LOGICAL
  109. BuildKernelMap (
  110. OUT PKERN_MAP KernelMap
  111. );
  112. ULONG
  113. DbgGetPfnSize(
  114. VOID
  115. )
  116. {
  117. return GetTypeSize("nt!_MMPFN");
  118. }
  119. ULONG
  120. DumpModifiedNoWriteInformation (
  121. ULONG Flags
  122. );
  123. ULONG64
  124. READ_PVOID (
  125. ULONG64 Address
  126. );
  127. typedef struct _MEMORY_RUN {
  128. ULONG64 BasePage;
  129. ULONG64 LastPage;
  130. } MEMORY_RUN, *PMEMORY_RUN;
  131. void
  132. GetVersionedMmPfnMembers (
  133. ULONG64 Pfn,
  134. PULONG64 PteFrame,
  135. PCHAR InPageError
  136. )
  137. {
  138. if (BuildNo >= 2440) {
  139. GetFieldValue(Pfn, "nt!_MMPFN", "u4.PteFrame", *PteFrame);
  140. if (InPageError) {
  141. GetFieldValue(Pfn, "nt!_MMPFN", "u4.InPageError", *InPageError);
  142. }
  143. } else {
  144. GetFieldValue(Pfn, "nt!_MMPFN", "PteFrame", *PteFrame);
  145. if (InPageError) {
  146. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1.InPageError", *InPageError);
  147. }
  148. }
  149. }
  150. DECLARE_API( memusage )
  151. /*++
  152. Routine Description:
  153. Dumps the page frame database table
  154. Arguments:
  155. arg -
  156. Return Value:
  157. None.
  158. --*/
  159. {
  160. ULONG i;
  161. ULONG result;
  162. ULONG64 PfnDb;
  163. ULONG64 HighPageAddr;
  164. ULONG64 LowPageAddr;
  165. ULONG64 HighPage=0;
  166. ULONG64 LowPage=0;
  167. ULONG64 PageCount;
  168. ULONG64 ReadCount;
  169. ULONG WasZeroedPage;
  170. ULONG WasFreePage;
  171. ULONG Total;
  172. ULONG WasStandbyPage;
  173. ULONG WasModifiedPage;
  174. ULONG WasModifiedNoWritePage;
  175. ULONG WasBadPage;
  176. ULONG WasActiveAndValidPage;
  177. ULONG WasTransitionPage;
  178. ULONG WasUnknownPage;
  179. ULONG64 NPPoolStart;
  180. ULONG64 NPSystemStart;
  181. ULONG64 Pfn;
  182. ULONG64 PfnStart;
  183. PCHAR PfnArray;
  184. ULONG PfnSize;
  185. ULONG NumberOfPfnToRead;
  186. ULONG CompleteSoFar = (ULONG) ~0;
  187. ULONG64 CacheSize;
  188. ULONG Flags;
  189. INIT_API();
  190. Flags = (ULONG) GetExpression(args);
  191. if (Flags & 3) {
  192. EXIT_API();
  193. return DumpModifiedNoWriteInformation (Flags);
  194. }
  195. LowPageAddr = GetNtDebuggerData(MmLowestPhysicalPage);
  196. HighPageAddr = GetNtDebuggerData(MmHighestPhysicalPage);
  197. PfnDb = GetNtDebuggerData(MmPfnDatabase);
  198. NPPoolStart = GetNtDebuggerData(MmNonPagedPoolStart);
  199. NPSystemStart = GetNtDebuggerData(MmNonPagedSystemStart);
  200. PfnSize = GetTypeSize("nt!_MMPFN");
  201. NumberOfPfnToRead = 300;
  202. if ( LowPageAddr &&
  203. HighPageAddr &&
  204. PfnDb &&
  205. NPPoolStart &&
  206. NPSystemStart ) {
  207. ULONG64 MemoryDescriptorAddress;
  208. ULONG NumberOfRuns;
  209. ULONG Offset, Size;
  210. PMEMORY_RUN PhysicalMemoryBlock;
  211. MemoryDescriptorAddress = READ_PVOID (GetExpression ("nt!MmPhysicalMemoryBlock"));
  212. InitTypeRead (MemoryDescriptorAddress, nt!_PHYSICAL_MEMORY_DESCRIPTOR);
  213. NumberOfRuns = (ULONG) ReadField (NumberOfRuns);
  214. PhysicalMemoryBlock = LocalAlloc(LPTR, NumberOfRuns * sizeof (MEMORY_RUN));
  215. if (PhysicalMemoryBlock == NULL) {
  216. dprintf("LocalAlloc failed\n");
  217. return S_OK;
  218. }
  219. Size = GetTypeSize("nt!_PHYSICAL_MEMORY_RUN");
  220. GetFieldOffset("nt!_PHYSICAL_MEMORY_DESCRIPTOR", "Run", &Offset);
  221. for (i = 0; i < NumberOfRuns; i += 1) {
  222. InitTypeRead(MemoryDescriptorAddress+Offset+i*Size,nt!_PHYSICAL_MEMORY_RUN);
  223. PhysicalMemoryBlock[i].BasePage = (ULONG64) ReadField (BasePage);
  224. PhysicalMemoryBlock[i].LastPage = (ULONG64) ReadField (PageCount) +
  225. PhysicalMemoryBlock[i].BasePage;
  226. }
  227. if ( !ReadPointer( LowPageAddr, &LowPage) ) {
  228. dprintf("%08p: Unable to get low physical page\n",LowPageAddr);
  229. LocalFree(PhysicalMemoryBlock);
  230. EXIT_API();
  231. return E_INVALIDARG;
  232. }
  233. if ( !ReadPointer( HighPageAddr,&HighPage) ) {
  234. dprintf("%08p: Unable to get high physical page\n",HighPageAddr);
  235. LocalFree(PhysicalMemoryBlock);
  236. EXIT_API();
  237. return E_INVALIDARG;
  238. }
  239. if ( !ReadPointer( PfnDb,&PfnStart) ) {
  240. dprintf("%08p: Unable to get PFN database address\n",PfnDb);
  241. LocalFree(PhysicalMemoryBlock);
  242. EXIT_API();
  243. return E_INVALIDARG;
  244. }
  245. #ifdef IG_GET_CACHE_SIZE
  246. if (!TargetIsDump && !IsLocalKd) {
  247. Ioctl (IG_GET_CACHE_SIZE, &CacheSize, sizeof(CacheSize));
  248. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  249. if (CacheSize < 0x10000000) {
  250. dprintf("\nCacheSize too low - increasing to 10M");
  251. ExecuteCommand(Client, ".cache 10000");
  252. }
  253. } else if (CacheSize < 0x1000000) {
  254. dprintf("\nCacheSize too low - increasing to 1M");
  255. ExecuteCommand(Client, ".cache 1000");
  256. }
  257. }
  258. #endif
  259. dprintf(" loading PFN database\n");
  260. PfnArray = VirtualAlloc ( NULL,
  261. (ULONG) ((HighPage-LowPage+1) * PfnSize),
  262. MEM_RESERVE | MEM_COMMIT,
  263. PAGE_READWRITE);
  264. if (!PfnArray) {
  265. dprintf("Unable to get allocate memory of %I64ld bytes\n",
  266. (HighPage+1) * PfnSize);
  267. } else {
  268. for (PageCount = LowPage;
  269. PageCount <= HighPage;
  270. PageCount += NumberOfPfnToRead) {
  271. //dprintf("getting PFN table block - "
  272. // "address %lx - count %lu - page %lu\n",
  273. // Pfn, ReadCount, PageCount);
  274. if ( CheckControlC() ) {
  275. VirtualFree (PfnArray,0,MEM_RELEASE);
  276. LocalFree(PhysicalMemoryBlock);
  277. EXIT_API();
  278. return E_INVALIDARG;
  279. }
  280. ReadCount = HighPage - PageCount > NumberOfPfnToRead ?
  281. NumberOfPfnToRead :
  282. HighPage - PageCount + 1;
  283. ReadCount *= PfnSize;
  284. Pfn = (PfnStart + PageCount * PfnSize);
  285. if (CompleteSoFar != (ULONG) (((PageCount + LowPage) * 100)/ HighPage)) {
  286. CompleteSoFar = (ULONG) (((PageCount + LowPage) * 100)/ HighPage);
  287. dprintf("loading (%d%% complete)\r", CompleteSoFar);
  288. }
  289. // Let KD cache the data - we won't be reading from the array.
  290. if ( !ReadMemory( Pfn,
  291. PfnArray + PageCount * PfnSize,
  292. (ULONG) ReadCount,
  293. &result) ) {
  294. dprintf("Unable to get PFN table block - "
  295. "address %p - count %lu - page %lu\n",
  296. Pfn, ReadCount, PageCount);
  297. VirtualFree (PfnArray,0,MEM_RELEASE);
  298. LocalFree(PhysicalMemoryBlock);
  299. EXIT_API();
  300. return E_INVALIDARG;
  301. }
  302. }
  303. dprintf("\n");
  304. // Now we have a local copy: let's take a look
  305. WasZeroedPage = 0;
  306. WasFreePage = 0;
  307. WasStandbyPage = 0;
  308. WasModifiedPage = 0;
  309. WasModifiedNoWritePage = 0;
  310. WasBadPage = 0;
  311. WasActiveAndValidPage = 0;
  312. WasTransitionPage = 0;
  313. WasUnknownPage = 0;
  314. CompleteSoFar = 0;
  315. for (PageCount = LowPage;
  316. PageCount <= HighPage;
  317. PageCount++) {
  318. ULONG PageLocation=0;
  319. ULONG64 Flink=0, Blink=0;
  320. if ( CheckControlC() ) {
  321. VirtualFree (PfnArray,0,MEM_RELEASE);
  322. LocalFree(PhysicalMemoryBlock);
  323. EXIT_API();
  324. return E_INVALIDARG;
  325. }
  326. if (CompleteSoFar < (ULONG) (((PageCount + LowPage) * 100)/ HighPage)) {
  327. CompleteSoFar = (ULONG) (((PageCount + LowPage) * 100)/ HighPage);
  328. dprintf("Compiling memory usage data (%d%% Complete).\r", CompleteSoFar);
  329. }
  330. for (i = 0; i < NumberOfRuns; i += 1) {
  331. if ((PageCount >= PhysicalMemoryBlock[i].BasePage) &&
  332. (PageCount < PhysicalMemoryBlock[i].LastPage)) {
  333. break;
  334. }
  335. }
  336. if (i == NumberOfRuns) {
  337. //
  338. // Skip PFNs that don't exist (ie: that aren't in
  339. // the MmPhysicalMemoryBlock).
  340. //
  341. continue;
  342. }
  343. Pfn = (PfnStart + PageCount * PfnSize);
  344. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1.PageLocation", PageLocation);
  345. switch (PageLocation) {
  346. case ZeroedPageList:
  347. GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", Flink);
  348. GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", Blink);
  349. if ((Flink == 0) &&
  350. (Blink == 0)) {
  351. WasActiveAndValidPage++;
  352. } else {
  353. WasZeroedPage++;
  354. }
  355. break;
  356. case FreePageList:
  357. WasFreePage++;
  358. break;
  359. case StandbyPageList:
  360. WasStandbyPage++;
  361. break;
  362. case ModifiedPageList:
  363. WasModifiedPage++;
  364. break;
  365. case ModifiedNoWritePageList:
  366. WasModifiedNoWritePage++;
  367. break;
  368. case BadPageList:
  369. WasModifiedNoWritePage++;
  370. break;
  371. case ActiveAndValid:
  372. WasActiveAndValidPage++;
  373. break;
  374. case TransitionPage:
  375. WasTransitionPage++;
  376. break;
  377. default:
  378. WasUnknownPage++;
  379. break;
  380. }
  381. }
  382. dprintf("\n");
  383. dprintf( " Zeroed: %6lu (%6lu kb)\n",
  384. WasZeroedPage, WasZeroedPage * _KB);
  385. dprintf( " Free: %6lu (%6lu kb)\n",
  386. WasFreePage, WasFreePage * _KB);
  387. dprintf( " Standby: %6lu (%6lu kb)\n",
  388. WasStandbyPage, WasStandbyPage * _KB);
  389. dprintf( " Modified: %6lu (%6lu kb)\n",
  390. WasModifiedPage,
  391. WasModifiedPage * _KB);
  392. dprintf( " ModifiedNoWrite: %6lu (%6lu kb)\n",
  393. WasModifiedNoWritePage,WasModifiedNoWritePage * _KB);
  394. dprintf( " Active/Valid: %6lu (%6lu kb)\n",
  395. WasActiveAndValidPage, WasActiveAndValidPage * _KB);
  396. dprintf( " Transition: %6lu (%6lu kb)\n",
  397. WasTransitionPage, WasTransitionPage * _KB);
  398. dprintf( " Unknown: %6lu (%6lu kb)\n",
  399. WasUnknownPage, WasUnknownPage * _KB);
  400. Total = WasZeroedPage +
  401. WasFreePage +
  402. WasStandbyPage +
  403. WasModifiedPage +
  404. WasModifiedNoWritePage +
  405. WasActiveAndValidPage +
  406. WasTransitionPage +
  407. WasUnknownPage +
  408. WasUnknownPage;
  409. dprintf( " TOTAL: %6lu (%6lu kb)\n",
  410. Total, Total * _KB);
  411. }
  412. MemoryUsage (PfnStart, LowPage, HighPage, 0);
  413. VirtualFree (PfnArray,0,MEM_RELEASE);
  414. LocalFree(PhysicalMemoryBlock);
  415. }
  416. EXIT_API();
  417. return S_OK;
  418. }
  419. DECLARE_API( lockedpages )
  420. /*++
  421. Routine Description:
  422. Displays the driver-locked pages.
  423. Arguments:
  424. None.
  425. Return Value:
  426. None.
  427. --*/
  428. {
  429. #if 0
  430. ULONG64 LockHeader;
  431. ULONG64 LockTracker;
  432. ULONG64 NextEntry;
  433. ULONG GlistOff;
  434. ULONG64 Count;
  435. CHAR Buffer[256];
  436. ULONG64 displacement;
  437. UNREFERENCED_PARAMETER (args);
  438. UNREFERENCED_PARAMETER (Client);
  439. LockHeader = GetExpression ("nt!MmLockedPagesHead");
  440. if (GetFieldValue(LockHeader,
  441. "nt!_LOCK_HEADER",
  442. "Count",
  443. Count)) {
  444. dprintf("%08p: Unable to get lock header data.\n", LockHeader);
  445. return E_INVALIDARG;
  446. }
  447. GetFieldValue(LockHeader,"nt!_LOCK_HEADER","ListHead.Flink", NextEntry);
  448. if (NextEntry == 0) {
  449. dprintf("Locked pages tracking not enabled\n");
  450. return E_INVALIDARG;
  451. }
  452. if (NextEntry == LockHeader) {
  453. dprintf("There are no pages currently locked.\n");
  454. return E_INVALIDARG;
  455. }
  456. dprintf("%I64d locked pages...\n", Count);
  457. dprintf("Tracker MDL PageCount Caller/CallersCaller\n");
  458. GetFieldOffset("LOCK_TRACKER", "GlobalListEntry", &GlistOff);
  459. while (NextEntry != LockHeader) {
  460. LockTracker = (NextEntry - GlistOff);
  461. if (GetFieldValue(LockTracker, "nt!LOCK_TRACKER",
  462. "GlobalListEntry.Flink", NextEntry)) {
  463. dprintf("%08p: Unable to get lock tracker data.\n", LockTracker);
  464. return E_INVALIDARG;
  465. }
  466. InitTypeRead(LockTracker, nt!LOCK_TRACKER);
  467. //old way...
  468. //dprintf("Tracker %p : MDL @ %p, PageCount = %I64x, Caller = %p %p\n",
  469. dprintf("%16p %5p %10I64x ",
  470. LockTracker,
  471. ReadField(Mdl),
  472. ReadField(Count));
  473. Buffer[0] = '!';
  474. GetSymbol (ReadField(CallingAddress),
  475. (PCHAR)Buffer,
  476. &displacement);
  477. dprintf("%s", Buffer);
  478. if (displacement) {
  479. dprintf( "+0x%1p", displacement );
  480. }
  481. dprintf("/");
  482. Buffer[0] = '!';
  483. GetSymbol (ReadField(CallersCaller),
  484. (PCHAR)Buffer,
  485. &displacement);
  486. dprintf("%s", Buffer);
  487. if (displacement) {
  488. dprintf( "+0x%1p", displacement );
  489. }
  490. dprintf("\n");
  491. if (CheckControlC()) {
  492. break;
  493. }
  494. }
  495. #else
  496. dprintf ("This command is no longer supported.\n");
  497. #endif
  498. return S_OK;
  499. }
  500. DECLARE_API( pfnperf )
  501. /*++
  502. Routine Description:
  503. Displays the PFN spinlock duration list.
  504. Arguments:
  505. None.
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. ULONG64 PfnDuration;
  511. ULONG64 PfnEntry;
  512. ULONG64 displacement;
  513. ULONG64 AcquiredAddress;
  514. ULONG64 ReleasedAddress;
  515. CHAR SymbolBuffer[MAX_PATH];
  516. PCHAR SymPointer;
  517. ULONG EntrySize;
  518. ULONG result;
  519. ULONG64 ReadCount;
  520. ULONG64 i;
  521. PCHAR LocalData;
  522. PCHAR local;
  523. ULONG64 NumberOfPfnEntries;
  524. UNREFERENCED_PARAMETER (args);
  525. UNREFERENCED_PARAMETER (Client);
  526. PfnDuration = GetExpression ("nt!MiPfnSorted");
  527. if (PfnDuration == 0) {
  528. dprintf("%08p: Unable to get PFN duration data.\n", PfnDuration);
  529. return E_INVALIDARG;
  530. }
  531. PfnEntry = PfnDuration;
  532. EntrySize = GetTypeSize("nt!_MMPFNTIMINGS");
  533. NumberOfPfnEntries = GetUlongValue ("nt!MiMaxPfnTimings");
  534. dprintf("Top %ld PFN lock holders sorted by duration\n", NumberOfPfnEntries);
  535. LocalData = LocalAlloc(LPTR, (ULONG) (NumberOfPfnEntries * EntrySize));
  536. if (!LocalData) {
  537. dprintf("unable to get allocate %ld bytes of memory\n",
  538. NumberOfPfnEntries * EntrySize);
  539. return E_INVALIDARG;
  540. }
  541. ReadCount = NumberOfPfnEntries * EntrySize;
  542. if ((!ReadMemory(PfnDuration,
  543. LocalData,
  544. (ULONG) ReadCount,
  545. &result)) || (result < (ULONG) ReadCount)) {
  546. dprintf("unable to get PFN duration table - "
  547. "address %p - count %I64u\n",
  548. LocalData, ReadCount);
  549. }
  550. else {
  551. dprintf("\nDuration LockAcquirer LockReleaser\n");
  552. local = LocalData;
  553. for (i = 0; i < NumberOfPfnEntries; i += 1) {
  554. ULONG64 HoldTime=0, Address = 0;
  555. GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "HoldTime", HoldTime);
  556. GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "AcquiredAddress", AcquiredAddress);
  557. GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "ReleasedAddress", ReleasedAddress);
  558. //
  559. // Sign extend if necessary.
  560. //
  561. if (!IsPtr64()) {
  562. AcquiredAddress = (ULONG64)(LONG64)(LONG)AcquiredAddress;
  563. ReleasedAddress = (ULONG64)(LONG64)(LONG)ReleasedAddress;
  564. }
  565. //
  566. // Output a '*' if the lock was contended for, '.' if not.
  567. //
  568. dprintf( "%3d%c %I64ld ", (ULONG)i, HoldTime & 0x1 ? '*' : '.', HoldTime );
  569. SymbolBuffer[0] = '!';
  570. GetSymbol(AcquiredAddress, (PCHAR)SymbolBuffer, &displacement);
  571. SymPointer = SymbolBuffer;
  572. while (*SymPointer != '!') {
  573. SymPointer += 1;
  574. }
  575. SymPointer += 1;
  576. dprintf ("%s", SymPointer);
  577. if (displacement) {
  578. dprintf( "+0x%x", displacement );
  579. }
  580. dprintf( ", ");
  581. SymbolBuffer[0] = '!';
  582. GetSymbol(ReleasedAddress, (PCHAR)SymbolBuffer, &displacement);
  583. SymPointer = SymbolBuffer;
  584. while (*SymPointer != '!') {
  585. SymPointer += 1;
  586. }
  587. SymPointer += 1;
  588. dprintf ("%s", SymPointer);
  589. if (displacement) {
  590. dprintf( "+0x%x", displacement );
  591. }
  592. dprintf( "\n");
  593. PfnEntry += EntrySize;
  594. }
  595. }
  596. if (LocalData) {
  597. LocalFree((void *)LocalData);
  598. }
  599. return S_OK;
  600. }
  601. DECLARE_API( pfn )
  602. /*++
  603. Routine Description:
  604. Displays the corresponding PDE and PTE.
  605. Arguments:
  606. arg - Supplies the Page frame number in hex.
  607. Return Value:
  608. None.
  609. --*/
  610. {
  611. ULONG64 Address;
  612. ULONG64 PfnDb;
  613. ULONG64 Pfn;
  614. ULONG64 PfnStart;
  615. ULONG Flags;
  616. ULONG PfnSize;
  617. PfnSize = GetTypeSize("nt!_MMPFN");
  618. if (!PfnSize) {
  619. dprintf("unable to _MMPFN type.\n");
  620. return E_INVALIDARG;
  621. }
  622. PfnDb = GetNtDebuggerData( MmPfnDatabase );
  623. if (!PfnDb) {
  624. dprintf("unable to get PFN0 database address\n");
  625. return E_INVALIDARG;
  626. }
  627. PfnStart = 0;
  628. if (!ReadPointer(PfnDb,&PfnStart)) {
  629. dprintf("unable to get PFN database address %p\n", PfnDb);
  630. return E_INVALIDARG;
  631. }
  632. Address = 0;
  633. Flags = 0;
  634. if (GetExpressionEx(args, &Address, &args)) {
  635. Flags = (ULONG) GetExpression(args);
  636. }
  637. if (Flags != 0) {
  638. if (!TargetIsDump) {
  639. ULONG64 CacheSize;
  640. Ioctl(IG_GET_CACHE_SIZE, &CacheSize, sizeof(CacheSize));
  641. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  642. if (CacheSize < 0x10000000) {
  643. dprintf("CacheSize too low - increasing to 10M\n");
  644. ExecuteCommand(Client, ".cache 10000");
  645. }
  646. } else if (CacheSize < 0x1000000) {
  647. dprintf("CacheSize too low - increasing to 1M\n");
  648. ExecuteCommand(Client, ".cache 1000");
  649. }
  650. }
  651. DumpWholePfn ( Address, Flags);
  652. return E_INVALIDARG;
  653. }
  654. if (Address >= PfnStart) {
  655. //
  656. // Ensure any passed in address is offsetted correctly.
  657. //
  658. Address = (Address - PfnStart) / PfnSize;
  659. }
  660. Pfn = (PfnStart + Address * PfnSize);
  661. PrintPfn64(Pfn);
  662. return S_OK;
  663. }
  664. VOID
  665. DumpTerminalServerMemory (
  666. VOID
  667. )
  668. {
  669. ULONG64 Next;
  670. ULONG64 SessionListPointer;
  671. ULONG64 SessionData;
  672. ULONG SessionId;
  673. ULONG SessionWsListLinksOffset;
  674. ULONG64 NonPagedPoolBytes;
  675. ULONG64 PagedPoolBytes;
  676. ULONG64 CommittedPages;
  677. ULONG Failures;
  678. ULONG TotalFailures;
  679. ULONG64 SessionPoolSize;
  680. ULONG64 SessionViewSize;
  681. ULONG64 PagedPoolInfoPointer;
  682. dprintf("\n\tTerminal Server Memory Usage By Session:\n\n");
  683. // Get the offset of ActiveProcessLinks in _EPROCESS
  684. if (GetFieldOffset("nt!_MM_SESSION_SPACE", "WsListEntry", &SessionWsListLinksOffset)) {
  685. return;
  686. }
  687. SessionListPointer = GetExpression ("nt!MiSessionWsList");
  688. if (!SessionListPointer) {
  689. dprintf("Unable to get value of SessionListPointer\n");
  690. return;
  691. }
  692. if (GetFieldValue( SessionListPointer, "nt!_LIST_ENTRY", "Flink", Next )) {
  693. dprintf("Unable to read _LIST_ENTRY @ %p\n", SessionListPointer);
  694. return;
  695. }
  696. SessionPoolSize = GetUlongValue ("nt!MmSessionPoolSize");
  697. SessionViewSize = GetUlongValue ("nt!MmSessionViewSize");
  698. dprintf("\tSession Paged Pool Maximum is %ldK\n", SessionPoolSize / 1024);
  699. dprintf("\tSession View Space Maximum is %ldK\n", SessionViewSize / 1024);
  700. while(Next != SessionListPointer) {
  701. SessionData = Next - SessionWsListLinksOffset;
  702. if (GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionId", SessionId )) {
  703. dprintf("Unable to read _MM_SESSION_SPACE at %p\n",SessionData);
  704. return;
  705. }
  706. TotalFailures = 0;
  707. dprintf("\n\tSession ID %x @ %p:\n",SessionId, SessionData);
  708. #if 0
  709. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "NonPagedPoolBytes",
  710. NonPagedPoolBytes );
  711. #endif
  712. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "PagedPoolInfo.AllocatedPagedPool",
  713. PagedPoolBytes );
  714. PagedPoolBytes *= PageSize;
  715. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "CommittedPages",
  716. CommittedPages );
  717. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[0]",
  718. Failures);
  719. TotalFailures += Failures;
  720. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[1]",
  721. Failures);
  722. TotalFailures += Failures;
  723. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[2]",
  724. Failures);
  725. TotalFailures += Failures;
  726. GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[3]",
  727. Failures);
  728. TotalFailures += Failures;
  729. #if 0
  730. dprintf("\tNonpaged Pool Usage: %8I64ldK\n",NonPagedPoolBytes / 1024);
  731. #endif
  732. dprintf("\tPaged Pool Usage: %8I64ldK\n",PagedPoolBytes / 1024);
  733. if (TotalFailures != 0) {
  734. dprintf("\n\t*** %ld Pool Allocation Failures ***\n\n",TotalFailures);
  735. }
  736. dprintf("\tCommit Usage: %8I64ldK\n",CommittedPages * _KB);
  737. GetFieldValue(SessionData, "nt!_MM_SESSION_SPACE", "WsListEntry.Flink", Next);
  738. if (CheckControlC()) {
  739. return;
  740. }
  741. }
  742. return;
  743. }
  744. VOID
  745. DumpPagefileWritesLog (
  746. VOID
  747. )
  748. {
  749. ULONG64 PagesInThisRequest;
  750. ULONG64 TotalPagesWritten;
  751. ULONG64 PfnEntry;
  752. ULONG64 PfnDb;
  753. ULONG64 PfnStart;
  754. ULONG PfnSize;
  755. ULONG MdlSize;
  756. ULONG MdlOff;
  757. ULONG64 PageFileTraceAddress;
  758. ULONG64 PageFileTraceIndexAddress;
  759. ULONG PagefileTraceIndex;
  760. ULONG PageFileTraceLength;
  761. ULONG I, Index;
  762. ULONG64 Address;
  763. ULONG PageFileTraceEntrySize;
  764. ULONG Result;
  765. ULONG Flags;
  766. NTSTATUS WriteStatus;
  767. LARGE_INTEGER Time;
  768. CHAR Buffer[256];
  769. PCHAR Buf;
  770. PCHAR BufEnd;
  771. TotalPagesWritten = 0;
  772. BufEnd = Buffer + sizeof(Buffer);
  773. dprintf("\nPagefile Write Log :\n\n");
  774. PageFileTraceLength = 0x100;
  775. //
  776. // Read pagefile write package data.
  777. //
  778. PageFileTraceIndexAddress = GetExpression ("nt!MiPageFileTraceIndex");
  779. if (PageFileTraceIndexAddress == 0) {
  780. dprintf ("Incorrect symbols or this kernel does not track pagefile writes.\n");
  781. return;
  782. }
  783. ReadMemory (PageFileTraceIndexAddress, &PagefileTraceIndex, sizeof(ULONG), &Result);
  784. if (Result != sizeof(ULONG)) {
  785. dprintf ("page file write tracking: read error \n");
  786. return;
  787. }
  788. PageFileTraceAddress = GetExpression ("nt!MiPageFileTraces");
  789. PageFileTraceEntrySize = GetTypeSize("nt!_MI_PAGEFILE_TRACES");
  790. GetFieldOffset ("nt!_MI_PAGEFILE_TRACES", "MdlHack", &MdlOff);
  791. MdlSize = GetTypeSize("nt!_MDL");
  792. //
  793. // Compute the start of the PFN database so completed MDLs (which
  794. // contain PFN database addresses not frame numbers) can be converted
  795. // back for easier perusal.
  796. //
  797. PfnSize = GetTypeSize("nt!_MMPFN");
  798. PfnDb = GetNtDebuggerData (MmPfnDatabase);
  799. if (!PfnDb) {
  800. dprintf("unable to get PFN0 database address\n");
  801. return;
  802. }
  803. PfnStart = 0;
  804. if (!ReadPointer (PfnDb, &PfnStart)) {
  805. dprintf("unable to get PFN database address %p\n", PfnDb);
  806. return;
  807. }
  808. if (!IsPtr64()) {
  809. PfnStart = (ULONG64) (ULONG64) (ULONG) PfnStart;
  810. }
  811. //
  812. // Dump information, starting at the oldest trace first.
  813. //
  814. dprintf ("TPri IPri Avail PfPages MDLSize MDLPfn Status Time\n");
  815. Index = PagefileTraceIndex + 1;
  816. for (I = 0, Index = PagefileTraceIndex; I < PageFileTraceLength; I += 1) {
  817. Index += 1;
  818. Index &= (PageFileTraceLength - 1);
  819. Address = PageFileTraceAddress + Index * PageFileTraceEntrySize;
  820. InitTypeRead (Address, nt!_MI_PAGEFILE_TRACES);
  821. // dprintf ("Address: %I64X\n", Address);
  822. dprintf ("%d ", ReadField (Priority));
  823. dprintf ("%d ", ReadField (IrpPriority));
  824. dprintf ("%7x ", ReadField (AvailablePages));
  825. dprintf ("%7x ", ReadField (ModifiedPagefilePages));
  826. Time.QuadPart = ReadField (CurrentTime);
  827. WriteStatus = (NTSTATUS) ReadField (Status);
  828. Address += MdlOff;
  829. InitTypeRead (Address, nt!_MDL);
  830. PagesInThisRequest = ReadField (ByteCount) / PageSize;
  831. dprintf ("%2x ", PagesInThisRequest);
  832. Address += MdlSize;
  833. InitTypeRead (Address, nt!_MMPFN);
  834. PfnEntry = ReadField (u1.Flink);
  835. if (PfnEntry >= PfnStart) {
  836. //
  837. // Convert any completed MDLs (PFN addresses) back to a PFN index.
  838. //
  839. PfnEntry = (PfnEntry - PfnStart) / PfnSize;
  840. }
  841. dprintf ("%8x ", PfnEntry);
  842. FileTimeToString(Time,TRUE, Buffer);
  843. if (WriteStatus != (NTSTATUS)-1) {
  844. dprintf ("%8x ", WriteStatus);
  845. TotalPagesWritten += PagesInThisRequest;
  846. }
  847. else {
  848. dprintf (" Sent ");
  849. }
  850. //
  851. // Get rid of timezone information so the display will fit easily.
  852. //
  853. for (Buf = Buffer; Buf < BufEnd; Buf += 1) {
  854. if (*Buf == '(') {
  855. *Buf = 0;
  856. break;
  857. }
  858. }
  859. dprintf ("%s\n", Buffer);
  860. if (CheckControlC()) {
  861. dprintf ("Interrupted\n");
  862. break;
  863. }
  864. }
  865. dprintf ("TotalPagesWritten in this log is 0x%x\n", TotalPagesWritten);
  866. return;
  867. }
  868. #if (_MSC_VER < 1200) && defined(_M_IX86)
  869. #pragma optimize("g", off)
  870. #endif
  871. DECLARE_API( vm )
  872. /*++
  873. Routine Description:
  874. Displays physical memory usage by driver.
  875. Arguments:
  876. arg - Flags : 0 (default) == systemwide vm & per-process output.
  877. 1 == just systemwide vm counts, no per-process output.
  878. 2 == systemwide vm, per-process & Mm thread output.
  879. 3 == systemwide vm & Mm thread display, no per-process output.
  880. 4 == systemwide vm, per-process & Terminal Server session output.
  881. Return Value:
  882. None.
  883. --*/
  884. {
  885. ULONG Flags;
  886. ULONG Index;
  887. ULONG64 MemorySize;
  888. ULONG64 CommitLimit;
  889. ULONG64 CommitTotal;
  890. ULONG64 SharedCommit;
  891. ULONG64 SpecialPoolPages;
  892. ULONG64 ProcessCommit;
  893. ULONG64 PagedPoolCommit;
  894. ULONG64 DriverCommit;
  895. ULONG64 ZeroPages;
  896. ULONG64 FreePages;
  897. ULONG64 StandbyPages;
  898. ULONG64 ModifiedPages;
  899. ULONG64 ModifiedNoWrite;
  900. ULONG64 NumberOfPagedPools;
  901. ULONG64 NumberOfPagingFiles;
  902. ULONG64 AvailablePages;
  903. ULONG64 Failures;
  904. ULONG64 LockPagesCount;
  905. ULONG64 MmTotalPagesForPagingFile;
  906. ULONG64 SpecialPagesNonPaged;
  907. ULONG64 SpecialPagesNonPagedMaximum;
  908. ULONG64 FreePtesPointer;
  909. ULONG64 FreeNonPagedPtes;
  910. ULONG64 ResidentAvailablePages;
  911. ULONG64 PoolLoc;
  912. ULONG64 PoolLocBase;
  913. ULONG result;
  914. ULONG TotalPages;
  915. ULONG ExtendedCommit;
  916. ULONG64 TotalProcessCommit;
  917. PPROCESS_COMMIT_USAGE ProcessCommitUsage;
  918. ULONG i;
  919. ULONG NumberOfProcesses;
  920. ULONG64 PagedPoolBytesMax;
  921. ULONG64 PagedPoolBytes;
  922. ULONG64 NonPagedPoolBytesMax;
  923. ULONG64 NonPagedPoolBytes;
  924. ULONG64 PageFileBase;
  925. ULONG64 PageFilePointer;
  926. ULONG PageFileFullExtendPages;
  927. ULONG PageFileFullExtendCount;
  928. PUCHAR tempbuffer;
  929. UNICODE_STRING unicodeString;
  930. ULONG64 PagedPoolInfoPointer;
  931. ULONG64 FreeSystemPtes;
  932. UCHAR PagedPoolType[] = "nt!_MM_PAGED_POOL_INFO";
  933. ULONG64 AllocatedPagedPool=0;
  934. ULONG Desc_TotalPages=0, TotalBigPages=0, Desc_size;
  935. ULONG PtrSize = DBG_PTR_SIZE;
  936. ULONG NumberOfNonPagedPools;
  937. ULONG64 ExpNumberOfNonPagedPools;
  938. ULONG MiAddPtesCount;
  939. Flags = 0;
  940. Flags = (ULONG) GetExpression(args);
  941. dprintf("\n*** Virtual Memory Usage ***\n");
  942. MemorySize = GetNtDebuggerDataValue(MmNumberOfPhysicalPages);
  943. dprintf ("\tPhysical Memory: %8I64ld (%8I64ld Kb)\n",MemorySize,_KB*MemorySize);
  944. NumberOfPagingFiles = GetNtDebuggerDataValue(MmNumberOfPagingFiles);
  945. PageFilePointer = GetExpression ("nt!MmPagingFile");
  946. if (NumberOfPagingFiles == 0) {
  947. dprintf("\n************ NO PAGING FILE *********************\n\n");
  948. } else {
  949. for (i = 0; i < NumberOfPagingFiles; i++) {
  950. ULONG64 PageFileName_Buffer=0;
  951. if (!ReadPointer(PageFilePointer, &PageFileBase)) {
  952. dprintf("%08p: Unable to get page file\n",PageFilePointer);
  953. break;
  954. }
  955. if (GetFieldValue(PageFileBase,
  956. "nt!_MMPAGING_FILE",
  957. "PageFileName.Buffer",
  958. PageFileName_Buffer)) {
  959. dprintf("%08p: Unable to get page file\n",PageFilePointer);
  960. break;
  961. }
  962. InitTypeRead(PageFileBase, nt!_MMPAGING_FILE);
  963. if (PageFileName_Buffer == 0) {
  964. dprintf("\tNo Name for Paging File\n\n");
  965. } else {
  966. unicodeString.Length = (USHORT) ReadField(PageFileName.Length);
  967. if (unicodeString.Length > 1024) // sanity check
  968. {
  969. unicodeString.Length = 1024;
  970. }
  971. tempbuffer = LocalAlloc(LPTR, unicodeString.Length+sizeof(WCHAR));
  972. unicodeString.Buffer = (PWSTR)tempbuffer;
  973. unicodeString.MaximumLength = unicodeString.Length;
  974. if (!ReadMemory ( PageFileName_Buffer,
  975. tempbuffer,
  976. unicodeString.Length,
  977. &result)) {
  978. dprintf("\tPaging File Name paged out\n");
  979. } else {
  980. unicodeString.Buffer[(unicodeString.Length/sizeof(WCHAR))] = 0;
  981. dprintf("\tPage File: %wZ\n", &unicodeString);
  982. }
  983. LocalFree(tempbuffer);
  984. }
  985. dprintf("\t Current: %9I64ldKb Free Space: %9I64ldKb\n",
  986. ReadField(Size)*_KB,
  987. ReadField(FreeSpace)*_KB);
  988. dprintf("\t Minimum: %9I64ldKb Maximum: %9I64ldKb\n",
  989. ReadField(MinimumSize)*_KB,
  990. ReadField(MaximumSize)*_KB);
  991. PageFilePointer += PtrSize;
  992. }
  993. }
  994. PagedPoolInfoPointer = GetExpression ("nt!MmPagedPoolInfo");
  995. if (GetFieldValue(PagedPoolInfoPointer,
  996. PagedPoolType,
  997. "AllocatedPagedPool",
  998. AllocatedPagedPool)) {
  999. dprintf("%08p: Unable to get paged pool info\n",PagedPoolInfoPointer);
  1000. }
  1001. PagedPoolBytesMax = GetNtDebuggerDataPtrValue(MmSizeOfPagedPoolInBytes);
  1002. PagedPoolBytes = AllocatedPagedPool;
  1003. PagedPoolBytes *= PageSize;
  1004. NonPagedPoolBytesMax = GetNtDebuggerDataPtrValue(MmMaximumNonPagedPoolInBytes);
  1005. NonPagedPoolBytes = GetUlongValue ("nt!MmAllocatedNonPagedPool");
  1006. NonPagedPoolBytes *= PageSize;
  1007. CommitLimit = GetNtDebuggerDataPtrValue(MmTotalCommitLimit);
  1008. CommitTotal = GetNtDebuggerDataPtrValue(MmTotalCommittedPages);
  1009. SharedCommit = GetNtDebuggerDataPtrValue(MmSharedCommit);
  1010. DriverCommit = GetNtDebuggerDataValue(MmDriverCommit);
  1011. ProcessCommit = GetNtDebuggerDataPtrValue(MmProcessCommit);
  1012. PagedPoolCommit = GetNtDebuggerDataValue(MmPagedPoolCommit);
  1013. ZeroPages = GetNtDebuggerDataValue(MmZeroedPageListHead);
  1014. FreePages = GetNtDebuggerDataValue(MmFreePageListHead);
  1015. StandbyPages = GetNtDebuggerDataValue(MmStandbyPageListHead);
  1016. ModifiedPages = GetNtDebuggerDataValue(MmModifiedPageListHead);
  1017. ModifiedNoWrite = GetNtDebuggerDataValue(MmModifiedNoWritePageListHead);
  1018. AvailablePages = GetNtDebuggerDataValue(MmAvailablePages);
  1019. ResidentAvailablePages = GetNtDebuggerDataValue(MmResidentAvailablePages);
  1020. if (BuildNo < 2257) {
  1021. ExtendedCommit = GetUlongValue("nt!MmExtendedCommit");
  1022. PageFileFullExtendPages = GetUlongValue("nt!MmPageFileFullExtendPages");
  1023. PageFileFullExtendCount = GetUlongValue("nt!MmPageFileFullExtendCount");
  1024. }
  1025. FreeSystemPtes = GetUlongValue("nt!MmTotalFreeSystemPtes");
  1026. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  1027. MiAddPtesCount = GetUlongValue("nt!MiAddPtesCount");
  1028. if (MiAddPtesCount == 0) {
  1029. FreeSystemPtes += GetUlongValue("nt!MiExtraPtes1");
  1030. FreeSystemPtes += GetUlongValue("nt!MiExtraPtes2");
  1031. }
  1032. }
  1033. LockPagesCount = GetUlongValue("nt!MmSystemLockPagesCount");
  1034. MmTotalPagesForPagingFile = GetUlongValue("nt!MmTotalPagesForPagingFile");
  1035. SpecialPagesNonPaged = GetUlongValue("nt!MiSpecialPagesNonPaged");
  1036. SpecialPagesNonPagedMaximum = GetUlongValue("nt!MiSpecialPagesNonPagedMaximum");
  1037. FreePtesPointer = GetExpression ("nt!MmTotalFreeSystemPtes");
  1038. FreePtesPointer += sizeof(ULONG);
  1039. FreeNonPagedPtes = 0;
  1040. if (!ReadMemory (FreePtesPointer, &FreeNonPagedPtes, sizeof(ULONG), &result)) {
  1041. dprintf("\tError reading free nonpaged PTEs %p\n", FreePtesPointer);
  1042. }
  1043. SpecialPoolPages = GetUlongValue("nt!MmSpecialPagesInUse");
  1044. dprintf("\tAvailable Pages: %8I64ld (%8I64ld Kb)\n",AvailablePages, AvailablePages*_KB);
  1045. dprintf("\tResAvail Pages: %8I64ld (%8I64ld Kb)\n",ResidentAvailablePages, ResidentAvailablePages*_KB);
  1046. if ((LONG64) (ResidentAvailablePages - LockPagesCount) < 100) {
  1047. dprintf("\n\t********** Running out of physical memory **********\n\n");
  1048. }
  1049. dprintf("\tLocked IO Pages: %8I64ld (%8I64ld Kb)\n",LockPagesCount,_KB*LockPagesCount);
  1050. dprintf("\tFree System PTEs: %8I64ld (%8I64ld Kb)\n",FreeSystemPtes,_KB*FreeSystemPtes);
  1051. if (FreeSystemPtes < 1024) {
  1052. dprintf("\n\t********** Running out of system PTEs **************\n\n");
  1053. }
  1054. Failures = GetUlongValue("nt!MmPteFailures");
  1055. if (Failures != 0) {
  1056. dprintf("\n\t******* %u system PTE allocations have failed ******\n\n", Failures);
  1057. }
  1058. dprintf("\tFree NP PTEs: %8I64ld (%8I64ld Kb)\n",FreeNonPagedPtes,_KB*FreeNonPagedPtes);
  1059. dprintf("\tFree Special NP: %8I64ld (%8I64ld Kb)\n",
  1060. (SpecialPagesNonPagedMaximum - SpecialPagesNonPaged),
  1061. _KB*(SpecialPagesNonPagedMaximum - SpecialPagesNonPaged));
  1062. dprintf("\tModified Pages: %8I64ld (%8I64ld Kb)\n",ModifiedPages,ModifiedPages*_KB);
  1063. dprintf("\tModified PF Pages:%8I64ld (%8I64ld Kb)\n",MmTotalPagesForPagingFile, MmTotalPagesForPagingFile*_KB);
  1064. if ((AvailablePages < 50) && (ModifiedPages > 200)) {
  1065. dprintf("\t********** High Number Of Modified Pages ********\n");
  1066. }
  1067. if (ModifiedNoWrite > ((MemorySize / 100) * 3)) {
  1068. dprintf("\t********** High Number Of Modified No Write Pages ********\n");
  1069. dprintf("\tModified No Write Pages: %I64ld (%8I64ld Kb)\n",
  1070. ModifiedNoWrite,_KB*ModifiedNoWrite);
  1071. }
  1072. //
  1073. // Dump all the nonpaged pools.
  1074. //
  1075. PoolLoc = GetNtDebuggerData(NonPagedPoolDescriptor );
  1076. Desc_TotalPages = 0; TotalBigPages=0;
  1077. if ( !PoolLoc ||
  1078. GetFieldValue(PoolLoc,
  1079. "nt!_POOL_DESCRIPTOR",
  1080. "TotalPages",
  1081. Desc_TotalPages)) {
  1082. dprintf("%08p: Unable to get pool descriptor\n",PoolLoc);
  1083. return E_INVALIDARG;
  1084. }
  1085. Desc_size = GetTypeSize("nt!_POOL_DESCRIPTOR");
  1086. if (ExpNumberOfNonPagedPools = GetExpression("nt!ExpNumberOfNonPagedPools")) {
  1087. NumberOfNonPagedPools = GetUlongFromAddress (ExpNumberOfNonPagedPools);
  1088. } else {
  1089. NumberOfNonPagedPools = 0;
  1090. }
  1091. if (NumberOfNonPagedPools > 1) {
  1092. TotalPages = 0;
  1093. PoolLocBase = GetExpression ("nt!ExpNonPagedPoolDescriptor");
  1094. if (PoolLocBase != 0) {
  1095. for (Index = 0; Index < NumberOfNonPagedPools; Index += 1) {
  1096. if (!ReadPointer(PoolLocBase, &PoolLoc)) {
  1097. dprintf("%08p: Unable to get nonpaged pool info\n",PoolLocBase);
  1098. break;
  1099. }
  1100. if (GetFieldValue(PoolLoc,
  1101. "nt!_POOL_DESCRIPTOR",
  1102. "TotalPages",
  1103. Desc_TotalPages)) {
  1104. dprintf("%08p: Unable to get pool descriptor\n",PoolLoc);
  1105. return E_INVALIDARG;
  1106. }
  1107. GetFieldValue(PoolLoc,"_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages);
  1108. dprintf("\tNonPagedPool %1ld Used: %5ld (%8ld Kb)\n",
  1109. Index,
  1110. Desc_TotalPages + TotalBigPages,
  1111. _KB*(Desc_TotalPages + TotalBigPages));
  1112. TotalPages += Desc_TotalPages + TotalBigPages;
  1113. PoolLocBase += PtrSize;
  1114. }
  1115. }
  1116. }
  1117. GetFieldValue(PoolLoc,"nt!_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages);
  1118. if (NumberOfNonPagedPools > 1) {
  1119. dprintf("\tNonPagedPool Usage: %5ld (%8ld Kb)\n", TotalPages,_KB*TotalPages);
  1120. }
  1121. else {
  1122. dprintf("\tNonPagedPool Usage: %5ld (%8ld Kb)\n", Desc_TotalPages + TotalBigPages,
  1123. _KB*(Desc_TotalPages + TotalBigPages));
  1124. }
  1125. dprintf("\tNonPagedPool Max: %5I64ld (%8I64ld Kb)\n", NonPagedPoolBytesMax/PageSize,_KB*(NonPagedPoolBytesMax/PageSize));
  1126. if ((Desc_TotalPages + TotalBigPages) > 4 * ((NonPagedPoolBytesMax / PageSize) / 5)) {
  1127. dprintf("\t********** Excessive NonPaged Pool Usage *****\n");
  1128. }
  1129. //
  1130. // Dump all the paged pools.
  1131. //
  1132. NumberOfPagedPools = GetNtDebuggerDataValue(ExpNumberOfPagedPools);
  1133. TotalPages = 0;
  1134. PoolLocBase = GetExpression ("nt!ExpPagedPoolDescriptor");
  1135. if ((PoolLocBase != 0) && (NumberOfPagedPools != 0)) {
  1136. for (Index = 0; (Index < (NumberOfPagedPools + 1)) ; Index += 1) {
  1137. if (Index && (BuildNo <= 2464)) {
  1138. PoolLoc += Desc_size;
  1139. } else {
  1140. if (!ReadPointer(PoolLocBase, &PoolLoc)) {
  1141. dprintf("%08p: Unable to get paged pool info\n",PoolLocBase);
  1142. break;
  1143. }
  1144. }
  1145. if (GetFieldValue(PoolLoc,
  1146. "nt!_POOL_DESCRIPTOR",
  1147. "TotalPages",
  1148. Desc_TotalPages)) {
  1149. dprintf("%08p: Unable to get pool descriptor, PagedPool usage may be wrong\n",PoolLoc);
  1150. break;
  1151. }
  1152. GetFieldValue(PoolLoc,"nt!_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages);
  1153. dprintf("\tPagedPool %1ld Usage: %5ld (%8ld Kb)\n",
  1154. Index,
  1155. Desc_TotalPages + TotalBigPages,
  1156. _KB*(Desc_TotalPages + TotalBigPages));
  1157. TotalPages += Desc_TotalPages + TotalBigPages;
  1158. PoolLocBase += PtrSize;
  1159. }
  1160. }
  1161. if (PagedPoolBytes > 95 * (PagedPoolBytesMax/ 100)) {
  1162. dprintf("\t********** Excessive Paged Pool Usage *****\n");
  1163. }
  1164. dprintf("\tPagedPool Usage: %5ld (%8ld Kb)\n", TotalPages,_KB*TotalPages);
  1165. dprintf("\tPagedPool Maximum: %5I64ld (%8I64ld Kb)\n", PagedPoolBytesMax/PageSize,_KB*(PagedPoolBytesMax/PageSize));
  1166. Failures = GetUlongValue("nt!ExPoolFailures");
  1167. if (Failures != 0) {
  1168. dprintf("\n\t********** %u pool allocations have failed **********\n\n", Failures);
  1169. }
  1170. dprintf("\tShared Commit: %8I64ld (%8I64ld Kb)\n",SharedCommit,_KB*SharedCommit );
  1171. dprintf("\tSpecial Pool: %8I64ld (%8I64ld Kb)\n",SpecialPoolPages,_KB*SpecialPoolPages );
  1172. dprintf("\tShared Process: %8I64ld (%8I64ld Kb)\n",ProcessCommit,_KB*ProcessCommit );
  1173. dprintf("\tPagedPool Commit: %8I64ld (%8I64ld Kb)\n",PagedPoolCommit,_KB*PagedPoolCommit);
  1174. dprintf("\tDriver Commit: %8I64ld (%8I64ld Kb)\n",DriverCommit, _KB*DriverCommit );
  1175. dprintf("\tCommitted pages: %8I64ld (%8I64ld Kb)\n",CommitTotal, _KB*CommitTotal );
  1176. dprintf("\tCommit limit: %8I64ld (%8I64ld Kb)\n",CommitLimit, _KB*CommitLimit );
  1177. if ((CommitTotal + 100) > CommitLimit) {
  1178. dprintf("\n\t********** Number of committed pages is near limit ********\n");
  1179. }
  1180. if (BuildNo < 2257) {
  1181. if (ExtendedCommit != 0) {
  1182. dprintf("\n\t********** Commit has been extended with VM popup ********\n");
  1183. dprintf("\tExtended by: %8ld (%8ld Kb)\n", ExtendedCommit,_KB*ExtendedCommit);
  1184. }
  1185. if (PageFileFullExtendCount) {
  1186. if (PageFileFullExtendCount == 1) {
  1187. dprintf("\n\t****** ALL PAGING FILE BECAME FULL ONCE - COMMITMENT ADJUSTED ****\n");
  1188. }
  1189. else {
  1190. dprintf("\n\t****** ALL PAGING FILE BECAME FULL (%u times) - COMMITMENT ADJUSTED ****\n", PageFileFullExtendCount);
  1191. }
  1192. dprintf("\tCurrent adjust: %8ld (%8ld Kb)\n",
  1193. PageFileFullExtendPages,
  1194. _KB*PageFileFullExtendPages);
  1195. }
  1196. }
  1197. Failures = GetUlongValue("nt!MiChargeCommitmentFailures");
  1198. Failures += GetUlongValue("nt!MiChargeCommitmentFailures + 4");
  1199. if (Failures != 0) {
  1200. dprintf("\n\t********** %u commit requests have failed **********\n\n", Failures);
  1201. }
  1202. dprintf("\n");
  1203. if ((Flags & 0x1) == 0) {
  1204. ProcessCommitUsage = GetProcessCommit( &TotalProcessCommit, &NumberOfProcesses );
  1205. if (ProcessCommitUsage == NULL)
  1206. {
  1207. dprintf("\nProcessCommitUsage could not be calculated\n");
  1208. }
  1209. else
  1210. {
  1211. if (TotalProcessCommit != 0) {
  1212. dprintf("\tTotal Private: %8I64ld (%8I64ld Kb)\n",
  1213. TotalProcessCommit,_KB*TotalProcessCommit);
  1214. }
  1215. for (i=0; i<NumberOfProcesses; i++) {
  1216. dprintf( " %04I64lx %-15s %6I64d (%8I64ld Kb)\n",
  1217. ProcessCommitUsage[i].ClientId,
  1218. ProcessCommitUsage[i].ImageFileName,
  1219. ProcessCommitUsage[i].CommitCharge,
  1220. _KB*(ProcessCommitUsage[i].CommitCharge)
  1221. );
  1222. }
  1223. HeapFree(GetProcessHeap(), 0, ProcessCommitUsage);
  1224. }
  1225. }
  1226. if (Flags & 0x2) {
  1227. if (Client && (ExtQuery(Client) == S_OK)) {
  1228. dprintf("\n\tMemory Management Thread Stacks:\n");
  1229. DumpMmThreads ();
  1230. ExtRelease();
  1231. }
  1232. }
  1233. if (Flags & 0x4) {
  1234. if (Client && (ExtQuery(Client) == S_OK)) {
  1235. DumpTerminalServerMemory ();
  1236. ExtRelease();
  1237. }
  1238. }
  1239. if (Flags & 0x8) {
  1240. DumpPagefileWritesLog ();
  1241. }
  1242. return S_OK;
  1243. }
  1244. #if (_MSC_VER < 1200) && defined(_M_IX86)
  1245. #pragma optimize("", on)
  1246. #endif
  1247. VOID
  1248. DumpWholePfn(
  1249. IN ULONG64 Address,
  1250. IN ULONG Flags
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. Dumps the PFN database
  1255. Arguments:
  1256. Address - address to dump at
  1257. Flags -
  1258. Return Value:
  1259. None.
  1260. --*/
  1261. {
  1262. ULONG result;
  1263. ULONG64 HighPage;
  1264. ULONG64 LowPage;
  1265. ULONG64 PageCount;
  1266. ULONG64 ReadCount;
  1267. ULONG64 i;
  1268. ULONG64 Pfn;
  1269. ULONG64 PfnStart;
  1270. PUCHAR PfnArray;
  1271. PUCHAR PfnArrayPointer;
  1272. ULONG64 VirtualAddress;
  1273. ULONG MatchLocation;
  1274. BOOLEAN foundlink;
  1275. BOOLEAN RandomAccessRequired;
  1276. ULONG PfnSize;
  1277. ULONG NumberOfPfnToRead;
  1278. ULONG sz;
  1279. MMPFNENTRY u3_e1;
  1280. CHAR InPageError;
  1281. LowPage = GetNtDebuggerDataPtrValue(MmLowestPhysicalPage);
  1282. HighPage = GetNtDebuggerDataPtrValue(MmHighestPhysicalPage);
  1283. PfnStart = GetNtDebuggerDataPtrValue(MmPfnDatabase);
  1284. PfnSize = GetTypeSize("nt!_MMPFN");
  1285. //
  1286. // Read sufficient pages such that htere isn't lot of wait
  1287. // before first page dump.
  1288. //
  1289. NumberOfPfnToRead = 2000;
  1290. PfnArray = NULL;
  1291. if (Flags == 7) {
  1292. RandomAccessRequired = TRUE;
  1293. }
  1294. else {
  1295. RandomAccessRequired = FALSE;
  1296. }
  1297. if (RandomAccessRequired == FALSE) {
  1298. dprintf("\n Page Flink Blk/Shr Ref V PTE Address SavedPTE Frame State\n");
  1299. }
  1300. //
  1301. // If asked to dump the whole database or we're going to need the ability
  1302. // to look up random frames, then read in the whole database now.
  1303. //
  1304. if (Address == 0 || RandomAccessRequired == TRUE) {
  1305. PfnArray = LocalAlloc(LPTR, (ULONG) (HighPage+1) * PfnSize);
  1306. if (!PfnArray) {
  1307. dprintf("unable to get allocate %ld bytes of memory\n",
  1308. (HighPage+1) * PfnSize);
  1309. return;
  1310. }
  1311. for (PageCount = LowPage;
  1312. PageCount <= HighPage;
  1313. PageCount += NumberOfPfnToRead) {
  1314. if (CheckControlC()) {
  1315. goto alldone;
  1316. }
  1317. ReadCount = HighPage - PageCount > NumberOfPfnToRead ?
  1318. NumberOfPfnToRead :
  1319. HighPage - PageCount + 1;
  1320. ReadCount *= PfnSize;
  1321. Pfn = (PfnStart + PageCount * PfnSize);
  1322. PfnArrayPointer = (PUCHAR)(PfnArray + (ULONG) PageCount * PfnSize);
  1323. //
  1324. // KD caches the Pfns
  1325. //
  1326. if ((!ReadMemory(Pfn,
  1327. PfnArrayPointer,
  1328. (ULONG) ReadCount,
  1329. &result)) || (result < (ULONG) ReadCount)) {
  1330. dprintf("unable to get PFN table block - "
  1331. "address %p - count %I64u - page %I64lu\n",
  1332. Pfn, ReadCount, PageCount);
  1333. goto alldone;
  1334. }
  1335. for (i = PageCount;
  1336. (i < PageCount + NumberOfPfnToRead) && (i < HighPage);
  1337. i += 1, Pfn = (Pfn + PfnSize)) {
  1338. ULONG u3_e2_ReferenceCount=0;
  1339. ULONG64 u1_Flink=0, u2_Blink=0, PteAddress=0, OriginalPte=0, PteFrame=0;
  1340. if (RandomAccessRequired == TRUE) {
  1341. if ((i % 256 ) == 0) {
  1342. dprintf("."); // every 256 pages, print a dot
  1343. }
  1344. }
  1345. else {
  1346. GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", u1_Flink);
  1347. GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", u2_Blink);
  1348. GetFieldValue(Pfn, "nt!_MMPFN", "PteAddress",PteAddress);
  1349. GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte",OriginalPte);
  1350. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e2.ReferenceCount", u3_e2_ReferenceCount);
  1351. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1);
  1352. GetVersionedMmPfnMembers(Pfn, &PteFrame, &InPageError);
  1353. if (u3_e1.PrototypePte == 0) {
  1354. VirtualAddress = DbgGetVirtualAddressMappedByPte(PteAddress);
  1355. } else {
  1356. VirtualAddress = 0;
  1357. }
  1358. dprintf("%5I64lx %8p %8p%6x %8p %8p ",
  1359. i,
  1360. u1_Flink,
  1361. u2_Blink,
  1362. u3_e2_ReferenceCount,
  1363. PteAddress,
  1364. VirtualAddress);
  1365. dprintf("%8p ", OriginalPte);
  1366. dprintf("%6I64lx ", PteFrame);
  1367. dprintf("%s %c%c%c%c%c%c\n",
  1368. PageLocationList[u3_e1.PageLocation],
  1369. u3_e1.Modified ? 'M':' ',
  1370. u3_e1.PrototypePte ? 'P':' ',
  1371. u3_e1.ReadInProgress ? 'R':' ',
  1372. u3_e1.WriteInProgress ? 'W':' ',
  1373. InPageError ? 'E':' ',
  1374. u3_e1.ParityError ? 'X':' '
  1375. );
  1376. }
  1377. if (CheckControlC()) {
  1378. goto alldone;
  1379. }
  1380. }
  1381. }
  1382. if (RandomAccessRequired == TRUE) {
  1383. dprintf("\n");
  1384. }
  1385. else {
  1386. goto alldone;
  1387. }
  1388. }
  1389. dprintf("\n Page Flink Blk/Shr Ref V PTE Address SavedPTE Frame State\n");
  1390. Pfn = (PfnStart + Address * PfnSize);
  1391. if (GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1)) {
  1392. dprintf("unable to get PFN element\n");
  1393. goto alldone;
  1394. }
  1395. MatchLocation = u3_e1.PageLocation;
  1396. do {
  1397. ULONG u3_e2_ReferenceCount=0;
  1398. ULONG64 u1_Flink=0, u2_Blink=0, PteAddress=0, OriginalPte=0, PteFrame=0;
  1399. if (CheckControlC()) {
  1400. goto alldone;
  1401. }
  1402. Pfn = (PfnStart + Address * PfnSize);
  1403. sz = sizeof (u3_e1);
  1404. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1);
  1405. if (u3_e1.PrototypePte == 0) {
  1406. VirtualAddress = DbgGetVirtualAddressMappedByPte ( PteAddress);
  1407. } else {
  1408. VirtualAddress = 0;
  1409. }
  1410. if (u3_e1.PageLocation == MatchLocation) {
  1411. GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", u1_Flink);
  1412. GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", u2_Blink);
  1413. GetFieldValue(Pfn, "nt!_MMPFN", "PteAddress", PteAddress);
  1414. GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte",OriginalPte);
  1415. GetFieldValue(Pfn, "nt!_MMPFN", "u3.e2.ReferenceCount", u3_e2_ReferenceCount);
  1416. GetVersionedMmPfnMembers(Pfn, &PteFrame, &InPageError);
  1417. dprintf("%5I64lx %8p %8p%6x %8p %8p ",
  1418. Address,
  1419. u1_Flink,
  1420. u2_Blink,
  1421. u3_e2_ReferenceCount,
  1422. PteAddress,
  1423. VirtualAddress);
  1424. dprintf("%8p ", OriginalPte);
  1425. dprintf("%6I64lx ", PteFrame);
  1426. dprintf("%s %c%c%c%c%c%c\n",
  1427. PageLocationList[u3_e1.PageLocation],
  1428. u3_e1.Modified ? 'M':' ',
  1429. u3_e1.PrototypePte ? 'P':' ',
  1430. u3_e1.ReadInProgress ? 'R':' ',
  1431. u3_e1.WriteInProgress ? 'W':' ',
  1432. InPageError ? 'E':' ',
  1433. u3_e1.ParityError ? 'X':' '
  1434. );
  1435. }
  1436. if (MatchLocation > 5) {
  1437. Address += 1;
  1438. } else {
  1439. ULONG64 OriginalPte_u_Long=0;
  1440. sz = sizeof (OriginalPte_u_Long);
  1441. if (Flags == 7) {
  1442. ULONG64 P;
  1443. //
  1444. // Search the whole database for an OriginalPte field that
  1445. // points to this PFN - we must do this because this chain
  1446. // is singly (not doubly) linked.
  1447. //
  1448. foundlink = FALSE;
  1449. P = PfnStart;
  1450. for (i = 0; i <= HighPage; i += 1, P += PfnSize) {
  1451. GetFieldValue(P, "nt!_MMPFN", "OriginalPte.u.Long", OriginalPte_u_Long);
  1452. if (OriginalPte_u_Long == Address) {
  1453. Address = i;
  1454. foundlink = TRUE;
  1455. break;
  1456. }
  1457. }
  1458. if (foundlink == FALSE) {
  1459. dprintf("No OriginalPte chain found for %lx\n", Address);
  1460. break;
  1461. }
  1462. } else if (Flags == 5) {
  1463. GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte.u.Long", OriginalPte_u_Long);
  1464. Address = OriginalPte_u_Long;
  1465. } else if (Flags == 3) {
  1466. Address = u2_Blink;
  1467. } else {
  1468. Address = u1_Flink;
  1469. }
  1470. }
  1471. if (CheckControlC()) {
  1472. goto alldone;
  1473. }
  1474. } while (Address < HighPage);
  1475. alldone:
  1476. if (PfnArray) {
  1477. LocalFree((void *)PfnArray);
  1478. }
  1479. }
  1480. VOID
  1481. PrintPfn64 (
  1482. IN ULONG64 PfnAddress
  1483. )
  1484. {
  1485. MMPFNENTRY u3_e1;
  1486. ULONG64 PfnDb, PfnStart;
  1487. ULONG PfnSize;
  1488. ULONG CacheAttribute;
  1489. CHAR InPageError, VerifierAllocation;
  1490. if ((PfnSize = GetTypeSize("nt!_MMPFN")) == 0) {
  1491. dprintf("Type _MMPFN not found.\n");
  1492. return;
  1493. }
  1494. PfnDb = GetNtDebuggerData(MmPfnDatabase);
  1495. if (!ReadPointer(PfnDb, &PfnStart)) {
  1496. dprintf("%08P: Unable to get PFN database start\n",PfnDb);
  1497. return;
  1498. }
  1499. if (!IsPtr64()) {
  1500. PfnAddress = (ULONG64) (LONG64) (LONG) PfnAddress;
  1501. }
  1502. dprintf(" PFN %08P at address %08P\n",
  1503. (PfnAddress - PfnStart) / PfnSize,
  1504. PfnAddress);
  1505. InitTypeRead(PfnAddress, nt!_MMPFN);
  1506. dprintf(" flink %08P", ReadField(u1.Flink));
  1507. dprintf(" blink / share count %08P", ReadField(u2.Blink));
  1508. dprintf(" pteaddress %08P\n", ReadField(PteAddress));
  1509. GetFieldValue(PfnAddress, "nt!_MMPFN", "u3.e1", u3_e1);
  1510. switch (TargetMachine) {
  1511. case IMAGE_FILE_MACHINE_IA64:
  1512. case IMAGE_FILE_MACHINE_AMD64:
  1513. dprintf(" reference count %04hX used entry count %04hX %s color %01hX\n",
  1514. (ULONG) ReadField(u3.e2.ReferenceCount),
  1515. (ULONG) ReadField(UsedPageTableEntries),
  1516. PageAttribute[u3_e1.CacheAttribute],
  1517. u3_e1.PageColor);
  1518. break;
  1519. default:
  1520. dprintf(" reference count %04hX %s color %01hX\n",
  1521. (ULONG) ReadField(u3.e2.ReferenceCount),
  1522. PageAttribute[u3_e1.CacheAttribute],
  1523. u3_e1.PageColor);
  1524. break;
  1525. }
  1526. dprintf(" restore pte %08I64X ", ReadField(OriginalPte));
  1527. if (BuildNo < 2440) {
  1528. dprintf("containing page %06P ", ReadField(PteFrame));
  1529. InPageError = (CHAR) ReadField(u3.e1.InPageError);
  1530. VerifierAllocation = (CHAR) ReadField(u3.e1.VerifierAllocation);
  1531. } else {
  1532. dprintf("containing page %06P ", ReadField(u4.PteFrame));
  1533. InPageError = (CHAR) ReadField(u4.InPageError);
  1534. VerifierAllocation = (CHAR) ReadField(u4.VerifierAllocation);
  1535. }
  1536. dprintf("%s %c%c%c%c%c%c%c%c\n",
  1537. PageLocationList[u3_e1.PageLocation],
  1538. u3_e1.Modified ? 'M':' ',
  1539. u3_e1.PrototypePte ? 'P':' ',
  1540. u3_e1.ReadInProgress ? 'R':' ',
  1541. u3_e1.WriteInProgress ? 'W':' ',
  1542. InPageError ? 'E':' ',
  1543. u3_e1.ParityError ? 'X':' ',
  1544. u3_e1.RemovalRequested ? 'Y':' ',
  1545. VerifierAllocation ? 'V':' '
  1546. );
  1547. dprintf(" %s %s %s %s %s %s %s %s\n",
  1548. u3_e1.Modified ? "Modified":" ",
  1549. u3_e1.PrototypePte ? "Shared":" ",
  1550. u3_e1.ReadInProgress ? "ReadInProgress":" ",
  1551. u3_e1.WriteInProgress ? "WriteInProgress":" ",
  1552. InPageError ? "InPageError":" ",
  1553. u3_e1.ParityError ? "ParityError":" ",
  1554. u3_e1.RemovalRequested ? "RemovalRequested":" ",
  1555. VerifierAllocation ? "VerifierAllocation":" ");
  1556. return;
  1557. }
  1558. VOID
  1559. MemoryUsage_OldVersion (
  1560. IN ULONG64 PfnStart,
  1561. IN ULONG64 LowPage,
  1562. IN ULONG64 HighPage,
  1563. IN ULONG IgnoreInvalidFrames
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. This routine (debugging only) dumps the current memory usage by
  1568. walking the PFN database.
  1569. For builds < 2540 only
  1570. Arguments:
  1571. None.
  1572. Return Value:
  1573. None.
  1574. --*/
  1575. {
  1576. ULONG PfnSize;
  1577. ULONG64 LastPfn;
  1578. ULONG64 Pfn1;
  1579. ULONG64 Pfn2;
  1580. ULONG64 Subsection1;
  1581. UNICODE_STRING NameString;
  1582. PPFN_INFO Info;
  1583. PPFN_INFO Info1;
  1584. PPFN_INFO InfoStart;
  1585. PPFN_INFO InfoEnd;
  1586. ULONG InfoSize;
  1587. PFN_INFO ProcessPfns;
  1588. PFN_INFO PagedPoolBlock;
  1589. PPFN_INFO LastProcessInfo = &ProcessPfns;
  1590. ULONG64 Master;
  1591. ULONG64 ControlArea1;
  1592. BOOLEAN Found;
  1593. ULONG result;
  1594. ULONG i;
  1595. ULONG64 PagedPoolStart;
  1596. ULONG64 VirtualAddress;
  1597. ULONG64 MmNonPagedPoolEnd;
  1598. ULONG64 PteFrame;
  1599. ULONG OriginalPteOffset;
  1600. ULONG PercentComplete=0;
  1601. PKERN_MAP pKernelMap;
  1602. ULONG64 SystemRangeStart;
  1603. // Get the offset of OriginalPte in MMPFN
  1604. if (GetFieldOffset("nt!_MMPFN", "OriginalPte", &OriginalPteOffset)) {
  1605. dprintf("Cannot find _MMPFN type");
  1606. return ;
  1607. }
  1608. SystemRangeStart = GetNtDebuggerDataValue(MmSystemRangeStart);
  1609. ProcessPfns.Next = NULL;
  1610. MmNonPagedPoolEnd = GetNtDebuggerDataPtrValue(MmNonPagedPoolEnd);
  1611. NameString.MaximumLength = sizeof(WCHAR) * 1000;
  1612. NameString.Buffer = calloc(1, NameString.MaximumLength);
  1613. if (!NameString.Buffer) {
  1614. return;
  1615. }
  1616. PagedPoolStart = GetNtDebuggerDataPtrValue(MmPagedPoolStart);
  1617. pKernelMap = calloc(1, sizeof(*pKernelMap));
  1618. if (!pKernelMap) {
  1619. free(NameString.Buffer);
  1620. return;
  1621. }
  1622. dprintf (" Building kernel map\n");
  1623. if (BuildKernelMap (pKernelMap) == FALSE) {
  1624. free(pKernelMap);
  1625. free(NameString.Buffer);
  1626. return;
  1627. }
  1628. dprintf (" Finished building kernel map\n");
  1629. RtlZeroMemory (&PagedPoolBlock, sizeof (PFN_INFO));
  1630. PfnSize = GetTypeSize("nt!_MMPFN");
  1631. LastPfn = (PfnStart + HighPage * PfnSize);
  1632. if (MmSubsectionBase == 0) {
  1633. MmSubsectionBase = GetNtDebuggerDataValue(MmSubsectionBase);
  1634. }
  1635. //
  1636. // Allocate a chunk of memory to hold PFN information. This is resized
  1637. // if it is later determined that the current size is not large enough.
  1638. //
  1639. InfoSize = USAGE_ALLOC_SIZE;
  1640. restart:
  1641. InfoStart = VirtualAlloc (NULL,
  1642. InfoSize,
  1643. MEM_COMMIT,
  1644. PAGE_READWRITE);
  1645. if (InfoStart == NULL) {
  1646. dprintf ("heap allocation for %d bytes failed\n", InfoSize);
  1647. free(pKernelMap);
  1648. free(NameString.Buffer);
  1649. return;
  1650. }
  1651. InfoEnd = InfoStart;
  1652. Pfn1 = (PfnStart + LowPage * PfnSize);
  1653. while (Pfn1 < LastPfn) {
  1654. ULONG PageLocation=0, PrototypePte=0, ReferenceCount=0;
  1655. ULONG Comp;
  1656. ULONG64 ShareCount=0, PteFrame1=0, PteAddress;
  1657. Comp = ((ULONG) (Pfn1 - (PfnStart + LowPage * PfnSize)))*100 /
  1658. ((ULONG) (LastPfn -(PfnStart + LowPage * PfnSize)));
  1659. if (Comp > PercentComplete) {
  1660. PercentComplete = Comp;
  1661. dprintf("Scanning PFN database - (%02d%% complete) \r", PercentComplete);
  1662. }
  1663. if (CheckControlC()) {
  1664. VirtualFree (InfoStart,0,MEM_RELEASE);
  1665. free(pKernelMap);
  1666. free(NameString.Buffer);
  1667. return;
  1668. }
  1669. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PageLocation", PageLocation);
  1670. if ((PageLocation != FreePageList) &&
  1671. (PageLocation != ZeroedPageList) &&
  1672. (PageLocation != BadPageList)) {
  1673. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PrototypePte", PrototypePte);
  1674. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e2.ReferenceCount", ReferenceCount);
  1675. GetFieldValue(Pfn1, "nt!_MMPFN", "u2.ShareCount", ShareCount);
  1676. GetFieldValue(Pfn1, "nt!_MMPFN", "PteAddress", PteAddress);
  1677. if (GetFieldValue(Pfn1, "nt!_MMPFN", "u4.PteFrame", PteFrame1) == FIELDS_DID_NOT_MATCH) {
  1678. GetFieldValue(Pfn1, "nt!_MMPFN", "PteFrame", PteFrame1);
  1679. }
  1680. Subsection1 = 0;
  1681. if (PrototypePte) {
  1682. ULONG OriginalPrototype=0;
  1683. GetFieldValue(Pfn1, "nt!_MMPFN", "OriginalPte.u.Soft.Prototype", OriginalPrototype);
  1684. if (OriginalPrototype) {
  1685. Subsection1 = DbgGetSubsectionAddress (Pfn1 + OriginalPteOffset);
  1686. }
  1687. }
  1688. if ((Subsection1) && (Subsection1 < 0xffffffffffbff000UI64)) {
  1689. Master = Subsection1;
  1690. } else {
  1691. PteFrame = PteFrame1;
  1692. if (IgnoreInvalidFrames) {
  1693. Master = PteFrame;
  1694. } else {
  1695. // dprintf("Pteaddr %p, PagedPoolStart %I64x ", PteAddress, PagedPoolStart);
  1696. if (PteAddress > PagedPoolStart) {
  1697. Master = PteFrame;
  1698. } else {
  1699. Master=0;
  1700. Pfn2 = PfnStart + PteFrame*PfnSize;
  1701. if (GetFieldValue(Pfn2, "nt!_MMPFN", "PteFrame", Master) == FIELDS_DID_NOT_MATCH) {
  1702. GetFieldValue(Pfn2, "nt!_MMPFN", "u4.PteFrame", Master);
  1703. }
  1704. // Master = MI_PFN_PTE FRAME(Pfn2);
  1705. if ((Master == 0) || (Master > HighPage)) {
  1706. dprintf("Invalid PTE frame\n");
  1707. // PrintPfn((PVOID)(((PCHAR)Pfn1-(PCHAR)PfnStart)/PfnSize),Pfn1);
  1708. PrintPfn64(Pfn1);
  1709. PrintPfn64(Pfn2);
  1710. dprintf(" subsection address: %p\n",Subsection1);
  1711. goto NextPfn;
  1712. }
  1713. }
  1714. }
  1715. }
  1716. //
  1717. // Tally any pages which are not protos and have a valid PTE
  1718. // address field.
  1719. //
  1720. if ((PteAddress < PagedPoolStart) && (PteAddress >= DbgGetPteAddress(SystemRangeStart) )) {
  1721. for (i=0; i<pKernelMap->Count; i++) {
  1722. VirtualAddress = DbgGetVirtualAddressMappedByPte (PteAddress);
  1723. if ((VirtualAddress >= pKernelMap->Item[i].StartVa) &&
  1724. (VirtualAddress < pKernelMap->Item[i].EndVa)) {
  1725. if ((PageLocation == ModifiedPageList) ||
  1726. (PageLocation == ModifiedNoWritePageList)) {
  1727. pKernelMap->Item[i].ModifiedCount += _KB;
  1728. if (ReferenceCount > 0) {
  1729. pKernelMap->Item[i].LockedCount += _KB;
  1730. }
  1731. } else if ((PageLocation == StandbyPageList) ||
  1732. (PageLocation == TransitionPage)) {
  1733. pKernelMap->Item[i].StandbyCount += _KB;
  1734. if (ReferenceCount > 0) {
  1735. pKernelMap->Item[i].LockedCount += _KB;
  1736. }
  1737. } else {
  1738. pKernelMap->Item[i].ValidCount += _KB;
  1739. if (ShareCount > 1) {
  1740. pKernelMap->Item[i].SharedCount += _KB;
  1741. if (ReferenceCount > 1) {
  1742. pKernelMap->Item[i].LockedCount += _KB;
  1743. }
  1744. }
  1745. }
  1746. goto NextPfn;
  1747. }
  1748. }
  1749. }
  1750. if (PteAddress >= 0xFFFFFFFFF0000000UI64) {
  1751. //
  1752. // This is paged pool, put it in the paged pool cell.
  1753. //
  1754. Info = &PagedPoolBlock;
  1755. Found = TRUE;
  1756. } else {
  1757. //
  1758. // See if there is already a master info block.
  1759. //
  1760. Info = InfoStart;
  1761. Found = FALSE;
  1762. while (Info < InfoEnd) {
  1763. if (Info->Master == Master) {
  1764. Found = TRUE;
  1765. break;
  1766. }
  1767. Info += 1;
  1768. }
  1769. }
  1770. if (!Found) {
  1771. Info = InfoEnd;
  1772. InfoEnd += 1;
  1773. if ((PUCHAR)Info >= ((PUCHAR)InfoStart + InfoSize) - sizeof(PFN_INFO)) {
  1774. //
  1775. // Don't bother copying the old array - free it instead to
  1776. // improve our chances of getting a bigger contiguous chunk.
  1777. //
  1778. VirtualFree (InfoStart,0,MEM_RELEASE);
  1779. InfoSize += USAGE_ALLOC_SIZE;
  1780. goto restart;
  1781. }
  1782. RtlZeroMemory (Info, sizeof (PFN_INFO));
  1783. Info->Master = Master;
  1784. GetFieldValue(Pfn1, "nt!_MMPFN", "OriginalPte.u.Long", Info->OriginalPte);
  1785. }
  1786. // dprintf("Pfn1 %p, PageLoc %x, Master %I64x\n", Pfn1, PageLocation, Master);
  1787. if ((PageLocation == ModifiedPageList) ||
  1788. (PageLocation == ModifiedNoWritePageList)) {
  1789. Info->ModifiedCount += _KB;
  1790. if (ReferenceCount > 0) {
  1791. Info->LockedCount += _KB;
  1792. }
  1793. } else if ((PageLocation == StandbyPageList) ||
  1794. (PageLocation == TransitionPage)) {
  1795. Info->StandbyCount += _KB;
  1796. if (ReferenceCount > 0) {
  1797. Info->LockedCount += _KB;
  1798. }
  1799. } else {
  1800. Info->ValidCount += _KB;
  1801. if (ShareCount > 1) {
  1802. Info->SharedCount += _KB;
  1803. if (ReferenceCount > 1) {
  1804. Info->LockedCount += _KB;
  1805. }
  1806. }
  1807. }
  1808. if ((PteAddress >= DbgGetPdeAddress (0x0)) &&
  1809. (PteAddress <= DbgGetPdeAddress (0xFFFFFFFFFFFFFFFF))) {
  1810. Info->PageTableCount += _KB;
  1811. }
  1812. }
  1813. NextPfn:
  1814. Pfn1 = (Pfn1 + PfnSize);
  1815. }
  1816. //
  1817. // dump the results.
  1818. //
  1819. #if 0
  1820. dprintf("Physical Page Summary:\n");
  1821. dprintf(" - number of physical pages: %ld\n",
  1822. MmNumberOfPhysicalPages);
  1823. dprintf(" - Zeroed Pages %ld\n", MmZeroedPageListHead.Total);
  1824. dprintf(" - Free Pages %ld\n", MmFreePageListHead.Total);
  1825. dprintf(" - Standby Pages %ld\n", MmStandbyPageListHead.Total);
  1826. dprintf(" - Modfified Pages %ld\n", MmModifiedPageListHead.Total);
  1827. dprintf(" - Modfified NoWrite Pages %ld\n", MmModifiedNoWritePageListHead.Total);
  1828. dprintf(" - Bad Pages %ld\n", MmBadPageListHead.Total);
  1829. #endif //0
  1830. dprintf("\n\n Usage Summary (in Kb):\n");
  1831. Info = InfoStart;
  1832. while (Info < InfoEnd) {
  1833. if (CheckControlC()) {
  1834. VirtualFree (InfoStart,0,MEM_RELEASE);
  1835. free(pKernelMap);
  1836. free(NameString.Buffer);
  1837. return;
  1838. }
  1839. if (Info->Master > 0x200000) {
  1840. //
  1841. // Get the control area from the subsection.
  1842. //
  1843. if (GetFieldValue(Info->Master,
  1844. "nt!_SUBSECTION",
  1845. "ControlArea",
  1846. ControlArea1)) {
  1847. dprintf("unable to get subsection va %p %lx\n",Info->Master,Info->OriginalPte);
  1848. }
  1849. // ControlArea1 = Subsection.ControlArea;
  1850. Info->Master = ControlArea1;
  1851. //
  1852. // Loop through the array so far for matching control areas
  1853. //
  1854. Info1 = InfoStart;
  1855. while (Info1 < Info) {
  1856. if (Info1->Master == ControlArea1) {
  1857. //
  1858. // Found a match, collapse these values.
  1859. //
  1860. Info1->ValidCount += Info->ValidCount;
  1861. Info1->StandbyCount += Info->StandbyCount;
  1862. Info1->ModifiedCount += Info->ModifiedCount;
  1863. Info1->SharedCount += Info->SharedCount;
  1864. Info1->LockedCount += Info->LockedCount;
  1865. Info1->PageTableCount += Info->PageTableCount;
  1866. Info->Master = 0;
  1867. break;
  1868. }
  1869. Info1++;
  1870. }
  1871. } else {
  1872. LastProcessInfo->Next = Info;
  1873. LastProcessInfo = Info;
  1874. }
  1875. Info++;
  1876. }
  1877. Info = InfoStart;
  1878. dprintf("Control Valid Standby Dirty Shared Locked PageTables name\n");
  1879. while (Info < InfoEnd) {
  1880. ULONG64 FilePointer;
  1881. if (CheckControlC()) {
  1882. VirtualFree (InfoStart,0,MEM_RELEASE);
  1883. free(pKernelMap);
  1884. free(NameString.Buffer);
  1885. return;
  1886. }
  1887. if (Info->Master > 0x200000) {
  1888. //
  1889. // Get the control area.
  1890. //
  1891. if (GetFieldValue(Info->Master,
  1892. "nt!_CONTROL_AREA",
  1893. "FilePointer",
  1894. FilePointer)) {
  1895. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Bad Control Area\n",
  1896. Info->Master,
  1897. Info->ValidCount,
  1898. Info->StandbyCount,
  1899. Info->ModifiedCount,
  1900. Info->SharedCount,
  1901. Info->LockedCount,
  1902. Info->PageTableCount
  1903. );
  1904. } else if (FilePointer == 0) {
  1905. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Page File Section\n",
  1906. Info->Master,
  1907. Info->ValidCount,
  1908. Info->StandbyCount,
  1909. Info->ModifiedCount,
  1910. Info->SharedCount,
  1911. Info->LockedCount,
  1912. Info->PageTableCount
  1913. );
  1914. } else {
  1915. ULONG64 NameBuffer;
  1916. //
  1917. // Get the file pointer.
  1918. //
  1919. if (GetFieldValue(FilePointer,
  1920. "nt!_FILE_OBJECT",
  1921. "FileName.Length",
  1922. NameString.Length)) {
  1923. dprintf("unable to get subsection %p\n",FilePointer);
  1924. }
  1925. if (NameString.Length && (NameString.Length < 1024)) {
  1926. //
  1927. // Get the name string.
  1928. //
  1929. if (NameString.Length > NameString.MaximumLength) {
  1930. NameString.Length = NameString.MaximumLength-1;
  1931. }
  1932. GetFieldValue(FilePointer,
  1933. "nt!_FILE_OBJECT",
  1934. "FileName.Buffer",
  1935. NameBuffer);
  1936. if ((!ReadMemory(NameBuffer,
  1937. NameString.Buffer,
  1938. NameString.Length,
  1939. &result)) || (result < NameString.Length)) {
  1940. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Name Not Available\n",
  1941. Info->Master,
  1942. Info->ValidCount,
  1943. Info->StandbyCount,
  1944. Info->ModifiedCount,
  1945. Info->SharedCount,
  1946. Info->LockedCount,
  1947. Info->PageTableCount
  1948. );
  1949. } else {
  1950. {
  1951. WCHAR FileName[MAX_PATH];
  1952. WCHAR FullFileName[MAX_PATH];
  1953. WCHAR *FilePart;
  1954. ZeroMemory(FileName,sizeof(FileName));
  1955. if (NameString.Length > sizeof(FileName)) {
  1956. wcscpy(FileName, L"File name length too big - possibly corrupted");
  1957. } else {
  1958. CopyMemory(FileName,NameString.Buffer,NameString.Length);
  1959. }
  1960. GetFullPathNameW(
  1961. FileName,
  1962. MAX_PATH,
  1963. FullFileName,
  1964. &FilePart
  1965. );
  1966. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld mapped_file( %ws )\n",
  1967. Info->Master,
  1968. Info->ValidCount,
  1969. Info->StandbyCount,
  1970. Info->ModifiedCount,
  1971. Info->SharedCount,
  1972. Info->LockedCount,
  1973. Info->PageTableCount,
  1974. FilePart);
  1975. }
  1976. }
  1977. } else {
  1978. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld No Name for File\n",
  1979. Info->Master,
  1980. Info->ValidCount,
  1981. Info->StandbyCount,
  1982. Info->ModifiedCount,
  1983. Info->SharedCount,
  1984. Info->LockedCount,
  1985. Info->PageTableCount
  1986. );
  1987. }
  1988. }
  1989. }
  1990. Info += 1;
  1991. }
  1992. Info = &PagedPoolBlock;
  1993. if ((Info->ValidCount != 0) ||
  1994. (Info->StandbyCount != 0) ||
  1995. (Info->ModifiedCount != 0)) {
  1996. dprintf("00000000 %4ld %5ld %5ld %5ld %5ld %5ld PagedPool\n",
  1997. Info->ValidCount,
  1998. Info->StandbyCount,
  1999. Info->ModifiedCount,
  2000. Info->SharedCount,
  2001. Info->LockedCount,
  2002. Info->PageTableCount
  2003. );
  2004. }
  2005. //
  2006. // dump the process information.
  2007. //
  2008. BuildDirbaseList();
  2009. Info = ProcessPfns.Next;
  2010. while (Info != NULL) {
  2011. if (Info->Master != 0) {
  2012. PUCHAR ImageName;
  2013. ImageName = DirbaseToImage(Info->Master);
  2014. if ( ImageName ) {
  2015. dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld process ( %s )\n",
  2016. Info->ValidCount,
  2017. Info->StandbyCount,
  2018. Info->ModifiedCount,
  2019. Info->PageTableCount,
  2020. ImageName
  2021. );
  2022. }
  2023. else {
  2024. dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld pagefile section (%lx)\n",
  2025. Info->ValidCount,
  2026. Info->StandbyCount,
  2027. Info->ModifiedCount,
  2028. Info->PageTableCount,
  2029. Info->Master
  2030. );
  2031. }
  2032. }
  2033. Info = Info->Next;
  2034. }
  2035. if (!IgnoreInvalidFrames) {
  2036. for (i=0;i<pKernelMap->Count ;i++) {
  2037. dprintf("-------- %4ld %5ld %5ld ----- %5ld ----- driver ( %ws )\n",
  2038. pKernelMap->Item[i].ValidCount,
  2039. pKernelMap->Item[i].StandbyCount,
  2040. pKernelMap->Item[i].ModifiedCount,
  2041. pKernelMap->Item[i].LockedCount,
  2042. pKernelMap->Item[i].Name
  2043. );
  2044. }
  2045. }
  2046. VirtualFree (InfoStart,0,MEM_RELEASE);
  2047. free(pKernelMap);
  2048. free(NameString.Buffer);
  2049. return;
  2050. }
  2051. VOID
  2052. MemoryUsage (
  2053. IN ULONG64 PfnStart,
  2054. IN ULONG64 LowPage,
  2055. IN ULONG64 HighPage,
  2056. IN ULONG IgnoreInvalidFrames
  2057. )
  2058. /*++
  2059. Routine Description:
  2060. This routine (debugging only) dumps the current memory usage by
  2061. walking the PFN database.
  2062. Arguments:
  2063. None.
  2064. Return Value:
  2065. None.
  2066. --*/
  2067. {
  2068. ULONG PageFrameIndex;
  2069. ULONG Type;
  2070. ULONG PfnSize;
  2071. ULONG64 LastPfn;
  2072. ULONG64 Pfn1;
  2073. ULONG64 Pfn2;
  2074. UNICODE_STRING NameString;
  2075. PPFN_INFO Info;
  2076. PPFN_INFO Info1;
  2077. PPFN_INFO InfoStart;
  2078. PPFN_INFO InfoEnd;
  2079. ULONG InfoSize;
  2080. PFN_INFO ProcessPfns;
  2081. PFN_INFO PagedPoolBlock;
  2082. PPFN_INFO LastProcessInfo = &ProcessPfns;
  2083. ULONG64 Master;
  2084. ULONG64 ControlArea1;
  2085. ULONG result;
  2086. ULONG i;
  2087. ULONG64 PagedPoolStart;
  2088. ULONG64 PagedPoolEnd;
  2089. ULONG64 VirtualAddress;
  2090. ULONG64 MmPagedPoolEnd;
  2091. ULONG64 PteFrame;
  2092. ULONG OriginalPteOffset;
  2093. ULONG PercentComplete=0;
  2094. ULONG OriginalPrototype;
  2095. PKERN_MAP pKernelMap;
  2096. ULONG64 MemoryDescriptorAddress;
  2097. ULONG NumberOfRuns;
  2098. ULONG Offset, Size;
  2099. PMEMORY_RUN PhysicalMemoryBlock;
  2100. ULONG PageLevel;
  2101. ULONG Levels;
  2102. if (!GetExpression("nt!PoolTrackTableExpansion")) {
  2103. MemoryUsage_OldVersion (PfnStart, LowPage, HighPage, IgnoreInvalidFrames);
  2104. return;
  2105. }
  2106. //
  2107. // Get the offset of OriginalPte in the MMPFN
  2108. //
  2109. if (GetFieldOffset("nt!_MMPFN", "OriginalPte", &OriginalPteOffset)) {
  2110. dprintf("Cannot find _MMPFN type");
  2111. return ;
  2112. }
  2113. ProcessPfns.Next = NULL;
  2114. PagedPoolEnd = GetNtDebuggerDataPtrValue(MmPagedPoolEnd);
  2115. NameString.MaximumLength = sizeof(WCHAR) * 1000;
  2116. NameString.Buffer = calloc(1, NameString.MaximumLength);
  2117. if (!NameString.Buffer) {
  2118. return;
  2119. }
  2120. PagedPoolStart = GetNtDebuggerDataPtrValue(MmPagedPoolStart);
  2121. pKernelMap = calloc(1, sizeof(*pKernelMap));
  2122. if (!pKernelMap) {
  2123. free(NameString.Buffer);
  2124. return;
  2125. }
  2126. dprintf (" Building kernel map\n");
  2127. if (BuildKernelMap (pKernelMap) == FALSE) {
  2128. free(pKernelMap);
  2129. free(NameString.Buffer);
  2130. return;
  2131. }
  2132. dprintf (" Finished building kernel map\n");
  2133. RtlZeroMemory (&PagedPoolBlock, sizeof (PFN_INFO));
  2134. PfnSize = GetTypeSize("nt!_MMPFN");
  2135. LastPfn = (PfnStart + HighPage * PfnSize);
  2136. if (MmSubsectionBase == 0) {
  2137. MmSubsectionBase = GetNtDebuggerDataPtrValue(MmSubsectionBase);
  2138. }
  2139. MemoryDescriptorAddress = READ_PVOID (GetExpression ("nt!MmPhysicalMemoryBlock"));
  2140. InitTypeRead (MemoryDescriptorAddress, nt!_PHYSICAL_MEMORY_DESCRIPTOR);
  2141. NumberOfRuns = (ULONG) ReadField (NumberOfRuns);
  2142. PhysicalMemoryBlock = LocalAlloc(LPTR, NumberOfRuns * sizeof (MEMORY_RUN));
  2143. if (PhysicalMemoryBlock == NULL) {
  2144. dprintf("LocalAlloc failed\n");
  2145. free(pKernelMap);
  2146. free(NameString.Buffer);
  2147. return;
  2148. }
  2149. Size = GetTypeSize("nt!_PHYSICAL_MEMORY_RUN");
  2150. GetFieldOffset("nt!_PHYSICAL_MEMORY_DESCRIPTOR", "Run", &Offset);
  2151. for (i = 0; i < NumberOfRuns; i += 1) {
  2152. InitTypeRead(MemoryDescriptorAddress+Offset+i*Size,nt!_PHYSICAL_MEMORY_RUN);
  2153. PhysicalMemoryBlock[i].BasePage = (ULONG64) ReadField (BasePage);
  2154. PhysicalMemoryBlock[i].LastPage = (ULONG64) ReadField (PageCount) +
  2155. PhysicalMemoryBlock[i].BasePage;
  2156. }
  2157. switch (TargetMachine) {
  2158. case IMAGE_FILE_MACHINE_I386:
  2159. Levels = 2;
  2160. break;
  2161. case IMAGE_FILE_MACHINE_IA64:
  2162. Levels = 3;
  2163. break;
  2164. case IMAGE_FILE_MACHINE_AMD64:
  2165. Levels = 4;
  2166. break;
  2167. default:
  2168. dprintf("Not implemented for this platform\n");
  2169. return;
  2170. }
  2171. //
  2172. // Allocate a chunk of memory to hold PFN information. This is resized
  2173. // if it is later determined that the current size is not large enough.
  2174. //
  2175. InfoSize = USAGE_ALLOC_SIZE;
  2176. restart:
  2177. InfoStart = VirtualAlloc (NULL,
  2178. InfoSize,
  2179. MEM_COMMIT,
  2180. PAGE_READWRITE);
  2181. if (InfoStart == NULL) {
  2182. dprintf ("heap allocation for %d bytes failed\n", InfoSize);
  2183. LocalFree(PhysicalMemoryBlock);
  2184. free(pKernelMap);
  2185. free(NameString.Buffer);
  2186. return;
  2187. }
  2188. InfoEnd = InfoStart;
  2189. PageFrameIndex = (ULONG) LowPage;
  2190. Pfn1 = (PfnStart + LowPage * PfnSize);
  2191. while (Pfn1 < LastPfn) {
  2192. ULONG PageLocation=0, PrototypePte=0, ReferenceCount=0;
  2193. ULONG Comp;
  2194. ULONG64 ShareCount=0, PteAddress, WsIndex = 0;
  2195. Comp = ((ULONG) (Pfn1 - (PfnStart + LowPage * PfnSize)))*100 /
  2196. ((ULONG) (LastPfn -(PfnStart + LowPage * PfnSize)));
  2197. if (Comp > PercentComplete) {
  2198. PercentComplete = Comp;
  2199. dprintf("Scanning PFN database - (%02d%% complete) \r", PercentComplete);
  2200. }
  2201. if (CheckControlC()) {
  2202. LocalFree(PhysicalMemoryBlock);
  2203. VirtualFree (InfoStart,0,MEM_RELEASE);
  2204. free(pKernelMap);
  2205. free(NameString.Buffer);
  2206. return;
  2207. }
  2208. for (i = 0; i < NumberOfRuns; i += 1) {
  2209. if ((PageFrameIndex >= PhysicalMemoryBlock[i].BasePage) &&
  2210. (PageFrameIndex < PhysicalMemoryBlock[i].LastPage)) {
  2211. break;
  2212. }
  2213. }
  2214. if (i == NumberOfRuns) {
  2215. //
  2216. // Skip PFNs that don't exist (ie: that aren't in
  2217. // the MmPhysicalMemoryBlock).
  2218. //
  2219. goto NextPfn;
  2220. }
  2221. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PageLocation", PageLocation);
  2222. if ((PageLocation != FreePageList) &&
  2223. (PageLocation != ZeroedPageList) &&
  2224. (PageLocation != BadPageList)) {
  2225. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PrototypePte", PrototypePte);
  2226. GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e2.ReferenceCount", ReferenceCount);
  2227. GetFieldValue(Pfn1, "nt!_MMPFN", "u2.ShareCount", ShareCount);
  2228. GetFieldValue(Pfn1, "nt!_MMPFN", "PteAddress", PteAddress);
  2229. GetFieldValue(Pfn1, "nt!_MMPFN", "u1.WsIndex", WsIndex);
  2230. GetVersionedMmPfnMembers(Pfn1, &PteFrame, NULL);
  2231. Info = NULL;
  2232. if (PrototypePte) {
  2233. GetFieldValue(Pfn1, "nt!_MMPFN", "OriginalPte.u.Soft.Prototype", OriginalPrototype);
  2234. if (OriginalPrototype) {
  2235. //
  2236. // File-backed section.
  2237. // Get the control area from the subsection.
  2238. //
  2239. Master = DbgGetSubsectionAddress (Pfn1 + OriginalPteOffset);
  2240. if (GetFieldValue(Master,
  2241. "nt!_SUBSECTION",
  2242. "ControlArea",
  2243. ControlArea1)) {
  2244. dprintf("unable to get control area pfn %p %p\n",Master,Pfn1);
  2245. LocalFree(PhysicalMemoryBlock);
  2246. VirtualFree (InfoStart,0,MEM_RELEASE);
  2247. free(pKernelMap);
  2248. free(NameString.Buffer);
  2249. return;
  2250. }
  2251. Master = ControlArea1;
  2252. Type = PFN_MAPPED_FILE;
  2253. } else {
  2254. //
  2255. // Pagefile-backed shared memory section.
  2256. //
  2257. Master = PteFrame;
  2258. Type = PFN_MAPPED_PAGEFILE;
  2259. }
  2260. }
  2261. else {
  2262. if ((PteFrame == 0xFFEDCB || PteFrame == 0xFFFFEDCB) ||
  2263. (PteFrame == 0xFFEDCA || PteFrame == 0xFFFFEDCA)) {
  2264. //
  2265. // This is an AWE frame (the PTE frame field has no
  2266. // meaning). The PteAddress field is already marked
  2267. // for delete so sanitize it for use below.
  2268. //
  2269. PteAddress &= ~0x1;
  2270. Master = 0xFFFFEDCB;
  2271. Type = PFN_AWE;
  2272. }
  2273. else {
  2274. Master = 0;
  2275. PageLevel = 0;
  2276. if(WsIndex != 0) {
  2277. //
  2278. // This page is in a working set.
  2279. // Recursively walk up the page maps until we find a
  2280. // frame whose containing frame is itself. This yields
  2281. // a unique process top level frame to use as the master.
  2282. //
  2283. do {
  2284. PageLevel += 1;
  2285. Pfn2 = PfnStart + PteFrame*PfnSize;
  2286. GetVersionedMmPfnMembers(Pfn2, &Master, NULL);
  2287. if ((Master == 0) || (Master > HighPage)) {
  2288. dprintf("Invalid PTE frame %p %p\n", Pfn1, Master);
  2289. PrintPfn64(Pfn1);
  2290. PrintPfn64(Pfn2);
  2291. goto NextPfn;
  2292. }
  2293. if (Master == PteFrame) {
  2294. break;
  2295. }
  2296. PteFrame = Master;
  2297. if (CheckControlC()) {
  2298. dprintf("Stop PTE frame %p %p\n", Pfn1, Master);
  2299. break;
  2300. }
  2301. } while ((BuildNo > 2440));
  2302. }
  2303. Type = PFN_PRIVATE;
  2304. if (PageLevel == Levels) {
  2305. //
  2306. // We had to go the all page levels up so this must not be a page table page.
  2307. // Tally all pages which are not protos and have a valid PTE
  2308. // address field.
  2309. //
  2310. VirtualAddress = DbgGetVirtualAddressMappedByPte (PteAddress);
  2311. for (i = 0; i < pKernelMap->Count; i += 1) {
  2312. if ((VirtualAddress >= pKernelMap->Item[i].StartVa) &&
  2313. (VirtualAddress < pKernelMap->Item[i].EndVa)) {
  2314. if ((PageLocation == ModifiedPageList) ||
  2315. (PageLocation == ModifiedNoWritePageList)) {
  2316. pKernelMap->Item[i].ModifiedCount += _KB;
  2317. if (ReferenceCount > 0) {
  2318. pKernelMap->Item[i].LockedCount += _KB;
  2319. }
  2320. } else if ((PageLocation == StandbyPageList) ||
  2321. (PageLocation == TransitionPage)) {
  2322. pKernelMap->Item[i].StandbyCount += _KB;
  2323. if (ReferenceCount > 0) {
  2324. pKernelMap->Item[i].LockedCount += _KB;
  2325. }
  2326. } else {
  2327. pKernelMap->Item[i].ValidCount += _KB;
  2328. if (ShareCount > 1) {
  2329. pKernelMap->Item[i].SharedCount += _KB;
  2330. if (ReferenceCount > 1) {
  2331. pKernelMap->Item[i].LockedCount += _KB;
  2332. }
  2333. }
  2334. }
  2335. goto NextPfn;
  2336. }
  2337. }
  2338. }
  2339. }
  2340. VirtualAddress = DbgGetVirtualAddressMappedByPte (PteAddress);
  2341. if ((VirtualAddress >= PagedPoolStart) &&
  2342. (VirtualAddress <= PagedPoolEnd)) {
  2343. //
  2344. // This is paged pool, put it in the paged pool cell.
  2345. //
  2346. Info = &PagedPoolBlock;
  2347. }
  2348. }
  2349. if (Info == NULL) {
  2350. //
  2351. // See if there is already a master info block.
  2352. //
  2353. for (Info = InfoStart; Info < InfoEnd; Info += 1) {
  2354. if (Info->Master == Master) {
  2355. break;
  2356. }
  2357. }
  2358. if (Info == InfoEnd) {
  2359. InfoEnd += 1;
  2360. if ((PUCHAR)Info >= ((PUCHAR)InfoStart + InfoSize) - sizeof(PFN_INFO)) {
  2361. //
  2362. // Don't bother copying the old array - free it
  2363. // instead to improve our chances of getting a
  2364. // bigger contiguous chunk.
  2365. //
  2366. VirtualFree (InfoStart,0,MEM_RELEASE);
  2367. InfoSize += USAGE_ALLOC_SIZE;
  2368. goto restart;
  2369. }
  2370. RtlZeroMemory (Info, sizeof (PFN_INFO));
  2371. Info->Master = Master;
  2372. Info->Type = Type;
  2373. GetFieldValue(Pfn1, "nt!_MMPFN", "OriginalPte.u.Long", Info->OriginalPte);
  2374. }
  2375. }
  2376. // dprintf("Pfn1 %p, PageLoc %x, Master %I64x\n", Pfn1, PageLocation, Master);
  2377. if ((PageLocation == ModifiedPageList) ||
  2378. (PageLocation == ModifiedNoWritePageList)) {
  2379. Info->ModifiedCount += _KB;
  2380. if (ReferenceCount > 0) {
  2381. Info->LockedCount += _KB;
  2382. }
  2383. } else if ((PageLocation == StandbyPageList) ||
  2384. (PageLocation == TransitionPage)) {
  2385. Info->StandbyCount += _KB;
  2386. if (ReferenceCount > 0) {
  2387. Info->LockedCount += _KB;
  2388. }
  2389. } else {
  2390. Info->ValidCount += _KB;
  2391. if (ShareCount > 1) {
  2392. Info->SharedCount += _KB;
  2393. if (ReferenceCount > 1) {
  2394. Info->LockedCount += _KB;
  2395. }
  2396. }
  2397. }
  2398. if ((PteAddress >= DbgGetPdeAddress (0x0)) &&
  2399. (PteAddress <= DbgGetPdeAddress (0xFFFFFFFFFFFFFFFF))) {
  2400. Info->PageTableCount += _KB;
  2401. }
  2402. }
  2403. NextPfn:
  2404. Pfn1 = (Pfn1 + PfnSize);
  2405. PageFrameIndex += 1;
  2406. }
  2407. dprintf("Scanning PFN database - (%d%% complete) \r", 100);
  2408. //
  2409. // dump the results.
  2410. //
  2411. #if 0
  2412. dprintf("Physical Page Summary:\n");
  2413. dprintf(" - number of physical pages: %ld\n",
  2414. MmNumberOfPhysicalPages);
  2415. dprintf(" - Zeroed Pages %ld\n", MmZeroedPageListHead.Total);
  2416. dprintf(" - Free Pages %ld\n", MmFreePageListHead.Total);
  2417. dprintf(" - Standby Pages %ld\n", MmStandbyPageListHead.Total);
  2418. dprintf(" - Modified Pages %ld\n", MmModifiedPageListHead.Total);
  2419. dprintf(" - Modified NoWrite Pages %ld\n", MmModifiedNoWritePageListHead.Total);
  2420. dprintf(" - Bad Pages %ld\n", MmBadPageListHead.Total);
  2421. #endif
  2422. dprintf("\n\n Usage Summary (in Kb):\n");
  2423. for (Info = InfoStart; Info < InfoEnd; Info += 1) {
  2424. if (CheckControlC()) {
  2425. LocalFree(PhysicalMemoryBlock);
  2426. VirtualFree (InfoStart,0,MEM_RELEASE);
  2427. free(pKernelMap);
  2428. free(NameString.Buffer);
  2429. return;
  2430. }
  2431. if (Info->Type & PFN_AWE) {
  2432. continue;
  2433. }
  2434. if ((Info->Type & (PFN_MAPPED_FILE | PFN_MAPPED_PAGEFILE)) == 0) {
  2435. LastProcessInfo->Next = Info;
  2436. LastProcessInfo = Info;
  2437. }
  2438. }
  2439. dprintf("Control Valid Standby Dirty Shared Locked PageTables name\n");
  2440. for (Info = InfoStart; Info < InfoEnd; Info += 1) {
  2441. ULONG64 FilePointer;
  2442. ULONG64 NameBuffer;
  2443. if (CheckControlC()) {
  2444. LocalFree(PhysicalMemoryBlock);
  2445. VirtualFree (InfoStart,0,MEM_RELEASE);
  2446. free(pKernelMap);
  2447. free(NameString.Buffer);
  2448. return;
  2449. }
  2450. //
  2451. // Skip private pages...
  2452. //
  2453. if ((Info->Type & (PFN_MAPPED_FILE)) == 0) {
  2454. continue;
  2455. }
  2456. //
  2457. // Show sharable pages...
  2458. //
  2459. //
  2460. // Get the control area's file pointer.
  2461. //
  2462. if (GetFieldValue(Info->Master,
  2463. "nt!_CONTROL_AREA",
  2464. "FilePointer",
  2465. FilePointer)) {
  2466. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Bad Control Area\n",
  2467. Info->Master,
  2468. Info->ValidCount,
  2469. Info->StandbyCount,
  2470. Info->ModifiedCount,
  2471. Info->SharedCount,
  2472. Info->LockedCount,
  2473. Info->PageTableCount
  2474. );
  2475. continue;
  2476. }
  2477. if (FilePointer == 0) {
  2478. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Page File Section\n",
  2479. Info->Master,
  2480. Info->ValidCount,
  2481. Info->StandbyCount,
  2482. Info->ModifiedCount,
  2483. Info->SharedCount,
  2484. Info->LockedCount,
  2485. Info->PageTableCount
  2486. );
  2487. continue;
  2488. }
  2489. //
  2490. // Get the file pointer.
  2491. //
  2492. if (GetFieldValue(FilePointer,
  2493. "nt!_FILE_OBJECT",
  2494. "FileName.Length",
  2495. NameString.Length)) {
  2496. dprintf("unable to get subsection %p\n",FilePointer);
  2497. }
  2498. if (NameString.Length && (NameString.Length < 1024)) {
  2499. //
  2500. // Get the name string.
  2501. //
  2502. if (NameString.Length > NameString.MaximumLength) {
  2503. NameString.Length = NameString.MaximumLength - 1;
  2504. }
  2505. GetFieldValue(FilePointer,
  2506. "nt!_FILE_OBJECT",
  2507. "FileName.Buffer",
  2508. NameBuffer);
  2509. if ((!ReadMemory(NameBuffer,
  2510. NameString.Buffer,
  2511. NameString.Length,
  2512. &result)) || (result < NameString.Length)) {
  2513. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Name Not Available\n",
  2514. Info->Master,
  2515. Info->ValidCount,
  2516. Info->StandbyCount,
  2517. Info->ModifiedCount,
  2518. Info->SharedCount,
  2519. Info->LockedCount,
  2520. Info->PageTableCount
  2521. );
  2522. } else {
  2523. WCHAR FileName[MAX_PATH];
  2524. WCHAR FullFileName[MAX_PATH];
  2525. WCHAR *FilePart;
  2526. ZeroMemory(FileName,sizeof(FileName));
  2527. if (NameString.Length > sizeof(FileName)) {
  2528. wcscpy(FileName, L"File name length too big - possibly corrupted");
  2529. } else {
  2530. CopyMemory(FileName,NameString.Buffer,NameString.Length);
  2531. }
  2532. GetFullPathNameW (FileName,
  2533. MAX_PATH,
  2534. FullFileName,
  2535. &FilePart);
  2536. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld mapped_file( %ws )\n",
  2537. Info->Master,
  2538. Info->ValidCount,
  2539. Info->StandbyCount,
  2540. Info->ModifiedCount,
  2541. Info->SharedCount,
  2542. Info->LockedCount,
  2543. Info->PageTableCount,
  2544. FilePart);
  2545. }
  2546. continue;
  2547. }
  2548. dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld No Name for File\n",
  2549. Info->Master,
  2550. Info->ValidCount,
  2551. Info->StandbyCount,
  2552. Info->ModifiedCount,
  2553. Info->SharedCount,
  2554. Info->LockedCount,
  2555. Info->PageTableCount
  2556. );
  2557. }
  2558. Info = &PagedPoolBlock;
  2559. if ((Info->ValidCount != 0) ||
  2560. (Info->StandbyCount != 0) ||
  2561. (Info->ModifiedCount != 0)) {
  2562. dprintf("00000000 %4ld %5ld %5ld %5ld %5ld %5ld PagedPool\n",
  2563. Info->ValidCount,
  2564. Info->StandbyCount,
  2565. Info->ModifiedCount,
  2566. Info->SharedCount,
  2567. Info->LockedCount,
  2568. Info->PageTableCount
  2569. );
  2570. }
  2571. //
  2572. // dump the process information.
  2573. //
  2574. BuildDirbaseList();
  2575. Info = ProcessPfns.Next;
  2576. while (Info != NULL) {
  2577. if (Info->Master == 0xFFFFEDCB) {
  2578. // AWE
  2579. dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld AWE (%lx)\n",
  2580. Info->ValidCount,
  2581. Info->StandbyCount,
  2582. Info->ModifiedCount,
  2583. Info->PageTableCount,
  2584. Info->Master
  2585. );
  2586. } else if (Info->Master != 0) {
  2587. PUCHAR ImageName;
  2588. ImageName = DirbaseToImage(Info->Master);
  2589. if ( ImageName ) {
  2590. dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld process ( %s )\n",
  2591. Info->ValidCount,
  2592. Info->StandbyCount,
  2593. Info->ModifiedCount,
  2594. Info->PageTableCount,
  2595. ImageName
  2596. );
  2597. }
  2598. else {
  2599. dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld pagefile section (%lx)\n",
  2600. Info->ValidCount,
  2601. Info->StandbyCount,
  2602. Info->ModifiedCount,
  2603. Info->PageTableCount,
  2604. Info->Master
  2605. );
  2606. }
  2607. }
  2608. Info = Info->Next;
  2609. }
  2610. if (!IgnoreInvalidFrames) {
  2611. for (i=0;i<pKernelMap->Count ;i++) {
  2612. dprintf("-------- %4ld %5ld %5ld ----- %5ld ----- driver ( %ws )\n",
  2613. pKernelMap->Item[i].ValidCount,
  2614. pKernelMap->Item[i].StandbyCount,
  2615. pKernelMap->Item[i].ModifiedCount,
  2616. pKernelMap->Item[i].LockedCount,
  2617. pKernelMap->Item[i].Name
  2618. );
  2619. }
  2620. }
  2621. LocalFree(PhysicalMemoryBlock);
  2622. VirtualFree (InfoStart,0,MEM_RELEASE);
  2623. free(pKernelMap);
  2624. free(NameString.Buffer);
  2625. return;
  2626. }
  2627. NTSTATUS
  2628. BuildDirbaseList (
  2629. VOID
  2630. )
  2631. {
  2632. ULONG64 Next;
  2633. ULONG64 ProcessHead;
  2634. ULONG64 Process;
  2635. NTSTATUS status=0;
  2636. ULONG ActiveProcessLinksOffset, DirectoryTableBaseOffset;
  2637. FIELD_INFO offField[] = {
  2638. {"ActiveProcessLinks", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL},
  2639. {"Pcb.DirectoryTableBase", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL}
  2640. };
  2641. SYM_DUMP_PARAM TypeSym ={
  2642. sizeof (SYM_DUMP_PARAM), "_EPROCESS", DBG_DUMP_NO_PRINT, 0,
  2643. NULL, NULL, NULL, 2, &offField[0]
  2644. };
  2645. // Get the offset of ActiveProcessLinks in EPROCESS
  2646. if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
  2647. return FALSE;
  2648. }
  2649. ActiveProcessLinksOffset = (ULONG) offField[0].address;
  2650. DirectoryTableBaseOffset = (ULONG) offField[1].address;
  2651. MaxDirbase = 0;
  2652. ProcessHead = GetNtDebuggerData(PsActiveProcessHead );
  2653. if (!ProcessHead) {
  2654. return STATUS_OBJECT_NAME_NOT_FOUND;
  2655. }
  2656. if (GetFieldValue(ProcessHead, "nt!_LIST_ENTRY", "Flink", Next)) {
  2657. return STATUS_OBJECT_NAME_NOT_FOUND;
  2658. }
  2659. //Next = List.Flink;
  2660. if (Next == 0) {
  2661. dprintf("PsActiveProcessHead is NULL!\n");
  2662. return STATUS_INVALID_PARAMETER;
  2663. }
  2664. while(Next != ProcessHead) {
  2665. ULONG64 PageFrameNumber=0;
  2666. Process = Next - ActiveProcessLinksOffset;
  2667. if (GetFieldValue(Process,
  2668. "nt!_EPROCESS",
  2669. "ImageFileName",
  2670. Names[MaxDirbase])) {
  2671. dprintf("Unable to read _EPROCESS at %p\n",Process);
  2672. MaxDirbase = 0;
  2673. return status;
  2674. }
  2675. if ( (Names[ MaxDirbase ])[0] == '\0' ) {
  2676. strcpy((PCHAR)&Names[MaxDirbase][0],(PCHAR)"SystemProcess");
  2677. }
  2678. GetFieldValue(Process,"_EPROCESS","ImageFileName",Names[MaxDirbase]);
  2679. GetFieldValue(Process + DirectoryTableBaseOffset, "nt!HARDWARE_PTE", "PageFrameNumber", PageFrameNumber);
  2680. DirBases[MaxDirbase++] = PageFrameNumber;
  2681. GetFieldValue(Process, "_EPROCESS", "ActiveProcessLinks.Flink", Next);
  2682. if (CheckControlC()) {
  2683. MaxDirbase = 0;
  2684. return STATUS_INVALID_PARAMETER;
  2685. }
  2686. }
  2687. return STATUS_INVALID_PARAMETER;
  2688. }
  2689. PUCHAR
  2690. DirbaseToImage(
  2691. IN ULONG64 DirBase
  2692. )
  2693. {
  2694. ULONG i;
  2695. for(i=0;i<MaxDirbase;i++) {
  2696. if ( DirBases[i] == DirBase ) {
  2697. return &Names[i][0];
  2698. }
  2699. }
  2700. return NULL;
  2701. }
  2702. LOGICAL
  2703. BuildKernelMap (
  2704. OUT PKERN_MAP KernelMap
  2705. )
  2706. {
  2707. ULONG64 Next;
  2708. ULONG64 ListHead;
  2709. NTSTATUS Status = 0;
  2710. ULONG Result;
  2711. ULONG64 DataTable;
  2712. ULONG i = 0;
  2713. ULONG64 Flink;
  2714. ULONG InLoadOrderLinksOffset;
  2715. FIELD_INFO offField = {"InLoadOrderLinks", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
  2716. SYM_DUMP_PARAM TypeSym ={
  2717. sizeof (SYM_DUMP_PARAM), "nt!_LDR_DATA_TABLE_ENTRY", DBG_DUMP_NO_PRINT, 0,
  2718. NULL, NULL, NULL, 1, &offField
  2719. };
  2720. // Get the offset of InLoadOrderLinks in LDR_DATA_TABLE_ENTRY
  2721. if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
  2722. return FALSE;
  2723. }
  2724. InLoadOrderLinksOffset = (ULONG) offField.address;
  2725. ListHead = GetNtDebuggerData(PsLoadedModuleList );
  2726. if (!ListHead) {
  2727. dprintf("Couldn't get offset of PsLoadedModuleListHead\n");
  2728. return FALSE;
  2729. }
  2730. if (GetFieldValue(ListHead, "nt!_LIST_ENTRY", "Flink", Flink)) {
  2731. dprintf("Unable to get value of PsLoadedModuleListHead\n");
  2732. return FALSE;
  2733. }
  2734. Next = Flink;
  2735. if (Next == 0) {
  2736. dprintf("PsLoadedModuleList is NULL!\n");
  2737. return FALSE;
  2738. }
  2739. while (Next != ListHead) {
  2740. ULONG64 BaseDllNameBuffer, DllBase;
  2741. ULONG BaseDllNameLength=0, SizeOfImage;
  2742. if (CheckControlC()) {
  2743. return FALSE;
  2744. }
  2745. DataTable = (Next - InLoadOrderLinksOffset);
  2746. if (GetFieldValue(DataTable,
  2747. "nt!_LDR_DATA_TABLE_ENTRY",
  2748. "BaseDllName.Buffer",
  2749. BaseDllNameBuffer)) {
  2750. dprintf("Unable to read LDR_DATA_TABLE_ENTRY at %08p\n",
  2751. DataTable);
  2752. return FALSE;
  2753. }
  2754. GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","BaseDllName.Length",BaseDllNameLength);
  2755. GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","DllBase",DllBase);
  2756. GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","SizeOfImage",SizeOfImage);
  2757. if (BaseDllNameLength >= sizeof(KernelMap->Item[0].Name))
  2758. {
  2759. BaseDllNameLength = sizeof(KernelMap->Item[0].Name) -1;
  2760. }
  2761. //
  2762. // Get the base DLL name.
  2763. //
  2764. if ((!ReadMemory(BaseDllNameBuffer,
  2765. &KernelMap->Item[i].Name[0],
  2766. BaseDllNameLength,
  2767. &Result)) || (Result < BaseDllNameLength)) {
  2768. dprintf("Unable to read name string at %08p - status %08lx\n",
  2769. DataTable,
  2770. Status);
  2771. return FALSE;
  2772. }
  2773. KernelMap->Item[i].Name[BaseDllNameLength/2] = L'\0';
  2774. KernelMap->Item[i].StartVa = DllBase;
  2775. KernelMap->Item[i].EndVa = KernelMap->Item[i].StartVa +
  2776. (ULONG)SizeOfImage;
  2777. i += 1;
  2778. GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","InLoadOrderLinks.Flink", Next);
  2779. }
  2780. KernelMap->Item[i].StartVa = GetNtDebuggerDataPtrValue(MmPagedPoolStart);
  2781. KernelMap->Item[i].EndVa = GetNtDebuggerDataPtrValue(MmPagedPoolEnd);
  2782. wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"Paged Pool");
  2783. i+= 1;
  2784. #if 0
  2785. KernelMap->Item[i].StartVa = DbgGetPteAddress (0xffffffff80000000UI64);
  2786. KernelMap->Item[i].EndVa = DbgGetPteAddress (0xffffffffffffffffUI64);
  2787. wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"System Page Tables");
  2788. i+= 1;
  2789. KernelMap->Item[i].StartVa = DbgGetPdeAddress (0x80000000);
  2790. KernelMap->Item[i].EndVa = DbgGetPdeAddress (0xffffffff);
  2791. wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"System Page Tables");
  2792. i+= 1;
  2793. #endif 0
  2794. // LWFIX: Both PTEs and nonpaged pool can be in multiple virtually discontiguous
  2795. // areas. Fix this.
  2796. KernelMap->Item[i].StartVa = DbgGetVirtualAddressMappedByPte (
  2797. GetNtDebuggerDataPtrValue(MmSystemPtesStart));
  2798. KernelMap->Item[i].EndVa = DbgGetVirtualAddressMappedByPte (
  2799. GetNtDebuggerDataPtrValue(MmSystemPtesEnd)) + 1;
  2800. wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"Kernel Stacks");
  2801. i+= 1;
  2802. KernelMap->Item[i].StartVa = GetNtDebuggerDataPtrValue(MmNonPagedPoolStart);
  2803. KernelMap->Item[i].EndVa = GetNtDebuggerDataPtrValue(MmNonPagedPoolEnd);
  2804. wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"NonPaged Pool");
  2805. i+= 1;
  2806. KernelMap->Count = i;
  2807. return TRUE;
  2808. }
  2809. ULONG64 SpecialPoolStart;
  2810. ULONG64 SpecialPoolEnd;
  2811. #define VI_POOL_FREELIST_END ((ULONG64)-1)
  2812. LOGICAL
  2813. VerifierDumpPool (
  2814. IN ULONG64 Verifier
  2815. )
  2816. {
  2817. ULONG64 HashTableAddress;
  2818. ULONG PoolTag;
  2819. ULONG i;
  2820. ULONG64 Region;
  2821. ULONG64 HashEntry;
  2822. ULONG64 PoolHashSize;
  2823. ULONG64 NumberOfBytes;
  2824. ULONG SizeofEntry;
  2825. LONG64 FreeListNext;
  2826. LOGICAL NewTableFormat;
  2827. //
  2828. // Display the current and peak pool usage by allocation & bytes.
  2829. //
  2830. InitTypeRead(Verifier, nt!_MI_VERIFIER_DRIVER_ENTRY);
  2831. dprintf("\n");
  2832. dprintf("Current Pool Allocations %08I64lx %08I64lx\n",
  2833. ReadField(CurrentPagedPoolAllocations),
  2834. ReadField(CurrentNonPagedPoolAllocations));
  2835. dprintf("Current Pool Bytes %08I64lx %08I64lx\n",
  2836. ReadField(PagedBytes),
  2837. ReadField(NonPagedBytes));
  2838. dprintf("Peak Pool Allocations %08I64lx %08I64lx\n",
  2839. ReadField(PeakPagedPoolAllocations),
  2840. ReadField(PeakNonPagedPoolAllocations));
  2841. dprintf("Peak Pool Bytes %08I64lx %08I64lx\n",
  2842. ReadField(PeakPagedBytes),
  2843. ReadField(PeakNonPagedBytes));
  2844. //
  2845. // If no current allocations then the dump is over.
  2846. //
  2847. if ((ReadField(CurrentPagedPoolAllocations) == 0) &&
  2848. (ReadField(CurrentNonPagedPoolAllocations) == 0)) {
  2849. dprintf("\n");
  2850. return FALSE;
  2851. }
  2852. dprintf("\nPoolAddress SizeInBytes Tag CallersAddress\n");
  2853. i = 0;
  2854. SizeofEntry = GetTypeSize("nt!_VI_POOL_ENTRY");
  2855. if (SizeofEntry == 0)
  2856. {
  2857. dprintf("Unable to get size of nt!_VI_POOL_ENTRY\n");
  2858. return 0;
  2859. }
  2860. PoolHashSize = ReadField(PoolHashSize);
  2861. if (PoolHashSize == 0) {
  2862. //
  2863. // This is a kernel using the new chained slisted verifier pool
  2864. // tracking tables. It must be walked in a different fashion.
  2865. //
  2866. NewTableFormat = TRUE;
  2867. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  2868. HashTableAddress = ReadField(PoolPageHeaders.Alignment);
  2869. Region = ReadField(PoolPageHeaders.Region);
  2870. HashTableAddress = ((HashTableAddress >> 25) << 4) + Region;
  2871. }
  2872. else {
  2873. HashTableAddress = ReadField(PoolPageHeaders.Next);
  2874. }
  2875. PoolHashSize = PageSize / SizeofEntry;
  2876. PoolHashSize -= 1; // skip first entry - it's a header.
  2877. HashEntry = HashTableAddress + SizeofEntry;
  2878. }
  2879. else {
  2880. NewTableFormat = FALSE;
  2881. HashTableAddress = ReadField(PoolHash);
  2882. HashEntry = HashTableAddress;
  2883. }
  2884. NextPage:
  2885. for (i = 0; i < PoolHashSize; i += 1, HashEntry += SizeofEntry) {
  2886. if (NewTableFormat == FALSE) {
  2887. if (GetFieldValue(HashEntry, "nt!_VI_POOL_ENTRY", "FreeListNext", FreeListNext)) {
  2888. dprintf("%08p: Unable to get verifier hash page\n", HashEntry);
  2889. return FALSE;
  2890. }
  2891. //
  2892. // Sign extend if necessary.
  2893. //
  2894. if (!IsPtr64()) {
  2895. FreeListNext = (ULONG64)(LONG64)(LONG)FreeListNext;
  2896. }
  2897. //
  2898. // Skip freelist entries.
  2899. //
  2900. if ((FreeListNext == VI_POOL_FREELIST_END) ||
  2901. ((FreeListNext & MINLONG64_PTR) == 0)) {
  2902. continue;
  2903. }
  2904. }
  2905. InitTypeRead(HashEntry, nt!_VI_POOL_ENTRY);
  2906. NumberOfBytes = ReadField(InUse.NumberOfBytes);
  2907. if (NewTableFormat == TRUE) {
  2908. if (NumberOfBytes & 0x1) {
  2909. //
  2910. // This entry is free since byte counts are never odd.
  2911. //
  2912. if (CheckControlC()) {
  2913. return TRUE;
  2914. }
  2915. continue;
  2916. }
  2917. }
  2918. PoolTag = (ULONG) ReadField(InUse.Tag);
  2919. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  2920. dprintf("%p 0x%08p %c%c%c%c ",
  2921. ReadField(InUse.VirtualAddress),
  2922. NumberOfBytes,
  2923. (PP(PoolTag) & ~0x80),
  2924. PP(PoolTag >> 8),
  2925. PP(PoolTag >> 16),
  2926. PP(PoolTag >> 24)
  2927. );
  2928. #undef PP
  2929. dprintf("%p\n", ReadField(InUse.CallingAddress));
  2930. if (CheckControlC()) {
  2931. return TRUE;
  2932. }
  2933. }
  2934. if (NewTableFormat == TRUE) {
  2935. //
  2936. // The new table format is discontiguous so walk to the next entry
  2937. // (if there is one) to display it.
  2938. //
  2939. InitTypeRead (HashTableAddress, nt!_VI_POOL_PAGE_HEADER);
  2940. HashTableAddress = ReadField(NextPage);
  2941. if (HashTableAddress != 0) {
  2942. PoolHashSize = PageSize / SizeofEntry;
  2943. PoolHashSize -= 1; // skip first entry - it's a header.
  2944. HashEntry = HashTableAddress + SizeofEntry;
  2945. goto NextPage;
  2946. }
  2947. }
  2948. dprintf("\n");
  2949. return FALSE;
  2950. }
  2951. #if 0
  2952. typedef struct _COMMIT_INFO {
  2953. LPSTR Name;
  2954. ULONG Index;
  2955. } COMMIT_INFO, *PCOMMIT_INFO;
  2956. COMMIT_INFO CommitInfo[] = {
  2957. "MM_DBG_COMMIT_NONPAGED_POOL_EXPANSION", 0,
  2958. "MM_DBG_COMMIT_PAGED_POOL_PAGETABLE", 1,
  2959. "MM_DBG_COMMIT_PAGED_POOL_PAGES", 2,
  2960. "MM_DBG_COMMIT_SESSION_POOL_PAGE_TABLES", 3,
  2961. "MM_DBG_COMMIT_ALLOCVM1", 4,
  2962. "MM_DBG_COMMIT_ALLOCVM_SEGMENT", 5,
  2963. "MM_DBG_COMMIT_IMAGE", 6,
  2964. "MM_DBG_COMMIT_PAGEFILE_BACKED_SHMEM", 7,
  2965. "MM_DBG_COMMIT_INDEPENDENT_PAGES", 8,
  2966. "MM_DBG_COMMIT_CONTIGUOUS_PAGES", 9,
  2967. "MM_DBG_COMMIT_MDL_PAGES", 0xA,
  2968. "MM_DBG_COMMIT_NONCACHED_PAGES", 0xB,
  2969. "MM_DBG_COMMIT_MAPVIEW_DATA", 0xC,
  2970. "MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY", 0xD,
  2971. "MM_DBG_COMMIT_EXTRA_SYSTEM_PTES", 0xE,
  2972. "MM_DBG_COMMIT_DRIVER_PAGING_AT_INIT", 0xF,
  2973. "MM_DBG_COMMIT_PAGEFILE_FULL", 0x10,
  2974. "MM_DBG_COMMIT_PROCESS_CREATE", 0x11,
  2975. "MM_DBG_COMMIT_KERNEL_STACK_CREATE", 0x12,
  2976. "MM_DBG_COMMIT_SET_PROTECTION", 0x13,
  2977. "MM_DBG_COMMIT_SESSION_CREATE", 0x14,
  2978. "MM_DBG_COMMIT_SESSION_IMAGE_PAGES", 0x15,
  2979. "MM_DBG_COMMIT_SESSION_PAGETABLE_PAGES", 0x16,
  2980. "MM_DBG_COMMIT_SESSION_SHARED_IMAGE", 0x17,
  2981. "MM_DBG_COMMIT_DRIVER_PAGES", 0x18,
  2982. "MM_DBG_COMMIT_INSERT_VAD", 0x19,
  2983. "MM_DBG_COMMIT_SESSION_WS_INIT", 0x1A,
  2984. "MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES", 0x1B,
  2985. "MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES", 0x1C,
  2986. "MM_DBG_COMMIT_SPECIAL_POOL_PAGES", 0x1D,
  2987. "MM_DBG_COMMIT_SMALL", 0x1F,
  2988. "MM_DBG_COMMIT_EXTRA_WS_PAGES", 0x20,
  2989. "MM_DBG_COMMIT_EXTRA_INITIAL_SESSION_WS_PAGES", 0x21,
  2990. "MM_DBG_COMMIT_ALLOCVM_PROCESS", 0x22,
  2991. "MM_DBG_COMMIT_INSERT_VAD_PT", 0x23,
  2992. "MM_DBG_COMMIT_ALLOCVM_PROCESS2", 0x24,
  2993. "MM_DBG_COMMIT_CHARGE_NORMAL", 0x25,
  2994. "MM_DBG_COMMIT_CHARGE_CAUSE_POPUP", 0x26,
  2995. "MM_DBG_COMMIT_CHARGE_CANT_EXPAND", 0x27,
  2996. "MM_DBG_COMMIT_RETURN_NONPAGED_POOL_EXPANSION", 0x40,
  2997. "MM_DBG_COMMIT_RETURN_PAGED_POOL_PAGES", 0x41,
  2998. "MM_DBG_COMMIT_RETURN_SESSION_DATAPAGE", 0x42,
  2999. "MM_DBG_COMMIT_RETURN_ALLOCVM_SEGMENT", 0x43,
  3000. "MM_DBG_COMMIT_RETURN_ALLOCVM2", 0x44,
  3001. "MM_DBG_COMMIT_RETURN_IMAGE_NO_LARGE_CA", 0x46,
  3002. "MM_DBG_COMMIT_RETURN_PTE_RANGE", 0x47,
  3003. "MM_DBG_COMMIT_RETURN_NTFREEVM1", 0x48,
  3004. "MM_DBG_COMMIT_RETURN_NTFREEVM2", 0x49,
  3005. "MM_DBG_COMMIT_RETURN_INDEPENDENT_PAGES", 0x4A,
  3006. "MM_DBG_COMMIT_RETURN_AWE_EXCESS", 0x4B,
  3007. "MM_DBG_COMMIT_RETURN_MDL_PAGES", 0x4C,
  3008. "MM_DBG_COMMIT_RETURN_NONCACHED_PAGES", 0x4D,
  3009. "MM_DBG_COMMIT_RETURN_SESSION_CREATE_FAILURE", 0x4E,
  3010. "MM_DBG_COMMIT_RETURN_PAGETABLES", 0x4F,
  3011. "MM_DBG_COMMIT_RETURN_PROTECTION", 0x50,
  3012. "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE1", 0x51,
  3013. "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE2", 0x52,
  3014. "MM_DBG_COMMIT_RETURN_PAGEFILE_FULL", 0x53,
  3015. "MM_DBG_COMMIT_RETURN_SESSION_DEREFERENCE", 0x54,
  3016. "MM_DBG_COMMIT_RETURN_VAD", 0x55,
  3017. "MM_DBG_COMMIT_RETURN_PROCESS_CREATE_FAILURE1", 0x56,
  3018. "MM_DBG_COMMIT_RETURN_PROCESS_DELETE", 0x57,
  3019. "MM_DBG_COMMIT_RETURN_PROCESS_CLEAN_PAGETABLES", 0x58,
  3020. "MM_DBG_COMMIT_RETURN_KERNEL_STACK_DELETE", 0x59,
  3021. "MM_DBG_COMMIT_RETURN_SESSION_DRIVER_LOAD_FAILURE1",0x5A,
  3022. "MM_DBG_COMMIT_RETURN_DRIVER_INIT_CODE", 0x5B,
  3023. "MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD", 0x5C,
  3024. "MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD1", 0x5D,
  3025. "MM_DBG_COMMIT_RETURN_NORMAL", 0x5E,
  3026. "MM_DBG_COMMIT_RETURN_PF_FULL_EXTEND", 0x5F,
  3027. "MM_DBG_COMMIT_RETURN_EXTENDED", 0x60,
  3028. "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE3", 0x61,
  3029. };
  3030. VOID
  3031. DumpCommitTracker ()
  3032. {
  3033. ULONG64 MmTrackCommit;
  3034. ULONG64 PfnEntry;
  3035. ULONG64 displacement;
  3036. ULONG64 AcquiredAddress;
  3037. ULONG64 ReleasedAddress;
  3038. CHAR SymbolBuffer[80];
  3039. PCHAR SymPointer;
  3040. ULONG EntrySize;
  3041. ULONG result;
  3042. ULONG64 ReadCount;
  3043. ULONG64 i;
  3044. ULONG64 j;
  3045. PSIZE_T LocalData;
  3046. PCHAR local;
  3047. ULONG64 NumberOfCommitEntries;
  3048. MmTrackCommit = GetExpression ("nt!MmTrackCommit");
  3049. if (MmTrackCommit == 0) {
  3050. dprintf("%08p: Unable to get commit track data.\n", MmTrackCommit);
  3051. return;
  3052. }
  3053. PfnEntry = MmTrackCommit;
  3054. #if 0
  3055. NumberOfCommitEntries = GetUlongValue ("nt!MiMaxPfnTimings");
  3056. EntrySize = GetTypeSize("SIZE_T");
  3057. #else
  3058. NumberOfCommitEntries = 128;
  3059. EntrySize = 4;
  3060. #endif
  3061. ReadCount = NumberOfCommitEntries * EntrySize;
  3062. dprintf("Scanning %I64u %I64u commit points\n", NumberOfCommitEntries, ReadCount);
  3063. LocalData = LocalAlloc(LPTR, (ULONG) (NumberOfCommitEntries * EntrySize));
  3064. if (!LocalData) {
  3065. dprintf("unable to get allocate %ld bytes of memory\n",
  3066. (ULONG)(NumberOfCommitEntries * EntrySize));
  3067. return;
  3068. }
  3069. if ((!ReadMemory(MmTrackCommit,
  3070. LocalData,
  3071. (ULONG) ReadCount,
  3072. &result)) || (result < (ULONG) ReadCount)) {
  3073. dprintf("unable to get track commit table - "
  3074. "address %p - count %I64u\n",
  3075. LocalData, ReadCount);
  3076. }
  3077. else {
  3078. dprintf("\n%-50s %s\n", "Instance", "HexCount");
  3079. for (i = 0; i < NumberOfCommitEntries; i += 1) {
  3080. if (LocalData[i] != 0) {
  3081. for (j = 0; j < sizeof(CommitInfo) / sizeof (COMMIT_INFO); j += 1) {
  3082. if (CommitInfo[j].Index == i) {
  3083. dprintf ("%-50s %8x\n", CommitInfo[j].Name, LocalData[i]);
  3084. break;
  3085. }
  3086. }
  3087. }
  3088. }
  3089. }
  3090. if (LocalData) {
  3091. LocalFree((void *)LocalData);
  3092. }
  3093. return;
  3094. }
  3095. #endif
  3096. VOID
  3097. DumpFaultInjectionTraceLog (
  3098. PCSTR Args
  3099. );
  3100. VOID
  3101. DumpTrackIrqlLog (
  3102. PCSTR args
  3103. );
  3104. DECLARE_API( verifier )
  3105. /*++
  3106. Routine Description:
  3107. Displays the current Driver Verifier data.
  3108. Arguments:
  3109. arg - Supplies 7 for full listing
  3110. Return Value:
  3111. None.
  3112. --*/
  3113. {
  3114. ULONG result;
  3115. ULONG Flags;
  3116. ULONG VerifierFlags;
  3117. ULONG64 VerifierDataPointer;
  3118. ULONG64 SuspectPointer;
  3119. ULONG64 NextEntry;
  3120. ULONG64 VerifierDriverEntry;
  3121. PUCHAR tempbuffer;
  3122. UNICODE_STRING unicodeString;
  3123. LOGICAL Interrupted;
  3124. CHAR Buf[256];
  3125. PCHAR ImageFileName;
  3126. ANSI_STRING AnsiString;
  3127. UNICODE_STRING InputDriverName;
  3128. NTSTATUS st;
  3129. ULONG Level;
  3130. PCHAR state;
  3131. ULONG64 tmp;
  3132. UNREFERENCED_PARAMETER (Client);
  3133. //
  3134. // Display option usage.
  3135. //
  3136. if (strstr (args, "?") != NULL) {
  3137. dprintf ("!verifier \n");
  3138. dprintf (" \n");
  3139. dprintf (" Dump verifier summary information. \n");
  3140. dprintf (" \n");
  3141. dprintf ("!verifier [FLAGS [IMAGE]] \n");
  3142. dprintf (" \n");
  3143. dprintf (" 0x01 : Dump verified drivers pool statistics \n");
  3144. dprintf (" \n");
  3145. dprintf (" 0x03 : Dump individual pool allocation info \n");
  3146. dprintf (" \n");
  3147. dprintf (" 0x04 [N] : Dump N traces from fault injection trace log. \n");
  3148. dprintf (" \n");
  3149. dprintf (" 0x08 [N] : Dump N traces from track IRQL trace log\n");
  3150. dprintf (" \n");
  3151. dprintf ("To display everything use: \n");
  3152. dprintf (" \n");
  3153. dprintf (" !verifier 0xf \n");
  3154. dprintf (" \n");
  3155. return S_OK;
  3156. }
  3157. //
  3158. // Read the Flags parameter.
  3159. //
  3160. Flags = 0;
  3161. Flags = (ULONG) GetExpression (args);
  3162. //
  3163. // Display fault injection stacks.
  3164. //
  3165. if ((Flags == 0x04)) {
  3166. DumpFaultInjectionTraceLog (args);
  3167. return S_OK;
  3168. }
  3169. //
  3170. // Display track irql stacks.
  3171. //
  3172. if ((Flags == 0x08)) {
  3173. DumpTrackIrqlLog (args);
  3174. return S_OK;
  3175. }
  3176. //
  3177. // Continue with normal processing: !verifier [FLAGS [NAME]]
  3178. //
  3179. Flags = 0;
  3180. RtlZeroMemory(Buf, 256);
  3181. if (GetExpressionEx(args, &tmp, &args)) {
  3182. Flags = (ULONG) tmp;
  3183. while (args && (*args == ' ')) {
  3184. ++args;
  3185. }
  3186. if (StringCchCopy(Buf, sizeof(Buf), args) != S_OK)
  3187. {
  3188. Buf[0] = 0;
  3189. }
  3190. }
  3191. if (Buf[0] != '\0') {
  3192. ImageFileName = Buf;
  3193. RtlInitAnsiString(&AnsiString, ImageFileName);
  3194. st = RtlAnsiStringToUnicodeString(&InputDriverName, &AnsiString, TRUE);
  3195. if (!NT_SUCCESS(st)) {
  3196. dprintf("%08lx: Unable to initialize unicode string\n", st);
  3197. return E_INVALIDARG;
  3198. }
  3199. } else {
  3200. ImageFileName = NULL;
  3201. }
  3202. VerifierDataPointer = GetExpression ("nt!MmVerifierData");
  3203. if (GetFieldValue(VerifierDataPointer,
  3204. "nt!_MM_DRIVER_VERIFIER_DATA",
  3205. "Level",
  3206. Level)) {
  3207. dprintf("%08p: Unable to get verifier list.\n",VerifierDataPointer);
  3208. return E_INVALIDARG;
  3209. }
  3210. dprintf("\nVerify Level %x ... enabled options are:", Level);
  3211. if (Level & DRIVER_VERIFIER_SPECIAL_POOLING) {
  3212. dprintf("\n\tspecial pool");
  3213. }
  3214. if (Level & DRIVER_VERIFIER_FORCE_IRQL_CHECKING) {
  3215. dprintf("\n\tspecial irql");
  3216. }
  3217. if (Level & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES) {
  3218. dprintf("\n\tinject random low-resource API failures");
  3219. }
  3220. if (Level & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS) {
  3221. dprintf("\n\tall pool allocations checked on unload");
  3222. }
  3223. if (Level & DRIVER_VERIFIER_IO_CHECKING) {
  3224. dprintf("\n\tIo subsystem checking enabled");
  3225. }
  3226. if (Level & DRIVER_VERIFIER_DEADLOCK_DETECTION) {
  3227. dprintf("\n\tDeadlock detection enabled");
  3228. }
  3229. if (Level & DRIVER_VERIFIER_ENHANCED_IO_CHECKING) {
  3230. dprintf("\n\tEnhanced Io checking enabled");
  3231. }
  3232. if (Level & DRIVER_VERIFIER_DMA_VERIFIER) {
  3233. dprintf("\n\tDMA checking enabled");
  3234. }
  3235. if (InitTypeRead(VerifierDataPointer, nt!_MM_DRIVER_VERIFIER_DATA)) {
  3236. dprintf("Unable to read type nt!_MM_DRIVER_VERIFIER_DATA @ %p\n", VerifierDataPointer);
  3237. }
  3238. dprintf("\n\nSummary of All Verifier Statistics\n\n");
  3239. dprintf("RaiseIrqls 0x%x\n", (ULONG) ReadField(RaiseIrqls));
  3240. dprintf("AcquireSpinLocks 0x%x\n", (ULONG) ReadField(AcquireSpinLocks));
  3241. dprintf("Synch Executions 0x%x\n", (ULONG) ReadField(SynchronizeExecutions));
  3242. dprintf("Trims 0x%x\n", (ULONG) ReadField(Trims));
  3243. dprintf("\n");
  3244. dprintf("Pool Allocations Attempted 0x%x\n", (ULONG) ReadField(AllocationsAttempted));
  3245. dprintf("Pool Allocations Succeeded 0x%x\n", (ULONG) ReadField(AllocationsSucceeded));
  3246. dprintf("Pool Allocations Succeeded SpecialPool 0x%x\n", (ULONG) ReadField(AllocationsSucceededSpecialPool));
  3247. dprintf("Pool Allocations With NO TAG 0x%x\n", (ULONG) ReadField(AllocationsWithNoTag));
  3248. dprintf("Pool Allocations Failed 0x%x\n", (ULONG) ReadField(AllocationsFailed));
  3249. dprintf("Resource Allocations Failed Deliberately 0x%x\n", (ULONG) ReadField(AllocationsFailedDeliberately) + (ULONG) ReadField(BurstAllocationsFailedDeliberately));
  3250. dprintf("\n");
  3251. dprintf("Current paged pool allocations 0x%x for %08P bytes\n",
  3252. (ULONG) ReadField(CurrentPagedPoolAllocations),
  3253. ReadField(PagedBytes));
  3254. dprintf("Peak paged pool allocations 0x%x for %08P bytes\n",
  3255. (ULONG)ReadField(PeakPagedPoolAllocations),
  3256. ReadField(PeakPagedBytes));
  3257. dprintf("Current nonpaged pool allocations 0x%x for %08P bytes\n",
  3258. (ULONG) ReadField(CurrentNonPagedPoolAllocations),
  3259. ReadField(NonPagedBytes));
  3260. dprintf("Peak nonpaged pool allocations 0x%x for %08P bytes\n",
  3261. (ULONG)ReadField(PeakNonPagedPoolAllocations),
  3262. ReadField(PeakNonPagedBytes));
  3263. dprintf("\n");
  3264. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  3265. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  3266. if (Flags & 0x1) {
  3267. ULONG Off;
  3268. SuspectPointer = GetExpression ("nt!MiSuspectDriverList");
  3269. GetFieldOffset("nt!_MI_VERIFIER_DRIVER_ENTRY", "Links", &Off);
  3270. if (!ReadPointer(SuspectPointer,&NextEntry)) {
  3271. dprintf("%08p: Unable to get verifier list\n",SuspectPointer);
  3272. return E_INVALIDARG;
  3273. }
  3274. dprintf("Driver Verification List\n\n");
  3275. dprintf("Entry State NonPagedPool PagedPool Module\n\n");
  3276. while (NextEntry != SuspectPointer) {
  3277. VerifierDriverEntry = NextEntry - Off;
  3278. if (GetFieldValue( VerifierDriverEntry,
  3279. "nt!_MI_VERIFIER_DRIVER_ENTRY",
  3280. "Flags",
  3281. VerifierFlags)) {
  3282. dprintf("%08p: Unable to get verifier data\n", VerifierDriverEntry);
  3283. return E_INVALIDARG;
  3284. }
  3285. InitTypeRead(VerifierDriverEntry, nt!_MI_VERIFIER_DRIVER_ENTRY);
  3286. if ((VerifierFlags & VI_VERIFYING_DIRECTLY) == 0) {
  3287. NextEntry = ReadField(Links.Flink);
  3288. continue;
  3289. }
  3290. unicodeString.Length = (USHORT) ReadField(BaseName.Length);
  3291. if (unicodeString.Length > 1024) // sanity check
  3292. {
  3293. unicodeString.Length = 1024;
  3294. }
  3295. tempbuffer = LocalAlloc(LPTR, unicodeString.Length);
  3296. unicodeString.Buffer = (PWSTR)tempbuffer;
  3297. unicodeString.MaximumLength = unicodeString.Length;
  3298. if (!ReadMemory (ReadField(BaseName.Buffer),
  3299. tempbuffer,
  3300. unicodeString.Length,
  3301. &result)) {
  3302. dprintf("%08p: Unable to get verifier driver name\n", ReadField(BaseName.Buffer));
  3303. }
  3304. if (ImageFileName != NULL) {
  3305. if (RtlEqualUnicodeString(&InputDriverName, &unicodeString, TRUE) == 0) {
  3306. NextEntry = ReadField(Links.Flink);
  3307. continue;
  3308. }
  3309. }
  3310. if (ReadField(Loads) == 0 && ReadField(Unloads) == 0) {
  3311. state = "Hasn't loaded";
  3312. }
  3313. else if (ReadField(Loads) != ReadField(Unloads)) {
  3314. if (ReadField(Unloads) != 0) {
  3315. state = "Loaded&Unloaded";
  3316. }
  3317. else {
  3318. state = "Loaded";
  3319. }
  3320. }
  3321. else {
  3322. state = "Unloaded";
  3323. }
  3324. dprintf("%p %-16s %08p %08p %wZ\n",
  3325. VerifierDriverEntry,
  3326. state,
  3327. ReadField(NonPagedBytes),
  3328. ReadField(PagedBytes),
  3329. &unicodeString);
  3330. Interrupted = FALSE;
  3331. NextEntry = ReadField(Links.Flink);
  3332. if ((Flags & 0x2) &&
  3333. (Level & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)) {
  3334. Interrupted = VerifierDumpPool (VerifierDriverEntry);
  3335. }
  3336. LocalFree(tempbuffer);
  3337. if ((Interrupted == TRUE) ||
  3338. (ImageFileName != NULL) ||
  3339. (CheckControlC())) {
  3340. break;
  3341. }
  3342. }
  3343. }
  3344. if ((Flags & 0x04)) {
  3345. dprintf ("----------------------------------------------- \n");
  3346. dprintf ("Fault injection trace log \n");
  3347. dprintf ("----------------------------------------------- \n");
  3348. DumpFaultInjectionTraceLog (NULL);
  3349. }
  3350. if ((Flags & 0x08)) {
  3351. dprintf ("----------------------------------------------- \n");
  3352. dprintf ("Track irql trace log \n");
  3353. dprintf ("----------------------------------------------- \n");
  3354. DumpTrackIrqlLog (NULL);
  3355. }
  3356. return S_OK;
  3357. }
  3358. DECLARE_API( fpsearch )
  3359. /*++
  3360. Routine Description:
  3361. Free pool searcher.
  3362. Arguments:
  3363. arg - Supplies virtual address to match.
  3364. Return Value:
  3365. None.
  3366. --*/
  3367. {
  3368. ULONG i;
  3369. ULONG BufferSize;
  3370. ULONG RawCount;
  3371. PULONG RawPointer;
  3372. ULONG Flags;
  3373. ULONG ActualRead;
  3374. ULONG64 PageFrameNumber;
  3375. ULONG64 PAddress;
  3376. ULONG64 Address;
  3377. ULONG result;
  3378. ULONG64 PfnDb;
  3379. ULONG64 Pfn;
  3380. ULONG64 PfnStart;
  3381. ULONG PfnSize;
  3382. ULONG64 ChainedBp;
  3383. ULONG64 ValidBp;
  3384. ULONG64 LastBp;
  3385. ULONG64 ReturnAddress;
  3386. PCHAR Buffer;
  3387. ULONG64 MmFreePageListHeadAddress;
  3388. CHAR SymbolBuffer[MAX_PATH];
  3389. ULONG64 displacement;
  3390. ULONG64 Total;
  3391. ULONG StkOffset;
  3392. ULONG PtrSize;
  3393. ULONG PoolTag;
  3394. ULONG StackBytes;
  3395. ULONG64 StackPointer;
  3396. ULONG64 ChainedBpVal;
  3397. ULONG64 LastBpVal;
  3398. ULONG64 Blink;
  3399. PtrSize = IsPtr64() ? 8 : 4;
  3400. PfnSize = GetTypeSize("nt!_MMPFN");
  3401. BufferSize = GetTypeSize("nt!_MI_FREED_SPECIAL_POOL");
  3402. if (BufferSize == 0) {
  3403. dprintf("Type MI_FREED_SPECIAL_POOL not found.\n");
  3404. return E_INVALIDARG;
  3405. }
  3406. PfnDb = GetNtDebuggerData(MmPfnDatabase );
  3407. if (!PfnDb) {
  3408. dprintf("unable to get PFN0 database address\n");
  3409. return E_INVALIDARG;
  3410. }
  3411. result = !ReadPointer(PfnDb,&PfnStart);
  3412. if (result != 0) {
  3413. dprintf("unable to get PFN database address %p %x\n", PfnDb, result);
  3414. return E_INVALIDARG;
  3415. }
  3416. Address = 0;
  3417. Flags = 0;
  3418. if (!sscanf(args,"%I64lx %lx",&Address, &Flags)) {
  3419. Address = 0;
  3420. }
  3421. // Do not use GetExpression here - the actual address to be searched is phy address
  3422. // and it can be >32bit for 32bit targets
  3423. // Address = GetExpression (args);
  3424. if (Address == 0) {
  3425. dprintf("Usage: fpsearch address\n");
  3426. return E_INVALIDARG;
  3427. }
  3428. MmFreePageListHeadAddress = GetExpression ("nt!MmFreePageListHead");
  3429. if (GetFieldValue(MmFreePageListHeadAddress,
  3430. "nt!_MMPFNLIST",
  3431. "Total",
  3432. Total)) {
  3433. dprintf("%08p: Unable to get MmFreePageLocationList\n",MmFreePageListHeadAddress);
  3434. return E_INVALIDARG;
  3435. }
  3436. if (Total == 0) {
  3437. dprintf("No pages on free list to search\n");
  3438. return E_INVALIDARG;
  3439. }
  3440. if (Address != (ULONG64)-1) {
  3441. dprintf("Searching the free page list (%I64x entries) for VA %p\n\n",
  3442. Total, Address);
  3443. Address &= ~(ULONG64)(PageSize - 1);
  3444. }
  3445. else {
  3446. dprintf("Searching the free page list (%x entries) for all freed special pool\n\n",
  3447. Total);
  3448. }
  3449. GetFieldValue (MmFreePageListHeadAddress,
  3450. "nt!_MMPFNLIST",
  3451. "Blink",
  3452. PageFrameNumber);
  3453. GetFieldOffset("nt!_MI_FREED_SPECIAL_POOL", "StackData", &StkOffset);
  3454. Buffer = LocalAlloc(LPTR, BufferSize);
  3455. if (Buffer == NULL) {
  3456. dprintf("Could not allocate a buffer for the search\n");
  3457. return E_INVALIDARG;
  3458. }
  3459. while (PageFrameNumber != (ULONG64)-1) {
  3460. PAddress = (ULONG64)PageFrameNumber * PageSize;
  3461. ReadPhysical (PAddress, Buffer, BufferSize, &ActualRead);
  3462. if (ActualRead != BufferSize) {
  3463. dprintf("Physical memory read %I64X %x %x failed\n", PAddress, ActualRead, BufferSize);
  3464. // break;
  3465. }
  3466. if (Flags & 0x1) {
  3467. //
  3468. // Print a preview of the raw buffer.
  3469. //
  3470. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3471. RawPointer = (PULONG)Buffer;
  3472. RawCount = BufferSize / sizeof (ULONG);
  3473. if (RawCount > 32) {
  3474. RawCount = 32;
  3475. }
  3476. RawCount &= ~0x3;
  3477. for (i = 0; i < RawCount; i += 4) {
  3478. dprintf ("%I64X %08x %08x %08x %08x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
  3479. PageFrameNumber * PageSize,
  3480. *RawPointer,
  3481. *(RawPointer + 1),
  3482. *(RawPointer + 2),
  3483. *(RawPointer + 3),
  3484. PP(*RawPointer),
  3485. PP(*RawPointer >> 8),
  3486. PP(*RawPointer >> 16),
  3487. PP(*RawPointer >> 24),
  3488. PP(*(RawPointer + 1)),
  3489. PP(*(RawPointer + 1) >> 8),
  3490. PP(*(RawPointer + 1) >> 16),
  3491. PP(*(RawPointer + 1) >> 24),
  3492. PP(*(RawPointer + 2)),
  3493. PP(*(RawPointer + 2) >> 8),
  3494. PP(*(RawPointer + 2) >> 16),
  3495. PP(*(RawPointer + 2) >> 24),
  3496. PP(*(RawPointer + 3)),
  3497. PP(*(RawPointer + 3) >> 8),
  3498. PP(*(RawPointer + 3) >> 16),
  3499. PP(*(RawPointer + 3) >> 24));
  3500. RawPointer += 4;
  3501. }
  3502. dprintf ("\n");
  3503. }
  3504. Pfn = (PfnStart + PageFrameNumber * PfnSize);
  3505. if (GetFieldValue(Pfn,"nt!_MMPFN","u2.Blink", Blink)) {
  3506. dprintf("%08p: unable to get PFN element %x\n", Pfn, PfnSize);
  3507. break;
  3508. }
  3509. if ((ULONG)Blink == (ULONG)-1) {
  3510. Blink = (ULONG64)-1;
  3511. }
  3512. #define MI_FREED_SPECIAL_POOL_SIGNATURE 0x98764321
  3513. InitTypeReadPhysical (PAddress, nt!MI_FREED_SPECIAL_POOL);
  3514. if ((ULONG) ReadField(Signature) == MI_FREED_SPECIAL_POOL_SIGNATURE) {
  3515. if ((Address == (ULONG64)-1) ||
  3516. (((ULONG)(ReadField(VirtualAddress)) & ~(ULONG)(PageSize - 1)) == (ULONG)Address)) {
  3517. PoolTag = (ULONG) ReadField(OverlaidPoolHeader.PoolTag);
  3518. dprintf("VA PFN Tag Size Pagable Thread Tick\n");
  3519. dprintf("%p %6p %c%c%c%c %6x %s %08p %x\n",
  3520. ReadField(VirtualAddress),
  3521. PageFrameNumber,
  3522. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3523. PP(PoolTag),
  3524. PP(PoolTag >> 8),
  3525. PP(PoolTag >> 16),
  3526. PP(PoolTag >> 24),
  3527. #undef PP
  3528. (ULONG) ReadField(NumberOfBytesRequested),
  3529. ReadField(Pagable) ? "Yes" : "No ",
  3530. ReadField(Thread),
  3531. ReadField(TickCount));
  3532. dprintf("\tCALL STACK AT TIME OF DEALLOCATION\n");
  3533. //
  3534. // Calculate the relative stack and print it here symbolically.
  3535. //
  3536. StackBytes = (ULONG) ReadField(StackBytes);
  3537. StackPointer = ReadField(StackPointer);
  3538. ValidBp = (StackPointer & ~(ULONG64)(PageSize - 1));
  3539. ChainedBp = (PAddress + StkOffset);
  3540. LastBp = (ChainedBp + (ULONG) ReadField(StackBytes));
  3541. while (ChainedBp < LastBp) {
  3542. //
  3543. // Read directly from physical memory.
  3544. //
  3545. InitTypeReadPhysical(ChainedBp, nt!_LIST_ENTRY);
  3546. ChainedBpVal = ReadField(Flink);
  3547. InitTypeReadPhysical(LastBp, nt!_LIST_ENTRY);
  3548. LastBpVal = ReadField(Flink);
  3549. //
  3550. // Find a valid frame register chain.
  3551. //
  3552. if ((((ChainedBpVal) & ~(ULONG64)(PageSize - 1)) == ValidBp) &&
  3553. (ChainedBpVal > StackPointer) &&
  3554. ((ChainedBpVal - (StackPointer)) <= StackBytes)) {
  3555. ULONG64 ReturnAddressVal;
  3556. //
  3557. // Increment to the stacked return address.
  3558. //
  3559. ReturnAddress = ChainedBp + PtrSize;
  3560. InitTypeReadPhysical(ReturnAddress, nt!_LIST_ENTRY);
  3561. ReturnAddressVal = ReadField(Flink);
  3562. SymbolBuffer[0] = '!';
  3563. GetSymbol((ReturnAddressVal), (PUCHAR)SymbolBuffer, &displacement);
  3564. dprintf ("\t%s", SymbolBuffer);
  3565. if (displacement) {
  3566. dprintf( "+0x%x", displacement );
  3567. }
  3568. dprintf( "\n" );
  3569. #ifdef SLOW_BUT_THOROUGH
  3570. ChainedBp += PtrSize;
  3571. #else
  3572. if ((ReturnAddressVal & ~MAXLONG64_PTR) == 0) {
  3573. break;
  3574. }
  3575. //
  3576. // Subtract the stackpointer & add stackdata offset.
  3577. //
  3578. ChainedBp = (ChainedBpVal - StackPointer + StkOffset);
  3579. //
  3580. // Adjust for relative.
  3581. //
  3582. ChainedBp = (PAddress + ChainedBp);
  3583. #endif
  3584. }
  3585. else {
  3586. ChainedBp += PtrSize;
  3587. }
  3588. }
  3589. dprintf("\n");
  3590. if (Address != (ULONG64)-1) {
  3591. break;
  3592. }
  3593. }
  3594. }
  3595. if (CheckControlC()) {
  3596. break;
  3597. }
  3598. PageFrameNumber = Blink;
  3599. }
  3600. LocalFree(Buffer);
  3601. return S_OK;
  3602. }
  3603. USHORT
  3604. GetPfnRefCount(
  3605. IN ULONG64 PageFrameNumber
  3606. )
  3607. {
  3608. ULONG64 PfnDb;
  3609. ULONG64 Pfn;
  3610. ULONG64 PfnStart;
  3611. ULONG PfnSize;
  3612. ULONG ReferenceCount;
  3613. PfnSize = GetTypeSize("nt!_MMPFN");
  3614. PfnDb = GetNtDebuggerData(MmPfnDatabase );
  3615. if (!PfnDb) {
  3616. dprintf("unable to get PFN0 database address\n");
  3617. return 0;
  3618. }
  3619. if (!ReadPointer(PfnDb,&PfnStart)) {
  3620. dprintf("unable to get PFN database address %p\n", PfnDb);
  3621. return 0;
  3622. }
  3623. Pfn = (PfnStart + PageFrameNumber * PfnSize);
  3624. if (GetFieldValue(Pfn,"nt!_MMPFN","u3.e2.ReferenceCount", ReferenceCount)) {
  3625. dprintf("%08p: unable to get PFN element %x\n", Pfn, PfnSize);
  3626. return 0;
  3627. }
  3628. return (USHORT) ReferenceCount;
  3629. }
  3630. /////////////////////////////////////////////////////////////////////
  3631. ////////////////////////////////////// Dump irql tracking log
  3632. /////////////////////////////////////////////////////////////////////
  3633. VOID
  3634. DumpTrackIrqlLog (
  3635. PCSTR args
  3636. )
  3637. {
  3638. ULONG64 TrackIrqlQueueAddress;
  3639. ULONG64 TrackIrqlIndexAddress;
  3640. ULONG64 TrackIrqlQueueLengthAddress;
  3641. ULONG64 TrackIrqlQueue;
  3642. ULONG TrackIrqlIndex;
  3643. ULONG TrackIrqlQueueLength;
  3644. ULONG I, Index;
  3645. ULONG64 Address;
  3646. ULONG TrackIrqlTypeSize;
  3647. UCHAR SymbolName[256];
  3648. ULONG64 SymbolAddress;
  3649. ULONG64 SymbolOffset;
  3650. ULONG Result;
  3651. ULONG ShowCount;
  3652. ULONG Flags;
  3653. //
  3654. // Read how many traces we want to see.
  3655. //
  3656. ShowCount = 0;
  3657. if (args) {
  3658. ULONG64 tmp;
  3659. if (GetExpressionEx(args, &tmp, &args)) {
  3660. Flags = (ULONG) tmp;
  3661. if (!sscanf (args, "%u", &ShowCount)) {
  3662. ShowCount = 0;
  3663. }
  3664. }
  3665. if (ShowCount == 0) {
  3666. ShowCount = 4;
  3667. }
  3668. }
  3669. else {
  3670. ShowCount = 4;
  3671. }
  3672. //
  3673. // Read track irql package data
  3674. //
  3675. TrackIrqlQueueAddress = GetExpression ("nt!ViTrackIrqlQueue");
  3676. TrackIrqlIndexAddress = GetExpression ("nt!ViTrackIrqlIndex");
  3677. TrackIrqlQueueLengthAddress = GetExpression ("nt!ViTrackIrqlQueueLength");
  3678. if (TrackIrqlQueueAddress == 0 || TrackIrqlIndexAddress == 0) {
  3679. dprintf ("Incorrect symbols. \n");
  3680. return;
  3681. }
  3682. if (!ReadPointer (TrackIrqlQueueAddress, &TrackIrqlQueue)) {
  3683. dprintf("Unable to reas TrackIrqlQueue at %p\n", TrackIrqlQueueAddress);
  3684. TrackIrqlQueue = 0;
  3685. }
  3686. if (TrackIrqlQueue == 0) {
  3687. dprintf ("Irql tracking is not enabled. You need to enable driver verifier \n");
  3688. dprintf ("for at least one driver to activate irql tracking. \n");
  3689. return;
  3690. }
  3691. ReadMemory (TrackIrqlIndexAddress, &TrackIrqlIndex, sizeof(ULONG), &Result);
  3692. if (Result != sizeof(ULONG)) {
  3693. dprintf ("Trackirql: read error \n");
  3694. return;
  3695. }
  3696. ReadMemory (TrackIrqlQueueLengthAddress, &TrackIrqlQueueLength, sizeof(ULONG), &Result);
  3697. if (Result != sizeof(ULONG)) {
  3698. dprintf ("Trackirql: read error \n");
  3699. return;
  3700. }
  3701. TrackIrqlTypeSize = GetTypeSize("nt!_VI_TRACK_IRQL");
  3702. //
  3703. // Dump information
  3704. //
  3705. dprintf ("\nSize of track irql queue is 0x%X \n", TrackIrqlQueueLength);
  3706. for (I = 0, Index = TrackIrqlIndex; I < TrackIrqlQueueLength; I += 1) {
  3707. if (I >= ShowCount) {
  3708. break;
  3709. }
  3710. Index -= 1;
  3711. Index &= (TrackIrqlQueueLength - 1);
  3712. Address = TrackIrqlQueue + Index * TrackIrqlTypeSize;
  3713. InitTypeRead (Address, nt!_VI_TRACK_IRQL);
  3714. dprintf ("\n");
  3715. dprintf ("Thread: %I64X\n", ReadField (Thread));
  3716. dprintf ("Old irql: %I64X\n", ReadField (OldIrql));
  3717. dprintf ("New irql: %I64X\n", ReadField (NewIrql));
  3718. dprintf ("Processor: %I64X\n", ReadField (Processor));
  3719. dprintf ("Time stamp: %I64X\n", ReadField (TickCount));
  3720. dprintf ("\n");
  3721. SymbolAddress = ReadField(StackTrace[0]);
  3722. if (SymbolAddress == 0) { continue; }
  3723. GetSymbol(SymbolAddress, SymbolName, &SymbolOffset);
  3724. dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset);
  3725. SymbolAddress = ReadField(StackTrace[1]);
  3726. if (SymbolAddress == 0) { continue; }
  3727. GetSymbol(SymbolAddress, SymbolName, &SymbolOffset);
  3728. dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset);
  3729. SymbolAddress = ReadField(StackTrace[2]);
  3730. if (SymbolAddress == 0) { continue; }
  3731. GetSymbol(SymbolAddress, SymbolName, &SymbolOffset);
  3732. dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset);
  3733. SymbolAddress = ReadField(StackTrace[3]);
  3734. if (SymbolAddress == 0) { continue; }
  3735. GetSymbol(SymbolAddress, SymbolName, &SymbolOffset);
  3736. dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset);
  3737. SymbolAddress = ReadField(StackTrace[4]);
  3738. if (SymbolAddress == 0) { continue; }
  3739. GetSymbol(SymbolAddress, SymbolName, &SymbolOffset);
  3740. dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset);
  3741. if (CheckControlC()) {
  3742. dprintf ("Interrupted \n");
  3743. break;
  3744. }
  3745. }
  3746. }
  3747. /////////////////////////////////////////////////////////////////////
  3748. ////////////////////////////////////// Dump fault injection trace log
  3749. /////////////////////////////////////////////////////////////////////
  3750. ULONG64
  3751. ReadPvoid (
  3752. ULONG64 Address
  3753. )
  3754. {
  3755. ULONG64 RemoteValue = 0;
  3756. ReadPointer( Address, &RemoteValue);
  3757. return RemoteValue;
  3758. }
  3759. ULONG
  3760. ReadUlong(
  3761. ULONG64 Address
  3762. )
  3763. {
  3764. ULONG RemoteValue = 0;
  3765. ReadMemory( Address, &RemoteValue, sizeof( ULONG ), NULL );
  3766. return RemoteValue;
  3767. }
  3768. VOID
  3769. DumpFaultInjectionTrace (
  3770. ULONG64 Address
  3771. )
  3772. {
  3773. ULONG64 ReturnAddress;
  3774. CHAR SymbolName[ 1024 ];
  3775. ULONG64 Displacement;
  3776. ULONG I;
  3777. ULONG PvoidSize;
  3778. PvoidSize = IsPtr64() ? 8 : 4;
  3779. for (I = 0; I < 8; I += 1) {
  3780. ReturnAddress = ReadPvoid (Address + I * PvoidSize);
  3781. if (ReturnAddress == 0) {
  3782. break;
  3783. }
  3784. GetSymbol (ReturnAddress, SymbolName, &Displacement);
  3785. dprintf (" %p %s+0x%p\n",
  3786. ReturnAddress,
  3787. SymbolName,
  3788. Displacement);
  3789. }
  3790. }
  3791. VOID
  3792. DumpFaultInjectionTraceLog (
  3793. PCSTR Args
  3794. )
  3795. {
  3796. ULONG TracesToDisplay = 0;
  3797. ULONG64 TraceAddress;
  3798. ULONG64 Trace;
  3799. ULONG64 IndexAddress;
  3800. ULONG Index;
  3801. ULONG64 LengthAddress;
  3802. ULONG Length;
  3803. ULONG I;
  3804. ULONG PvoidSize;
  3805. ULONG64 TraceBlockAddress;
  3806. ULONG64 FirstReturnAddress;
  3807. ULONG TracesFound = 0;
  3808. BOOLEAN Interrupted = FALSE;
  3809. ULONG Flags;
  3810. if (Args) {
  3811. ULONG64 tmp;
  3812. if (GetExpressionEx(Args, &tmp, &Args)) {
  3813. Flags = (ULONG) tmp;
  3814. if (!sscanf (Args, "%u", &TracesToDisplay)) {
  3815. TracesToDisplay = 0;
  3816. }
  3817. }
  3818. if (TracesToDisplay == 0) {
  3819. TracesToDisplay = 4;
  3820. }
  3821. }
  3822. else {
  3823. TracesToDisplay = 4;
  3824. }
  3825. PvoidSize = IsPtr64() ? 8 : 4;
  3826. TraceAddress = (ULONG64) GetExpression ("nt!ViFaultTraces");
  3827. IndexAddress = (ULONG64) GetExpression ("nt!ViFaultTracesIndex");
  3828. LengthAddress = (ULONG64) GetExpression ("nt!ViFaultTracesLength");
  3829. Trace = ReadPvoid (TraceAddress);
  3830. if (Trace == 0) {
  3831. dprintf ("Driver fault injection is not enabled for this system. \n");
  3832. return;
  3833. }
  3834. Index = ReadUlong (IndexAddress);
  3835. Length = ReadUlong (LengthAddress);
  3836. for (I = 0; I < Length; I += 1) {
  3837. Index -= 1;
  3838. Index &= (Length - 1);
  3839. TraceBlockAddress = Trace + Index * PvoidSize * 8;
  3840. FirstReturnAddress = ReadPvoid (TraceBlockAddress);
  3841. if (FirstReturnAddress != 0) {
  3842. TracesFound += 1;
  3843. dprintf ("\n");
  3844. DumpFaultInjectionTrace (TraceBlockAddress);
  3845. if (TracesFound >= TracesToDisplay) {
  3846. break;
  3847. }
  3848. }
  3849. if (CheckControlC()) {
  3850. Interrupted = TRUE;
  3851. dprintf ("Interrupted \n");
  3852. break;
  3853. }
  3854. }
  3855. if (Interrupted == FALSE && TracesFound == 0) {
  3856. dprintf ("No fault injection traces found. \n");
  3857. }
  3858. }
  3859. PUCHAR MemoryDescriptorType[] = {
  3860. "ExceptionBlock",
  3861. "SystemBlock",
  3862. "Free",
  3863. "Bad",
  3864. "LoadedProgram",
  3865. "FirmwareTemporary",
  3866. "FirmwarePermanent",
  3867. "OsloaderHeap",
  3868. "OsloaderStack",
  3869. "SystemCode",
  3870. "HalCode",
  3871. "BootDriver",
  3872. "ConsoleInDriver",
  3873. "ConsoleOutDriver",
  3874. "StartupDpcStack",
  3875. "StartupKernelStack",
  3876. "StartupPanicStack",
  3877. "StartupPcrPage",
  3878. "StartupPdrPage",
  3879. "RegistryData",
  3880. "MemoryData",
  3881. "NlsData",
  3882. "SpecialMemory",
  3883. "BBTMemory",
  3884. "LoaderReserve",
  3885. "XIPRom",
  3886. "HALCachedMemory"
  3887. };
  3888. #define MAXIMUM_MEMORY_TYPE (sizeof(MemoryDescriptorType)/sizeof(UCHAR))
  3889. DECLARE_API( loadermemorylist )
  3890. /*++
  3891. Routine Description:
  3892. Displays the memory allocation list. This is the list
  3893. handed to the OS by the OSLOADER that describes physical
  3894. memory.
  3895. Displays the corresponding PDE and PTE.
  3896. Arguments:
  3897. list - points to the listheader
  3898. Return Value:
  3899. None.
  3900. --*/
  3901. {
  3902. ULONG64 ListHeaderAddress;
  3903. ULONG64 EntryAddress;
  3904. ULONG64 LengthInPages;
  3905. ULONG64 TypeOfMemory;
  3906. ULONG Count[MAXIMUM_MEMORY_TYPE];
  3907. ULONG i;
  3908. UNREFERENCED_PARAMETER (Client);
  3909. ListHeaderAddress = 0;
  3910. ListHeaderAddress = GetExpression(args);
  3911. if (ListHeaderAddress == 0) {
  3912. dprintf("Usage: !loadermemorylist <address_of_listhead>\n");
  3913. return E_INVALIDARG;
  3914. }
  3915. if (!ReadPointer(ListHeaderAddress, &EntryAddress)) {
  3916. dprintf("Unable to read list header at %p\n", ListHeaderAddress);
  3917. return E_INVALIDARG;
  3918. }
  3919. if (EntryAddress == ListHeaderAddress) {
  3920. dprintf("List at %p is empty\n", ListHeaderAddress);
  3921. return S_OK;
  3922. }
  3923. dprintf("Base Length Type\n");
  3924. RtlZeroMemory(Count, sizeof(Count));
  3925. do {
  3926. if (CheckControlC()) {
  3927. dprintf ("Interrupted \n");
  3928. break;
  3929. }
  3930. InitTypeRead(EntryAddress, nt!MEMORY_ALLOCATION_DESCRIPTOR);
  3931. TypeOfMemory = ReadField(MemoryType);
  3932. if (TypeOfMemory < MAXIMUM_MEMORY_TYPE) {
  3933. LengthInPages = ReadField(PageCount);
  3934. dprintf("%08x %08x %s\n",
  3935. (ULONG)ReadField(BasePage),
  3936. (ULONG)LengthInPages,
  3937. MemoryDescriptorType[TypeOfMemory]);
  3938. Count[TypeOfMemory] += (ULONG)LengthInPages;
  3939. } else {
  3940. dprintf("Unrecognized Descriptor at %p\n", EntryAddress);
  3941. }
  3942. EntryAddress = ReadField(ListEntry.Flink);
  3943. } while (EntryAddress != ListHeaderAddress);
  3944. dprintf("\nSummary\nMemory Type Pages\n");
  3945. LengthInPages = 0;
  3946. for (i = 0; i < MAXIMUM_MEMORY_TYPE; i++) {
  3947. if (Count[i]) {
  3948. dprintf("%-20s%08x (%8d)\n",
  3949. MemoryDescriptorType[i],
  3950. Count[i],
  3951. Count[i]);
  3952. LengthInPages += Count[i];
  3953. }
  3954. }
  3955. dprintf(" ======== ========\n");
  3956. dprintf("Total %08x (%8d) = ~%dMB\n",
  3957. (ULONG)LengthInPages,
  3958. (ULONG)LengthInPages,
  3959. (ULONG)LengthInPages / (1024 * 1024 / 4096));
  3960. return S_OK;
  3961. }
  3962. ///////////////////////////////////////////////////////////////////////////
  3963. BOOL
  3964. VerifyExpectedPfnNumberSize (
  3965. VOID
  3966. )
  3967. {
  3968. ULONG PfnNumberTypeSize;
  3969. ULONG ExpectedPfnNumberTypeSize;
  3970. BOOL Success;
  3971. Success = TRUE;
  3972. PfnNumberTypeSize = GetTypeSize ("nt!PFN_NUMBER");
  3973. if (PfnNumberTypeSize == 0) {
  3974. dprintf ("ERROR: Cannot get the size of nt!PFN_NUMBER.\n"
  3975. "Please check your symbols.\n" );
  3976. Success = FALSE;
  3977. goto Done;
  3978. }
  3979. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  3980. ExpectedPfnNumberTypeSize = sizeof(ULONG);
  3981. }
  3982. else {
  3983. //
  3984. // Assume 64 bit target machine.
  3985. //
  3986. ExpectedPfnNumberTypeSize = sizeof(ULONG64);
  3987. }
  3988. if (PfnNumberTypeSize != ExpectedPfnNumberTypeSize) {
  3989. dprintf ("ERROR: sizeof (nt!PFN_NUMBER) = %u, expected %u.\n",
  3990. PfnNumberTypeSize,
  3991. ExpectedPfnNumberTypeSize);
  3992. Success = FALSE;
  3993. }
  3994. Done:
  3995. return Success;
  3996. }
  3997. ///////////////////////////////////////////////////////////////////////
  3998. BOOL
  3999. DumpMnwPfnInfo (
  4000. IN ULONG64 PfnNumber,
  4001. IN ULONG64 PfnAddr,
  4002. IN ULONG CaFieldOffset,
  4003. IN ULONG FilePointerFieldOffset,
  4004. IN ULONG FileNameFieldOffset,
  4005. IN ULONG UnicodeStrLengthFieldOffset,
  4006. IN ULONG UnicodeStrBufferFieldOffset,
  4007. IN ULONG64 OriginalPteAddr,
  4008. IN ULONG Flags,
  4009. OUT ULONG64 *FileAddr,
  4010. OUT ULONG64 *CaAddr
  4011. )
  4012. {
  4013. ULONG64 SubsectionAddr;
  4014. ULONG64 BufferAddr;
  4015. ULONG ErrorCode;
  4016. BOOL Continue;
  4017. BOOL Success;
  4018. USHORT Length;
  4019. UNICODE_STRING UnicodeString;
  4020. Continue = TRUE;
  4021. *FileAddr = 0;
  4022. *CaAddr = 0;
  4023. ZeroMemory (&UnicodeString,
  4024. sizeof (UnicodeString));
  4025. //
  4026. // Get the address of the subsection.
  4027. //
  4028. SubsectionAddr = DbgGetSubsectionAddress (OriginalPteAddr);
  4029. //
  4030. // Get the address of the control area.
  4031. //
  4032. ErrorCode = ReadPointer (SubsectionAddr + CaFieldOffset,
  4033. CaAddr);
  4034. if (ErrorCode != TRUE) {
  4035. dprintf ("ERROR: Cannot read ControlArea address from 0x%p\n",
  4036. SubsectionAddr + CaFieldOffset);
  4037. Continue = FALSE;
  4038. goto Done;
  4039. }
  4040. //
  4041. // Get the address of the file object.
  4042. //
  4043. ErrorCode = ReadPointer (*CaAddr + FilePointerFieldOffset,
  4044. FileAddr);
  4045. if (ErrorCode != TRUE) {
  4046. dprintf ("ERROR: Cannot read file object address from 0x%p\n",
  4047. *CaAddr + FilePointerFieldOffset);
  4048. Continue = FALSE;
  4049. goto Done;
  4050. }
  4051. //
  4052. // Get the file name, if it's not paged out.
  4053. //
  4054. Success = ReadMemory (*FileAddr + FileNameFieldOffset + UnicodeStrLengthFieldOffset,
  4055. &Length,
  4056. sizeof (Length),
  4057. NULL);
  4058. if (Success != FALSE && Length > 0 && Length < 1024) {
  4059. UnicodeString.Buffer = malloc (Length);
  4060. if (UnicodeString.Buffer != NULL) {
  4061. ErrorCode = ReadPointer (*FileAddr + FileNameFieldOffset + UnicodeStrBufferFieldOffset,
  4062. &BufferAddr);
  4063. if (ErrorCode == TRUE) {
  4064. Success = ReadMemory (BufferAddr,
  4065. UnicodeString.Buffer,
  4066. Length,
  4067. NULL);
  4068. if (Success != FALSE) {
  4069. UnicodeString.Length = Length;
  4070. UnicodeString.MaximumLength = UnicodeString.Length;
  4071. }
  4072. }
  4073. }
  4074. }
  4075. //
  4076. // Print out everything we know about this physical page of memory.
  4077. //
  4078. if (Flags & 2) {
  4079. dprintf ("%16p %16p %16p %16p %16p %wZ\n",
  4080. PfnNumber,
  4081. PfnAddr,
  4082. SubsectionAddr,
  4083. *CaAddr,
  4084. *FileAddr,
  4085. &UnicodeString);
  4086. }
  4087. Done:
  4088. if (UnicodeString.Buffer != NULL) {
  4089. free (UnicodeString.Buffer);
  4090. UnicodeString.Buffer = NULL;
  4091. }
  4092. return Continue;
  4093. }
  4094. ///////////////////////////////////////////////////////////////////////
  4095. BOOL
  4096. DumpMnwPfnInfoFromPfnNoAddr (
  4097. IN ULONG64 FirstPfnAddr,
  4098. IN ULONG MmPfnTypeSize,
  4099. IN ULONG OriginalPteFieldOffset,
  4100. IN ULONG U1FlinkFieldOffset,
  4101. IN ULONG CaFieldOffset,
  4102. IN ULONG FilePointerFieldOffset,
  4103. IN ULONG FileNameFieldOffset,
  4104. IN ULONG UnicodeStrLengthFieldOffset,
  4105. IN ULONG UnicodeStrBufferFieldOffset,
  4106. IN ULONG Flags,
  4107. IN OUT PULONG64 CurrentPfnNumberAddr,
  4108. OUT ULONG64 *FileAddr,
  4109. OUT ULONG64 *CaAddr
  4110. )
  4111. {
  4112. ULONG64 PfnNumber64;
  4113. ULONG64 CrtPfnAddr;
  4114. ULONG PfnNumber32;
  4115. BOOL ContinueWithNextPfn;
  4116. #define MM_EMPTY_LIST_32BIT ((ULONG)-1)
  4117. #define MM_EMPTY_LIST_64BIT ((ULONG64)-1)
  4118. ContinueWithNextPfn = TRUE;
  4119. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  4120. //
  4121. // Read the current PFN number.
  4122. //
  4123. ContinueWithNextPfn = ReadMemory (*CurrentPfnNumberAddr,
  4124. &PfnNumber32,
  4125. sizeof (PfnNumber32),
  4126. NULL);
  4127. if (ContinueWithNextPfn == FALSE) {
  4128. dprintf ("ERROR: Cannot read PFN_NUMBER at 0x%p\n",
  4129. *CurrentPfnNumberAddr);
  4130. goto Done;
  4131. }
  4132. //
  4133. // Check if this is the end of list marker.
  4134. //
  4135. if (PfnNumber32 == MM_EMPTY_LIST_32BIT) {
  4136. dprintf ("ERROR: End of the PFN numbers list found before parsing all list elements!!!\n");
  4137. ContinueWithNextPfn = FALSE;
  4138. goto Done;
  4139. }
  4140. //
  4141. // Cast our PFN number to 64 bit and continue with that.
  4142. //
  4143. PfnNumber64 = (ULONG64)PfnNumber32;
  4144. }
  4145. else {
  4146. //
  4147. // Read the current PFN number.
  4148. //
  4149. ContinueWithNextPfn = ReadMemory (*CurrentPfnNumberAddr,
  4150. &PfnNumber64,
  4151. sizeof (PfnNumber64),
  4152. NULL);
  4153. if (ContinueWithNextPfn == FALSE) {
  4154. dprintf ("ERROR: Cannot read PFN_NUMBER at 0x%p\n",
  4155. *CurrentPfnNumberAddr);
  4156. goto Done;
  4157. }
  4158. //
  4159. // Check if this is the end of list marker.
  4160. //
  4161. if (PfnNumber64 == MM_EMPTY_LIST_64BIT) {
  4162. dprintf ("ERROR: End of the PFN numbers list found before parsing all list elements!!!\n");
  4163. ContinueWithNextPfn = FALSE;
  4164. goto Done;
  4165. }
  4166. }
  4167. CrtPfnAddr = FirstPfnAddr + PfnNumber64 * MmPfnTypeSize;
  4168. ContinueWithNextPfn = DumpMnwPfnInfo (PfnNumber64,
  4169. CrtPfnAddr,
  4170. CaFieldOffset,
  4171. FilePointerFieldOffset,
  4172. FileNameFieldOffset,
  4173. UnicodeStrLengthFieldOffset,
  4174. UnicodeStrBufferFieldOffset,
  4175. CrtPfnAddr + OriginalPteFieldOffset,
  4176. Flags,
  4177. FileAddr,
  4178. CaAddr);
  4179. //
  4180. // Continue with the next PFN_NUMBER in the list.
  4181. //
  4182. *CurrentPfnNumberAddr = CrtPfnAddr + U1FlinkFieldOffset;
  4183. Done:
  4184. return ContinueWithNextPfn;
  4185. }
  4186. ///////////////////////////////////////////////////////////////////////
  4187. typedef struct _DBG_MNW_INFO {
  4188. ULONG64 FileObject;
  4189. ULONG64 ControlArea;
  4190. ULONG Count;
  4191. } DBG_MNW_INFO, *PDBG_MNW_INFO;
  4192. VOID
  4193. AddMwnPage (
  4194. IN ULONG64 FileAddr,
  4195. IN ULONG64 CaAddr,
  4196. IN OUT PDBG_MNW_INFO MnwInfo,
  4197. IN OUT PULONG EntryCount
  4198. )
  4199. {
  4200. ULONG Index;
  4201. //
  4202. // See if we already have this file object in the aray.
  4203. //
  4204. for (Index = 0; Index < *EntryCount; Index += 1) {
  4205. if (MnwInfo[Index].FileObject == FileAddr) {
  4206. //
  4207. // Found this file object. Increment its page count.
  4208. //
  4209. ASSERT (MnwInfo[Index].Count > 0);
  4210. MnwInfo[Index].Count += 1;
  4211. goto Done;
  4212. }
  4213. }
  4214. //
  4215. // Add a new entry for this file object.
  4216. //
  4217. MnwInfo[*EntryCount].ControlArea = CaAddr;
  4218. MnwInfo[*EntryCount].FileObject = FileAddr;
  4219. MnwInfo[*EntryCount].Count = 1;
  4220. *EntryCount += 1;
  4221. Done:
  4222. NOTHING;
  4223. }
  4224. int __cdecl
  4225. MwnInfoCompare(
  4226. const void *elem1,
  4227. const void *elem2
  4228. )
  4229. {
  4230. PDBG_MNW_INFO Info1;
  4231. PDBG_MNW_INFO Info2;
  4232. Info1 = (PDBG_MNW_INFO)elem1;
  4233. Info2 = (PDBG_MNW_INFO)elem2;
  4234. if (Info1->Count < Info2->Count) {
  4235. return -1;
  4236. }
  4237. else if (Info1->Count > Info2->Count) {
  4238. return 1;
  4239. }
  4240. else {
  4241. return 0;
  4242. }
  4243. }
  4244. VOID
  4245. DbgDumpMwnSummarry (
  4246. IN ULONG FileNameFieldOffset,
  4247. IN ULONG UnicodeStrLengthFieldOffset,
  4248. IN ULONG UnicodeStrBufferFieldOffset,
  4249. IN PDBG_MNW_INFO MnwInfo,
  4250. IN ULONG EntryCount
  4251. )
  4252. {
  4253. ULONG Index;
  4254. ULONG ErrorCode;
  4255. USHORT Length;
  4256. ULONG64 BufferAddr;
  4257. BOOL Success;
  4258. UNICODE_STRING UnicodeString;
  4259. const char Separator[] = "===================================================\n";
  4260. if (EntryCount > 0) {
  4261. //
  4262. // Sort by the number of pages per file object.
  4263. //
  4264. qsort (MnwInfo,
  4265. EntryCount,
  4266. sizeof (*MnwInfo),
  4267. MwnInfoCompare);
  4268. //
  4269. // Print out the summarry.
  4270. //
  4271. dprintf ("\n");
  4272. dprintf (Separator);
  4273. dprintf ("%8s %16s %16s FileName\n",
  4274. "PagesNo",
  4275. "ControlArea",
  4276. "FileObject");
  4277. dprintf (Separator);
  4278. for (Index = 0; Index < EntryCount; Index += 1) {
  4279. //
  4280. // Get the file name, if it's not paged out.
  4281. //
  4282. ZeroMemory (&UnicodeString,
  4283. sizeof (UnicodeString));
  4284. Success = ReadMemory (MnwInfo[Index].FileObject + FileNameFieldOffset + UnicodeStrLengthFieldOffset,
  4285. &Length,
  4286. sizeof (Length),
  4287. NULL);
  4288. if (Success != FALSE && Length > 0 && Length < 1024) {
  4289. UnicodeString.Buffer = malloc (Length);
  4290. if (UnicodeString.Buffer != NULL) {
  4291. ErrorCode = ReadPtr (MnwInfo[Index].FileObject + FileNameFieldOffset + UnicodeStrBufferFieldOffset,
  4292. &BufferAddr);
  4293. if (ErrorCode == S_OK) {
  4294. Success = ReadMemory (BufferAddr,
  4295. UnicodeString.Buffer,
  4296. Length,
  4297. NULL);
  4298. if (Success != FALSE) {
  4299. UnicodeString.Length = Length;
  4300. UnicodeString.MaximumLength = UnicodeString.Length;
  4301. }
  4302. }
  4303. }
  4304. }
  4305. dprintf ("%8x %16p %16p %wZ\n",
  4306. MnwInfo[Index].Count,
  4307. MnwInfo[Index].ControlArea,
  4308. MnwInfo[Index].FileObject,
  4309. &UnicodeString);
  4310. if (UnicodeString.Buffer != NULL) {
  4311. free (UnicodeString.Buffer);
  4312. UnicodeString.Buffer = NULL;
  4313. }
  4314. }
  4315. dprintf (Separator);
  4316. }
  4317. }
  4318. ULONG
  4319. DumpModifiedNoWriteInformation (
  4320. ULONG Flags
  4321. )
  4322. {
  4323. ULONG64 MmModifiedNoWritePageListHeadAddr;
  4324. ULONG64 TotalAddr;
  4325. ULONG64 CurrentPfnNumberAddr;
  4326. ULONG64 MmPfnDatabaseAddr;
  4327. ULONG64 FirstPfnAddr;
  4328. ULONG64 FileAddr;
  4329. ULONG64 CaAddr;
  4330. ULONG64 TotalPages64 = 0;
  4331. ULONG64 CrtPageIndex = 0;
  4332. ULONG FlinkFieldOffset;
  4333. ULONG TotalFieldOffset;
  4334. ULONG OriginalPteFieldOffset;
  4335. ULONG U1FlinkFieldOffset;
  4336. ULONG CaFieldOffset;
  4337. ULONG FilePointerFieldOffset;
  4338. ULONG FileNameFieldOffset;
  4339. ULONG UnicodeStrLengthFieldOffset;
  4340. ULONG UnicodeStrBufferFieldOffset;
  4341. ULONG TotalPages32;
  4342. ULONG ErrorCode;
  4343. ULONG MmPfnTypeSize;
  4344. ULONG MnwInfoEntryCount;
  4345. BOOL Continue;
  4346. const char Separator[] = "================================================================================================\n";
  4347. PDBG_MNW_INFO MnwInfo = NULL;
  4348. //
  4349. // Verify the size of PFN_NUMBER. We expect this to be 32 bit
  4350. // on x86 and 64 bit on the other platforms.
  4351. //
  4352. if (VerifyExpectedPfnNumberSize () == FALSE) {
  4353. goto Done;
  4354. }
  4355. dprintf ("\nLooking for pages in the ModifiedNoWrite list...\n");
  4356. //
  4357. // Get the address of MmModifiedNoWritePageListHead.
  4358. //
  4359. MmModifiedNoWritePageListHeadAddr = GetExpression ("&nt!MmModifiedNoWritePageListHead");
  4360. if (MmModifiedNoWritePageListHeadAddr == 0 ) {
  4361. dprintf ("ERROR: Unable to resolve nt!MmModifiedNoWritePageListHead\n");
  4362. goto Done;
  4363. }
  4364. dprintf ("MmModifiedNoWritePageListHead at 0x%p\n",
  4365. MmModifiedNoWritePageListHeadAddr);
  4366. //
  4367. // Find out the offset of Total inside the MMPFNLIST structure.
  4368. //
  4369. ErrorCode = GetFieldOffset ("nt!_MMPFNLIST",
  4370. "Total",
  4371. &TotalFieldOffset);
  4372. if (ErrorCode != S_OK) {
  4373. dprintf ("ERROR: Cannot get Total field offset inside nt!_MMPFNLIST.\n");
  4374. goto Done;
  4375. }
  4376. TotalAddr = MmModifiedNoWritePageListHeadAddr + TotalFieldOffset;
  4377. //
  4378. // Display the total number of PFNs in the list.
  4379. //
  4380. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  4381. TotalPages32 = 0;
  4382. Continue = ReadMemory (TotalAddr,
  4383. &TotalPages32,
  4384. sizeof (TotalPages32),
  4385. NULL);
  4386. TotalPages64 = (ULONG64) TotalPages32;
  4387. }
  4388. else {
  4389. Continue = ReadMemory (TotalAddr,
  4390. &TotalPages64,
  4391. sizeof (TotalPages64),
  4392. NULL);
  4393. }
  4394. if (Continue == FALSE) {
  4395. dprintf ("ERROR: Cannot read number of list entries at 0x%p\n",
  4396. TotalAddr);
  4397. goto Done;
  4398. }
  4399. dprintf ("Number of pages: 0x%I64x\n",
  4400. TotalPages64);
  4401. if (Flags & 1) {
  4402. MnwInfo = malloc ( (SIZE_T)TotalPages64 * sizeof (*MnwInfo));
  4403. if (MnwInfo == NULL) {
  4404. dprintf ("ERRROR: Cannot allocate memory for the summary info - dumping detailed info only\n");
  4405. Flags = (Flags & ~1) | 2;
  4406. }
  4407. }
  4408. //
  4409. // Get the field offset of ControlArea inside nt!_SUBSECTION
  4410. //
  4411. ErrorCode = GetFieldOffset ("nt!_SUBSECTION",
  4412. "ControlArea",
  4413. &CaFieldOffset);
  4414. if (ErrorCode != S_OK) {
  4415. dprintf ("ERROR: Cannot get ControlArea field offset inside nt!_SUBSECTION.\n");
  4416. goto Done;
  4417. }
  4418. //
  4419. // Get the field offset of FilePointer inside nt!_CONTROL_AREA.
  4420. //
  4421. ErrorCode = GetFieldOffset ("nt!_CONTROL_AREA",
  4422. "FilePointer",
  4423. &FilePointerFieldOffset);
  4424. if (ErrorCode != S_OK) {
  4425. dprintf ("ERROR: Cannot get FilePointer field offset inside nt!_CONTROL_AREA.\n");
  4426. goto Done;
  4427. }
  4428. //
  4429. // Get the field offset of FileName inside nt!_FILE_OBJECT.
  4430. //
  4431. ErrorCode = GetFieldOffset ("nt!_FILE_OBJECT",
  4432. "FileName",
  4433. &FileNameFieldOffset);
  4434. if (ErrorCode != S_OK) {
  4435. dprintf ("ERROR: Cannot get FileName field offset inside nt!_FILE_OBJECT.\n");
  4436. goto Done;
  4437. }
  4438. //
  4439. // Get the field offset of Length inside nt!_UNICODE_STRING.
  4440. //
  4441. ErrorCode = GetFieldOffset ("nt!_UNICODE_STRING",
  4442. "Length",
  4443. &UnicodeStrLengthFieldOffset);
  4444. if (ErrorCode != S_OK) {
  4445. dprintf ("ERROR: Cannot get Length field offset inside nt!_UNICODE_STRING.\n");
  4446. goto Done;
  4447. }
  4448. //
  4449. // Get the field offset of Length inside nt!_UNICODE_STRING.
  4450. //
  4451. ErrorCode = GetFieldOffset ("nt!_UNICODE_STRING",
  4452. "Buffer",
  4453. &UnicodeStrBufferFieldOffset);
  4454. if (ErrorCode != S_OK) {
  4455. dprintf ("ERROR: Cannot get Buffer field offset inside nt!_UNICODE_STRING.\n");
  4456. goto Done;
  4457. }
  4458. //
  4459. // Get the PFN database array address.
  4460. //
  4461. MmPfnDatabaseAddr = GetExpression ("&nt!MmPfnDatabase");
  4462. if (MmPfnDatabaseAddr == 0 ) {
  4463. dprintf( "ERROR: Unable to resolve nt!MmPfnDatabase\n");
  4464. goto Done;
  4465. }
  4466. //
  4467. // Get the address of the first PFN in the database.
  4468. //
  4469. ErrorCode = ReadPtr (MmPfnDatabaseAddr,
  4470. &FirstPfnAddr);
  4471. if (ErrorCode != S_OK) {
  4472. dprintf ("ERROR: Cannot read PFN address from 0x%p\n",
  4473. MmPfnDatabaseAddr);
  4474. goto Done;
  4475. }
  4476. //
  4477. // Get the size of the _MMPFN stucture.
  4478. //
  4479. MmPfnTypeSize = GetTypeSize ("nt!_MMPFN");
  4480. if (MmPfnTypeSize == 0) {
  4481. dprintf ("ERROR: Cannot get the size of nt!_MMPFN.\n");
  4482. goto Done;
  4483. }
  4484. //
  4485. // Get the offset of the OriginalPte field inside nt!_MMPFN.
  4486. //
  4487. ErrorCode = GetFieldOffset ("nt!_MMPFN",
  4488. "OriginalPte",
  4489. &OriginalPteFieldOffset);
  4490. if (ErrorCode != S_OK) {
  4491. dprintf ("ERROR: Cannot get OriginalPte field offset inside nt!_MMPFN.\n");
  4492. goto Done;
  4493. }
  4494. //
  4495. // Get the offset of the OriginalPte field inside nt!_MMPFN.
  4496. //
  4497. ErrorCode = GetFieldOffset ("nt!_MMPFN",
  4498. "u1.Flink",
  4499. &U1FlinkFieldOffset);
  4500. if (ErrorCode != S_OK) {
  4501. dprintf ("ERROR: Cannot get u1.Flink field offset inside nt!_MMPFN.\n");
  4502. goto Done;
  4503. }
  4504. //
  4505. // Get the offset of Flink inside the MMPFNLIST structure.
  4506. //
  4507. ErrorCode = GetFieldOffset ("nt!_MMPFNLIST",
  4508. "Flink",
  4509. &FlinkFieldOffset);
  4510. if (ErrorCode != S_OK) {
  4511. dprintf ("ERROR: Cannot get Flink field offset inside nt!_MMPFNLIST.\n");
  4512. goto Done;
  4513. }
  4514. //
  4515. // Parse all the PFN list, starting with the head.
  4516. //
  4517. if (TotalPages64 > 0) {
  4518. if (Flags & 2) {
  4519. dprintf ("\n");
  4520. dprintf (Separator);
  4521. dprintf ("%16s %16s %16s %16s %16s File Name\n",
  4522. "PFN number",
  4523. "PFN address",
  4524. "Subsection",
  4525. "ControlArea",
  4526. "FileObject");
  4527. dprintf (Separator);
  4528. }
  4529. CurrentPfnNumberAddr = MmModifiedNoWritePageListHeadAddr + FlinkFieldOffset;
  4530. MnwInfoEntryCount = 0;
  4531. for (CrtPageIndex = 0; CrtPageIndex < TotalPages64; CrtPageIndex += 1) {
  4532. if (CheckControlC()) {
  4533. goto DisplayStatistics;
  4534. }
  4535. //
  4536. // Read the current PFN.
  4537. //
  4538. Continue = DumpMnwPfnInfoFromPfnNoAddr (FirstPfnAddr,
  4539. MmPfnTypeSize,
  4540. OriginalPteFieldOffset,
  4541. U1FlinkFieldOffset,
  4542. CaFieldOffset,
  4543. FilePointerFieldOffset,
  4544. FileNameFieldOffset,
  4545. UnicodeStrLengthFieldOffset,
  4546. UnicodeStrBufferFieldOffset,
  4547. Flags,
  4548. &CurrentPfnNumberAddr,
  4549. &FileAddr,
  4550. &CaAddr);
  4551. if (Continue == FALSE) {
  4552. goto DisplayStatistics;
  4553. }
  4554. if (Flags & 1) {
  4555. AddMwnPage (FileAddr,
  4556. CaAddr,
  4557. MnwInfo,
  4558. &MnwInfoEntryCount);
  4559. }
  4560. }
  4561. DisplayStatistics:
  4562. if ((Flags & 2) && CrtPageIndex > 0) {
  4563. dprintf (Separator);
  4564. }
  4565. if (Flags & 1) {
  4566. DbgDumpMwnSummarry (FileNameFieldOffset,
  4567. UnicodeStrLengthFieldOffset,
  4568. UnicodeStrBufferFieldOffset,
  4569. MnwInfo,
  4570. MnwInfoEntryCount);
  4571. }
  4572. dprintf ("\n\nPages displayed: 0x%I64x. Total pages 0x%I64x.\n",
  4573. CrtPageIndex,
  4574. TotalPages64);
  4575. }
  4576. Done:
  4577. if (MnwInfo != NULL) {
  4578. free (MnwInfo);
  4579. }
  4580. return S_OK;
  4581. }