/*++ Copyright (c) 1992 Microsoft Corporation Module Name: memory.c Abstract: WinDbg Extension Api Author: Lou Perazzoli (loup) Environment: User Mode. Revision History: --*/ #include "precomp.h" #pragma hdrstop #define PACKET_MAX_SIZE 4000 #define USAGE_ALLOC_SIZE 256*1024 #ifdef _KB #undef _KB #endif #define _KB (PageSize/1024) typedef struct _PFN_INFO { ULONG64 Master; ULONG64 OriginalPte; ULONG ValidCount; ULONG StandbyCount; ULONG ModifiedCount; ULONG SharedCount; ULONG LockedCount; ULONG PageTableCount; struct _PFN_INFO *Next; } PFN_INFO, *PPFN_INFO; typedef struct _KERN_MAP1 { ULONG64 StartVa; ULONG64 EndVa; ULONG ValidCount; ULONG StandbyCount; ULONG ModifiedCount; ULONG SharedCount; ULONG LockedCount; ULONG PageTableCount; WCHAR Name[256]; } KERN_MAP1, *PKERN_MAP1; typedef struct _KERN_MAP { ULONG Count; KERN_MAP1 Item[500]; } KERN_MAP, *PKERN_MAP; typedef struct _MMPFNENTRY { ULONG Modified : 1; ULONG ReadInProgress : 1; ULONG WriteInProgress : 1; ULONG PrototypePte: 1; ULONG PageColor : 3; ULONG ParityError : 1; ULONG PageLocation : 3; ULONG RemovalRequested : 1; ULONG CacheAttribute : 2; ULONG Rom : 1; ULONG LockCharged : 1; ULONG DontUse : 16; //overlays USHORT for reference count field. } MMPFNENTRY; typedef struct _MMPFN_READ { MMPFNENTRY u3_e1; ULONG u3_e2_ReferenceCount; ULONG64 u1_Flink, u2_Blink, PteAddress, OriginalPte, PteFrame; } MMPFN_READ, *PMMPFN_READ; typedef struct _PFN_DUMP_CTXT { BOOL PrintIndex; ULONG64 index; BOOL ZeroAfterPrint; PMMPFN_READ pReadPfn; } PFN_DUMP_CTXT, *PPFN_DUMP_CTXT; UCHAR *PageLocationList[] = { (PUCHAR)"Zeroed ", (PUCHAR)"Free ", (PUCHAR)"Standby ", (PUCHAR)"Modified", (PUCHAR)"ModNoWrt", (PUCHAR)"Bad ", (PUCHAR)"Active ", (PUCHAR)"Trans " }; UCHAR *PageAttribute[] = { (PUCHAR)"NonCached", (PUCHAR)"Cached ", (PUCHAR)"WriteComb", (PUCHAR)"NotMapped" }; ULONG64 MmSubsectionBase; ULONG64 MaxDirbase; #define MAX_DIRBASEVECTOR 256 ULONG64 DirBases[MAX_DIRBASEVECTOR]; UCHAR Names[MAX_DIRBASEVECTOR][64]; VOID PrintPfn64 ( IN ULONG64 PfnAddress ); VOID DumpMmThreads ( VOID ); VOID DumpWholePfn( IN ULONG64 Address, IN ULONG Flags ); PUCHAR DirbaseToImage( IN ULONG64 DirBase ); NTSTATUS BuildDirbaseList( VOID ); LOGICAL BuildKernelMap ( OUT PKERN_MAP KernelMap ); ULONG DbgGetPfnSize( VOID ) { return GetTypeSize("nt!_MMPFN"); } LOGICAL PoolGetTag ( IN PVOID PoolAddress, IN PULONG PoolTag ); ULONG64 SystemRangeStart; DECLARE_API( memusage ) /*++ Routine Description: Dumps the page frame database table Arguments: arg - Return Value: None. --*/ { ULONG result; ULONG64 PfnDb; ULONG64 HighPageAddr; ULONG64 LowPageAddr; ULONG64 HighPage=0; ULONG64 LowPage=0; ULONG64 PageCount; ULONG64 ReadCount; ULONG WasZeroedPage; ULONG WasFreePage; ULONG Total; ULONG WasStandbyPage; ULONG WasModifiedPage; ULONG WasModifiedNoWritePage; ULONG WasBadPage; ULONG WasActiveAndValidPage; ULONG WasTransitionPage; ULONG WasUnknownPage; ULONG64 NPPoolStart; ULONG64 NPSystemStart; ULONG64 Pfn; ULONG64 PfnStart; PCHAR PfnArray; ULONG PfnSize; ULONG NumberOfPfnToRead; ULONG CompleteSoFar = (ULONG) ~0; ULONG64 CacheSize; UNREFERENCED_PARAMETER (args); UNREFERENCED_PARAMETER (Client); LowPageAddr = GetNtDebuggerData(MmLowestPhysicalPage); HighPageAddr = GetNtDebuggerData(MmHighestPhysicalPage); PfnDb = GetNtDebuggerData(MmPfnDatabase); NPPoolStart = GetNtDebuggerData(MmNonPagedPoolStart); NPSystemStart = GetNtDebuggerData(MmNonPagedSystemStart); SystemRangeStart = GetNtDebuggerDataValue(MmSystemRangeStart); PfnSize = GetTypeSize("nt!_MMPFN"); NumberOfPfnToRead = 300; if ( LowPageAddr && HighPageAddr && PfnDb && NPPoolStart && NPSystemStart ) { if ( !ReadPointer( LowPageAddr, &LowPage) ) { dprintf("%08p: Unable to get low physical page\n",LowPageAddr); return E_INVALIDARG; } if ( !ReadPointer( HighPageAddr,&HighPage) ) { dprintf("%08p: Unable to get high physical page\n",HighPageAddr); return E_INVALIDARG; } if ( !ReadPointer( PfnDb,&PfnStart) ) { dprintf("%08p: Unable to get PFN database address\n",PfnDb); return E_INVALIDARG; } #ifdef IG_GET_CACHE_SIZE if (GetDebuggerCacheSize(&CacheSize)) { if (CacheSize < (HighPage - LowPage)*PfnSize) { dprintf("*** WARNING Cache size too low, !memusage might take long time to run\n" " Increase Cache to %#lx kb for better performance.\n", (HighPage - LowPage)*PfnSize / 1024); } } #endif dprintf(" loading PFN database\n"); PfnArray = VirtualAlloc ( NULL, (ULONG) ((HighPage-LowPage+1) * PfnSize), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!PfnArray) { dprintf("Unable to get allocate memory of %I64ld bytes\n", (HighPage+1) * PfnSize); } else { for (PageCount = LowPage; PageCount <= HighPage; PageCount += NumberOfPfnToRead) { //dprintf("getting PFN table block - " // "address %lx - count %lu - page %lu\n", // Pfn, ReadCount, PageCount); if ( CheckControlC() ) { VirtualFree (PfnArray,0,MEM_RELEASE); return E_INVALIDARG; } ReadCount = HighPage - PageCount > NumberOfPfnToRead ? NumberOfPfnToRead : HighPage - PageCount + 1; ReadCount *= PfnSize; Pfn = (PfnStart + PageCount * PfnSize); if (CompleteSoFar != (ULONG) (((PageCount + LowPage) * 100)/ HighPage)) { CompleteSoFar = (ULONG) (((PageCount + LowPage) * 100)/ HighPage); dprintf("loading (%d%% complete)\r", CompleteSoFar); } // Let KD cache the data - we won't be reading from the array. if ( !ReadMemory( Pfn, PfnArray + PageCount * PfnSize, (ULONG) ReadCount, &result) ) { dprintf("Unable to get PFN table block - " "address %p - count %lu - page %lu\n", Pfn, ReadCount, PageCount); VirtualFree (PfnArray,0,MEM_RELEASE); return E_INVALIDARG; } } dprintf("\n"); // Now we have a local copy: let's take a look WasZeroedPage = 0; WasFreePage = 0; WasStandbyPage = 0; WasModifiedPage = 0; WasModifiedNoWritePage = 0; WasBadPage = 0; WasActiveAndValidPage = 0; WasTransitionPage = 0; WasUnknownPage = 0; CompleteSoFar = 0; for (PageCount = LowPage; PageCount <= HighPage; PageCount++) { ULONG PageLocation=0; ULONG64 Flink=0, Blink=0; if ( CheckControlC() ) { VirtualFree (PfnArray,0,MEM_RELEASE); return E_INVALIDARG; } if (CompleteSoFar < (ULONG) (((PageCount + LowPage) * 100)/ HighPage)) { CompleteSoFar = (ULONG) (((PageCount + LowPage) * 100)/ HighPage); dprintf("Compiling memory usage data (%d%% Complete).\r", CompleteSoFar); } Pfn = (PfnStart + PageCount * PfnSize); GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1.PageLocation", PageLocation); switch (PageLocation) { case ZeroedPageList: GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", Flink); GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", Blink); if ((Flink == 0) && (Blink == 0)) { WasActiveAndValidPage++; } else { WasZeroedPage++; } break; case FreePageList: WasFreePage++; break; case StandbyPageList: WasStandbyPage++; break; case ModifiedPageList: WasModifiedPage++; break; case ModifiedNoWritePageList: WasModifiedNoWritePage++; break; case BadPageList: WasModifiedNoWritePage++; break; case ActiveAndValid: WasActiveAndValidPage++; break; case TransitionPage: WasTransitionPage++; break; default: WasUnknownPage++; break; } } dprintf("\n"); dprintf( " Zeroed: %6lu (%6lu kb)\n", WasZeroedPage, WasZeroedPage * _KB); dprintf( " Free: %6lu (%6lu kb)\n", WasFreePage, WasFreePage * _KB); dprintf( " Standby: %6lu (%6lu kb)\n", WasStandbyPage, WasStandbyPage * _KB); dprintf( " Modified: %6lu (%6lu kb)\n", WasModifiedPage, WasModifiedPage * _KB); dprintf( " ModifiedNoWrite: %6lu (%6lu kb)\n", WasModifiedNoWritePage,WasModifiedNoWritePage * _KB); dprintf( " Active/Valid: %6lu (%6lu kb)\n", WasActiveAndValidPage, WasActiveAndValidPage * _KB); dprintf( " Transition: %6lu (%6lu kb)\n", WasTransitionPage, WasTransitionPage * _KB); dprintf( " Unknown: %6lu (%6lu kb)\n", WasUnknownPage, WasUnknownPage * _KB); Total = WasZeroedPage + WasFreePage + WasStandbyPage + WasModifiedPage + WasModifiedNoWritePage + WasActiveAndValidPage + WasTransitionPage + WasUnknownPage + WasUnknownPage; dprintf( " TOTAL: %6lu (%6lu kb)\n", Total, Total * _KB); } MemoryUsage (PfnStart, LowPage, HighPage, 0); VirtualFree (PfnArray,0,MEM_RELEASE); } return S_OK; } DECLARE_API( lockedpages ) /*++ Routine Description: Displays the driver-locked pages. Arguments: None. Return Value: None. --*/ { ULONG64 LockHeader; ULONG64 LockTracker; ULONG64 NextEntry; ULONG GlistOff; ULONG64 Count; CHAR Buffer[256]; ULONG64 displacement; UNREFERENCED_PARAMETER (args); UNREFERENCED_PARAMETER (Client); LockHeader = GetExpression ("nt!MmLockedPagesHead"); if (GetFieldValue(LockHeader, "nt!_LOCK_HEADER", "Count", Count)) { dprintf("%08p: Unable to get lock header data.\n", LockHeader); return E_INVALIDARG; } GetFieldValue(LockHeader,"nt!_LOCK_HEADER","ListHead.Flink", NextEntry); if (NextEntry == 0) { dprintf("Locked pages tracking not enabled\n"); return E_INVALIDARG; } if (NextEntry == LockHeader) { dprintf("There are no pages currently locked.\n"); return E_INVALIDARG; } dprintf("%I64d locked pages...\n", Count); dprintf("Tracker MDL PageCount Caller/CallersCaller\n"); GetFieldOffset("LOCK_TRACKER", "GlobalListEntry", &GlistOff); while (NextEntry != LockHeader) { LockTracker = (NextEntry - GlistOff); if (GetFieldValue(LockTracker, "nt!LOCK_TRACKER", "GlobalListEntry.Flink", NextEntry)) { dprintf("%08p: Unable to get lock tracker data.\n", LockTracker); return E_INVALIDARG; } InitTypeRead(LockTracker, nt!LOCK_TRACKER); dprintf("Tracker %p : MDL @ %p, PageCount = %I64x, Caller = %p %p\n", LockTracker, ReadField(Mdl), ReadField(Count)); Buffer[0] = '!'; GetSymbol (ReadField(CallingAddress), (PCHAR)Buffer, &displacement); dprintf("%s", Buffer); if (displacement) { dprintf( "+0x%1p", displacement ); } dprintf("/"); Buffer[0] = '!'; GetSymbol (ReadField(CallersCaller), (PCHAR)Buffer, &displacement); dprintf("%s", Buffer); if (displacement) { dprintf( "+0x%1p", displacement ); } dprintf("\n"); if (CheckControlC()) { break; } } return S_OK; } DECLARE_API( pfnperf ) /*++ Routine Description: Displays the PFN spinlock duration list. Arguments: None. Return Value: None. --*/ { ULONG64 PfnDuration; ULONG64 PfnEntry; ULONG64 displacement; ULONG64 AcquiredAddress; ULONG64 ReleasedAddress; CHAR SymbolBuffer[80]; PCHAR SymPointer; ULONG EntrySize; ULONG result; ULONG64 ReadCount; ULONG64 i; PCHAR LocalData; PCHAR local; ULONG64 NumberOfPfnEntries; UNREFERENCED_PARAMETER (args); UNREFERENCED_PARAMETER (Client); PfnDuration = GetExpression ("nt!MiPfnSorted"); if (PfnDuration == 0) { dprintf("%08p: Unable to get PFN duration data.\n", PfnDuration); return E_INVALIDARG; } PfnEntry = PfnDuration; EntrySize = GetTypeSize("nt!_MMPFNTIMINGS"); NumberOfPfnEntries = GetUlongValue ("MiMaxPfnTimings"); dprintf("Top %ld PFN lock holders sorted by duration\n", NumberOfPfnEntries); LocalData = LocalAlloc(LPTR, (ULONG) (NumberOfPfnEntries * EntrySize)); if (!LocalData) { dprintf("unable to get allocate %ld bytes of memory\n", NumberOfPfnEntries * EntrySize); return E_INVALIDARG; } ReadCount = NumberOfPfnEntries * EntrySize; if ((!ReadMemory(PfnDuration, LocalData, (ULONG) ReadCount, &result)) || (result < (ULONG) ReadCount)) { dprintf("unable to get PFN duration table - " "address %p - count %I64u\n", LocalData, ReadCount); } else { dprintf("\nDuration LockAcquirer LockReleaser\n"); local = LocalData; for (i = 0; i < NumberOfPfnEntries; i += 1) { ULONG64 HoldTime=0, Address = 0; GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "HoldTime", HoldTime); GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "AcquiredAddress", AcquiredAddress); GetFieldValue(PfnEntry, "nt!_MMPFNTIMINGS", "ReleasedAddress", ReleasedAddress); // // Sign extend if necessary. // if (!IsPtr64()) { AcquiredAddress = (ULONG64)(LONG64)(LONG)AcquiredAddress; ReleasedAddress = (ULONG64)(LONG64)(LONG)ReleasedAddress; } // // Output a '*' if the lock was contended for, '.' if not. // dprintf( "%3d%c %I64ld ", (ULONG)i, HoldTime & 0x1 ? '*' : '.', HoldTime ); SymbolBuffer[0] = '!'; GetSymbol(AcquiredAddress, (PCHAR)SymbolBuffer, &displacement); SymPointer = SymbolBuffer; while (*SymPointer != '!') { SymPointer += 1; } SymPointer += 1; dprintf ("%s", SymPointer); if (displacement) { dprintf( "+0x%x", displacement ); } dprintf( ", "); SymbolBuffer[0] = '!'; GetSymbol(ReleasedAddress, (PCHAR)SymbolBuffer, &displacement); SymPointer = SymbolBuffer; while (*SymPointer != '!') { SymPointer += 1; } SymPointer += 1; dprintf ("%s", SymPointer); if (displacement) { dprintf( "+0x%x", displacement ); } dprintf( "\n"); PfnEntry += EntrySize; } } if (LocalData) { LocalFree((void *)LocalData); } return S_OK; } DECLARE_API( pfn ) /*++ Routine Description: Displays the corresponding PDE and PTE. Arguments: arg - Supplies the Page frame number in hex. Return Value: None. --*/ { ULONG64 Address; ULONG64 PfnDb; ULONG64 Pfn; ULONG64 PfnStart; ULONG Flags; ULONG PfnSize; PfnSize = GetTypeSize("nt!_MMPFN"); if (!PfnSize) { dprintf("unable to _MMPFN type.\n"); return E_INVALIDARG; } PfnDb = GetNtDebuggerData( MmPfnDatabase ); if (!PfnDb) { dprintf("unable to get PFN0 database address\n"); return E_INVALIDARG; } PfnStart = 0; if (!ReadPointer(PfnDb,&PfnStart)) { dprintf("unable to get PFN database address %p\n", PfnDb); return E_INVALIDARG; } Address = 0; Flags = 0; if (GetExpressionEx(args, &Address, &args)) { Flags = (ULONG) GetExpression(args); } if (Flags != 0) { if (!TargetIsDump) { ULONG64 CacheSize; Ioctl(IG_GET_CACHE_SIZE, &CacheSize, sizeof(CacheSize)); if (TargetMachine == IMAGE_FILE_MACHINE_IA64) { if (CacheSize < 0x10000000) { dprintf("CacheSize too low - increasing to 10M\n"); ExecuteCommand(Client, ".cache 10000"); } } else if (CacheSize < 0x1000000) { dprintf("CacheSize too low - increasing to 1M\n"); ExecuteCommand(Client, ".cache 1000"); } } DumpWholePfn ( Address, Flags); return E_INVALIDARG; } if (Address >= PfnStart) { // // Ensure any passed in address is offsetted correctly. // Address = (Address - PfnStart) / PfnSize; } Pfn = (PfnStart + Address * PfnSize); PrintPfn64(Pfn); return S_OK; } VOID DumpTerminalServerMemory ( VOID ) { ULONG64 Next; ULONG64 SessionListPointer; ULONG64 SessionData; ULONG SessionId; ULONG SessionWsListLinksOffset; ULONG64 NonPagedPoolBytes; ULONG64 PagedPoolBytes; ULONG64 CommittedPages; ULONG Failures; ULONG TotalFailures; ULONG64 SessionPoolSize; ULONG64 SessionViewSize; dprintf("\n\tTerminal Server Memory Usage By Session:\n\n"); // Get the offset of ActiveProcessLinks in _EPROCESS if (GetFieldOffset("nt!_MM_SESSION_SPACE", "WsListEntry", &SessionWsListLinksOffset)) { return; } SessionListPointer = GetExpression ("nt!MiSessionWsList"); if (!SessionListPointer) { dprintf("Unable to get value of SessionListPointer\n"); return; } if (GetFieldValue( SessionListPointer, "nt!_LIST_ENTRY", "Flink", Next )) { dprintf("Unable to read _LIST_ENTRY @ %p\n", SessionListPointer); return; } SessionPoolSize = GetUlongValue ("MmSessionPoolSize"); SessionViewSize = GetUlongValue ("MmSessionViewSize"); dprintf("\tSession Paged Pool Maximum is %ldK\n", SessionPoolSize / 1024); dprintf("\tSession View Space Maximum is %ldK\n", SessionViewSize / 1024); while(Next != SessionListPointer) { SessionData = Next - SessionWsListLinksOffset; if (GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionId", SessionId )) { dprintf("Unable to read _MM_SESSION_SPACE at %p\n",SessionData); return; } TotalFailures = 0; dprintf("\n\tSession ID %x @ %p:\n",SessionId, SessionData); GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "NonPagedPoolBytes", NonPagedPoolBytes ); GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "PagedPoolBytes", PagedPoolBytes ); GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "CommittedPages", CommittedPages ); GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[0]", Failures); TotalFailures += Failures; GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[1]", Failures); TotalFailures += Failures; GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[2]", Failures); TotalFailures += Failures; GetFieldValue( SessionData, "nt!_MM_SESSION_SPACE", "SessionPoolAllocationFailures[3]", Failures); TotalFailures += Failures; dprintf("\tNonpaged Pool Usage: %8I64ldK\n",NonPagedPoolBytes / 1024); dprintf("\tPaged Pool Usage: %8I64ldK\n",PagedPoolBytes / 1024); if (TotalFailures != 0) { dprintf("\n\t*** %ld Pool Allocation Failures ***\n\n",TotalFailures); } dprintf("\tCommit Usage: %8I64ldK\n",CommittedPages * _KB); GetFieldValue(SessionData, "nt!_MM_SESSION_SPACE", "WsListEntry.Flink", Next); if (CheckControlC()) { return; } } return; } #if (_MSC_VER < 1200) && defined(_M_IX86) #pragma optimize("g", off) #endif DECLARE_API( vm ) /*++ Routine Description: Displays physical memory usage by driver. Arguments: arg - Flags : 0 (default) == systemwide vm & per-process output. 1 == just systemwide vm counts, no per-process output. 2 == systemwide vm, per-process & Mm thread output. 3 == systemwide vm & Mm thread display, no per-process output. Return Value: None. --*/ { ULONG Flags; ULONG Index; ULONG64 MemorySize; ULONG64 CommitLimit; ULONG64 CommitTotal; ULONG64 SharedCommit; ULONG64 SpecialPoolPages; ULONG64 ProcessCommit; ULONG64 PagedPoolCommit; ULONG64 DriverCommit; ULONG64 ZeroPages; ULONG64 FreePages; ULONG64 StandbyPages; ULONG64 ModifiedPages; ULONG64 ModifiedNoWrite; ULONG64 NumberOfPagedPools; ULONG64 NumberOfPagingFiles; ULONG64 AvailablePages; ULONG64 LockPagesCount; ULONG64 SpecialPagesNonPaged; ULONG64 SpecialPagesNonPagedMaximum; ULONG64 FreePtesPointer; ULONG64 FreeNonPagedPtes; ULONG64 ResidentAvailablePages; ULONG64 PoolLoc; ULONG64 PoolLocBase; ULONG result; ULONG TotalPages; ULONG ExtendedCommit; ULONG64 TotalProcessCommit; PPROCESS_COMMIT_USAGE ProcessCommitUsage; ULONG i; ULONG NumberOfProcesses; ULONG64 PagedPoolBytesMax; ULONG64 PagedPoolBytes; ULONG64 NonPagedPoolBytesMax; ULONG64 NonPagedPoolBytes; ULONG64 PageFileBase; ULONG64 PageFilePointer; ULONG PageFileFullExtendPages; ULONG PageFileFullExtendCount; PUCHAR tempbuffer; UNICODE_STRING unicodeString; ULONG64 PagedPoolInfoPointer; ULONG64 FreeSystemPtes; UCHAR PagedPoolType[] = "nt!_MM_PAGED_POOL_INFO"; ULONG64 AllocatedPagedPool=0; ULONG Desc_TotalPages=0, TotalBigPages=0, Desc_size; ULONG PtrSize = DBG_PTR_SIZE; ULONG NumberOfNonPagedPools; ULONG64 ExpNumberOfNonPagedPools; Flags = 0; Flags = (ULONG) GetExpression(args); dprintf("\n*** Virtual Memory Usage ***\n"); MemorySize = GetNtDebuggerDataValue(MmNumberOfPhysicalPages); dprintf ("\tPhysical Memory: %8I64ld (%8I64ld Kb)\n",MemorySize,_KB*MemorySize); NumberOfPagingFiles = GetNtDebuggerDataValue(MmNumberOfPagingFiles); PageFilePointer = GetExpression ("nt!MmPagingFile"); if (NumberOfPagingFiles == 0) { dprintf("\n************ NO PAGING FILE *********************\n\n"); } else { for (i = 0; i < NumberOfPagingFiles; i++) { ULONG64 PageFileName_Buffer=0; if (!ReadPointer(PageFilePointer, &PageFileBase)) { dprintf("%08p: Unable to get page file\n",PageFilePointer); break; } if (GetFieldValue(PageFileBase, "nt!_MMPAGING_FILE", "PageFileName.Buffer", PageFileName_Buffer)) { dprintf("%08p: Unable to get page file\n",PageFilePointer); break; } InitTypeRead(PageFileBase, nt!_MMPAGING_FILE); if (PageFileName_Buffer == 0) { dprintf("\tNo Name for Paging File\n\n"); } else { unicodeString.Length = (USHORT) ReadField(PageFileName.Length); tempbuffer = LocalAlloc(LPTR, unicodeString.Length); unicodeString.Buffer = (PWSTR)tempbuffer; unicodeString.MaximumLength = unicodeString.Length; if (!ReadMemory ( PageFileName_Buffer, tempbuffer, unicodeString.Length, &result)) { dprintf("\tPaging File Name paged out\n"); } else { dprintf("\tPage File: %wZ\n", &unicodeString); } LocalFree(tempbuffer); } dprintf("\t Current: %9I64ldKb Free Space: %9I64ldKb\n", ReadField(Size)*_KB, ReadField(FreeSpace)*_KB); dprintf("\t Minimum: %9I64ldKb Maximum: %9I64ldKb\n", ReadField(MinimumSize)*_KB, ReadField(MaximumSize)*_KB); PageFilePointer += PtrSize; } } PagedPoolInfoPointer = GetExpression ("nt!MmPagedPoolInfo"); if (GetFieldValue(PagedPoolInfoPointer, PagedPoolType, "AllocatedPagedPool", AllocatedPagedPool)) { dprintf("%08p: Unable to get paged pool info %p\n",PagedPoolInfoPointer); } PagedPoolBytesMax = GetNtDebuggerDataValue(MmSizeOfPagedPoolInBytes); PagedPoolBytes = AllocatedPagedPool; PagedPoolBytes *= PageSize; NonPagedPoolBytesMax = GetNtDebuggerDataValue(MmMaximumNonPagedPoolInBytes); NonPagedPoolBytes = GetUlongValue ("MmAllocatedNonPagedPool"); NonPagedPoolBytes *= PageSize; CommitLimit = GetNtDebuggerDataValue(MmTotalCommitLimit); CommitTotal = GetNtDebuggerDataValue(MmTotalCommittedPages); SharedCommit = GetNtDebuggerDataValue(MmSharedCommit); DriverCommit = GetNtDebuggerDataValue(MmDriverCommit); ProcessCommit = GetNtDebuggerDataValue(MmProcessCommit); PagedPoolCommit = GetNtDebuggerDataValue(MmPagedPoolCommit); ZeroPages = GetNtDebuggerDataValue(MmZeroedPageListHead); FreePages = GetNtDebuggerDataValue(MmFreePageListHead); StandbyPages = GetNtDebuggerDataValue(MmStandbyPageListHead); ModifiedPages = GetNtDebuggerDataValue(MmModifiedPageListHead); ModifiedNoWrite = GetNtDebuggerDataValue(MmModifiedNoWritePageListHead); AvailablePages = GetNtDebuggerDataValue(MmAvailablePages); ResidentAvailablePages = GetNtDebuggerDataValue(MmResidentAvailablePages); if (BuildNo < 2257) { ExtendedCommit = GetUlongValue("MmExtendedCommit"); PageFileFullExtendPages = GetUlongValue("MmPageFileFullExtendPages"); PageFileFullExtendCount = GetUlongValue("MmPageFileFullExtendCount"); } FreeSystemPtes = GetUlongValue("MmTotalFreeSystemPtes"); LockPagesCount = GetUlongValue("MmSystemLockPagesCount"); SpecialPagesNonPaged = GetUlongValue("MiSpecialPagesNonPaged"); SpecialPagesNonPagedMaximum = GetUlongValue("MiSpecialPagesNonPagedMaximum"); FreePtesPointer = GetExpression ("nt!MmTotalFreeSystemPtes"); FreePtesPointer += sizeof(ULONG); FreeNonPagedPtes = 0; if (!ReadMemory (FreePtesPointer, &FreeNonPagedPtes, sizeof(ULONG), &result)) { dprintf("\tError reading free nonpaged PTEs %p\n", FreePtesPointer); } SpecialPoolPages = GetUlongValue("nt!MmSpecialPagesInUse"); dprintf("\tAvailable Pages: %8I64ld (%8I64ld Kb)\n",AvailablePages, AvailablePages*_KB); dprintf("\tResAvail Pages: %8I64ld (%8I64ld Kb)\n",ResidentAvailablePages, ResidentAvailablePages*_KB); if ((LONG64) (ResidentAvailablePages - LockPagesCount) < 100) { dprintf("\n\t********** Running out of physical memory **********\n\n"); } dprintf("\tLocked IO Pages: %8I64ld (%8I64ld Kb)\n",LockPagesCount,_KB*LockPagesCount); dprintf("\tFree System PTEs: %8I64ld (%8I64ld Kb)\n",FreeSystemPtes,_KB*FreeSystemPtes); dprintf("\tFree NP PTEs: %8I64ld (%8I64ld Kb)\n",FreeNonPagedPtes,_KB*FreeNonPagedPtes); dprintf("\tFree Special NP: %8I64ld (%8I64ld Kb)\n", (SpecialPagesNonPagedMaximum - SpecialPagesNonPaged), _KB*(SpecialPagesNonPagedMaximum - SpecialPagesNonPaged)); dprintf("\tModified Pages: %8I64ld (%8I64ld Kb)\n",ModifiedPages,ModifiedPages*_KB); if ((AvailablePages < 50) && (ModifiedPages > 200)) { dprintf("\t********** High Number Of Modified Pages ********\n"); } if (ModifiedNoWrite > ((MemorySize / 100) * 3)) { dprintf("\t********** High Number Of Modified No Write Pages ********\n"); dprintf("\tModified No Write Pages: %I64ld (%8I64ld Kb)\n", ModifiedNoWrite,_KB*ModifiedNoWrite); } // // Dump all the nonpaged pools. // PoolLoc = GetNtDebuggerData(NonPagedPoolDescriptor ); Desc_TotalPages = 0; TotalBigPages=0; if ( !PoolLoc || GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages", Desc_TotalPages)) { dprintf("%08p: Unable to get pool descriptor\n",PoolLoc); return E_INVALIDARG; } Desc_size = GetTypeSize("nt!_POOL_DESCRIPTOR"); if (ExpNumberOfNonPagedPools = GetExpression("nt!ExpNumberOfNonPagedPools")) { NumberOfNonPagedPools = GetUlongFromAddress (ExpNumberOfNonPagedPools); } else { NumberOfNonPagedPools = 0; } if (NumberOfNonPagedPools > 1) { TotalPages = 0; PoolLocBase = GetExpression ("nt!ExpNonPagedPoolDescriptor"); if (PoolLocBase != 0) { for (Index = 0; Index < NumberOfNonPagedPools; Index += 1) { if (!ReadPointer(PoolLocBase, &PoolLoc)) { dprintf("%08p: Unable to get nonpaged pool info\n",PoolLocBase); break; } if (GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages", Desc_TotalPages)) { dprintf("%08p: Unable to get pool descriptor\n",PoolLoc); return E_INVALIDARG; } GetFieldValue(PoolLoc,"_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages); dprintf("\tNonPagedPool %1ld Used: %5ld (%8ld Kb)\n", Index, Desc_TotalPages + TotalBigPages, _KB*(Desc_TotalPages + TotalBigPages)); TotalPages += Desc_TotalPages + TotalBigPages; PoolLocBase += PtrSize; } } } GetFieldValue(PoolLoc,"nt!_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages); if (NumberOfNonPagedPools > 1) { dprintf("\tNonPagedPool Usage: %5ld (%8ld Kb)\n", TotalPages,_KB*TotalPages); } else { dprintf("\tNonPagedPool Usage: %5ld (%8ld Kb)\n", Desc_TotalPages + TotalBigPages, _KB*(Desc_TotalPages + TotalBigPages)); } dprintf("\tNonPagedPool Max: %5I64ld (%8I64ld Kb)\n", NonPagedPoolBytesMax/PageSize,_KB*(NonPagedPoolBytesMax/PageSize)); if ((Desc_TotalPages + TotalBigPages) > 4 * ((NonPagedPoolBytesMax / PageSize) / 5)) { dprintf("\t********** Excessive NonPaged Pool Usage *****\n"); } // // Dump all the paged pools. // NumberOfPagedPools = GetNtDebuggerDataValue(ExpNumberOfPagedPools); TotalPages = 0; PoolLocBase = GetExpression ("nt!ExpPagedPoolDescriptor"); if ((PoolLocBase != 0) && (NumberOfPagedPools != 0)) { for (Index = 0; (Index < (NumberOfPagedPools + 1)) ; Index += 1) { if (Index && (BuildNo <= 2464)) { PoolLoc += Desc_size; } else { if (!ReadPointer(PoolLocBase, &PoolLoc)) { dprintf("%08p: Unable to get paged pool info\n",PoolLocBase); break; } } if (GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages", Desc_TotalPages)) { dprintf("%08p: Unable to get pool descriptor, PagedPool usage may be wrong\n",PoolLoc); break; } GetFieldValue(PoolLoc,"nt!_POOL_DESCRIPTOR","TotalBigPages",TotalBigPages); dprintf("\tPagedPool %1ld Usage: %5ld (%8ld Kb)\n", Index, Desc_TotalPages + TotalBigPages, _KB*(Desc_TotalPages + TotalBigPages)); TotalPages += Desc_TotalPages + TotalBigPages; PoolLocBase += PtrSize; } } if (PagedPoolBytes > 95 * (PagedPoolBytesMax/ 100)) { dprintf("\t********** Excessive Paged Pool Usage *****\n"); } dprintf("\tPagedPool Usage: %5ld (%8ld Kb)\n", TotalPages,_KB*TotalPages); dprintf("\tPagedPool Maximum: %5I64ld (%8I64ld Kb)\n", PagedPoolBytesMax/PageSize,_KB*(PagedPoolBytesMax/PageSize)); dprintf("\tShared Commit: %8I64ld (%8I64ld Kb)\n",SharedCommit,_KB*SharedCommit ); dprintf("\tSpecial Pool: %8I64ld (%8I64ld Kb)\n",SpecialPoolPages,_KB*SpecialPoolPages ); dprintf("\tShared Process: %8I64ld (%8I64ld Kb)\n",ProcessCommit,_KB*ProcessCommit ); dprintf("\tPagedPool Commit: %8I64ld (%8I64ld Kb)\n",PagedPoolCommit,_KB*PagedPoolCommit); dprintf("\tDriver Commit: %8I64ld (%8I64ld Kb)\n",DriverCommit, _KB*DriverCommit ); dprintf("\tCommitted pages: %8I64ld (%8I64ld Kb)\n",CommitTotal, _KB*CommitTotal ); dprintf("\tCommit limit: %8I64ld (%8I64ld Kb)\n",CommitLimit, _KB*CommitLimit ); if ((CommitTotal + 100) > CommitLimit) { dprintf("\n\t********** Number of committed pages is near limit ********\n"); } if (BuildNo < 2257) { if (ExtendedCommit != 0) { dprintf("\n\t********** Commit has been extended with VM popup ********\n"); dprintf("\tExtended by: %8ld (%8ld Kb)\n", ExtendedCommit,_KB*ExtendedCommit); } if (PageFileFullExtendCount) { if (PageFileFullExtendCount == 1) { dprintf("\n\t****** ALL PAGING FILE BECAME FULL ONCE - COMMITMENT ADJUSTED ****\n", PageFileFullExtendCount); } else { dprintf("\n\t****** ALL PAGING FILE BECAME FULL (%u times) - COMMITMENT ADJUSTED ****\n", PageFileFullExtendCount); } dprintf("\tCurrent adjust: %8ld (%8ld Kb)\n", PageFileFullExtendPages, _KB*PageFileFullExtendPages); } } dprintf("\n"); if ((Flags & 0x1) == 0) { ProcessCommitUsage = GetProcessCommit( &TotalProcessCommit, &NumberOfProcesses ); if (ProcessCommitUsage == NULL) { dprintf("\nProcessCommitUsage could not be calculated\n"); } else { if (TotalProcessCommit != 0) { dprintf("\tTotal Private: %8I64ld (%8I64ld Kb)\n", TotalProcessCommit,_KB*TotalProcessCommit); } for (i=0; i NumberOfPfnToRead ? NumberOfPfnToRead : HighPage - PageCount + 1; ReadCount *= PfnSize; Pfn = (PfnStart + PageCount * PfnSize); PfnArrayPointer = (PUCHAR)(PfnArray + (ULONG) PageCount * PfnSize); // // KD caches the Pfns // if ((!ReadMemory(Pfn, PfnArrayPointer, (ULONG) ReadCount, &result)) || (result < (ULONG) ReadCount)) { dprintf("unable to get PFN table block - " "address %p - count %I64u - page %I64lu\n", Pfn, ReadCount, PageCount); goto alldone; } for (i = PageCount; (i < PageCount + NumberOfPfnToRead) && (i < HighPage); i += 1, Pfn = (Pfn + PfnSize)) { ULONG u3_e2_ReferenceCount=0; ULONG64 u1_Flink=0, u2_Blink=0, PteAddress=0, OriginalPte=0, PteFrame=0; if (RandomAccessRequired == TRUE) { if ((i % 256 ) == 0) { dprintf("."); // every 256 pages, print a dot } } else { GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", u1_Flink); GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", u2_Blink); GetFieldValue(Pfn, "nt!_MMPFN", "PteAddress",PteAddress); GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte",OriginalPte); GetFieldValue(Pfn, "nt!_MMPFN", "u3.e2.ReferenceCount", u3_e2_ReferenceCount); GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1); if (GetFieldValue(Pfn, "nt!_MMPFN", "u4.PteFrame", PteFrame) == FIELDS_DID_NOT_MATCH) { GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1.InPageError", InPageError); GetFieldValue(Pfn, "nt!_MMPFN", "PteFrame", PteFrame); } else { GetFieldValue(Pfn, "nt!_MMPFN", "u4.InPageError", InPageError); } if (u3_e1.PrototypePte == 0) { VirtualAddress = DbgGetVirtualAddressMappedByPte(PteAddress); } else { VirtualAddress = 0; } dprintf("%5I64lx %8p %8p%6x %8p %8p ", i, u1_Flink, u2_Blink, u3_e2_ReferenceCount, PteAddress, VirtualAddress); dprintf("%8p ", OriginalPte); dprintf("%6I64lx ", PteFrame); dprintf("%s %c%c%c%c%c%c\n", PageLocationList[u3_e1.PageLocation], u3_e1.Modified ? 'M':' ', u3_e1.PrototypePte ? 'P':' ', u3_e1.ReadInProgress ? 'R':' ', u3_e1.WriteInProgress ? 'W':' ', InPageError ? 'E':' ', u3_e1.ParityError ? 'X':' ' ); } if (CheckControlC()) { goto alldone; } } } if (RandomAccessRequired == TRUE) { dprintf("\n"); } else { goto alldone; } } dprintf("\n Page Flink Blk/Shr Ref V PTE Address SavedPTE Frame State\n"); Pfn = (PfnStart + Address * PfnSize); if (GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1)) { dprintf("unable to get PFN element\n"); goto alldone; } MatchLocation = u3_e1.PageLocation; do { ULONG u3_e2_ReferenceCount=0; ULONG64 u1_Flink=0, u2_Blink=0, PteAddress=0, OriginalPte=0, PteFrame=0; if (CheckControlC()) { goto alldone; } Pfn = (PfnStart + Address * PfnSize); sz = sizeof (u3_e1); GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1", u3_e1); if (u3_e1.PrototypePte == 0) { VirtualAddress = DbgGetVirtualAddressMappedByPte ( PteAddress); } else { VirtualAddress = 0; } if (u3_e1.PageLocation == MatchLocation) { GetFieldValue(Pfn, "nt!_MMPFN", "u1.Flink", u1_Flink); GetFieldValue(Pfn, "nt!_MMPFN", "u2.Blink", u2_Blink); GetFieldValue(Pfn, "nt!_MMPFN", "PteAddress", PteAddress); GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte",OriginalPte); GetFieldValue(Pfn, "nt!_MMPFN", "u3.e2.ReferenceCount", u3_e2_ReferenceCount); if(GetFieldValue(Pfn, "nt!_MMPFN", "u4.PteFrame", PteFrame) == FIELDS_DID_NOT_MATCH) { GetFieldValue(Pfn, "nt!_MMPFN", "u3.e1.InPageError", InPageError); GetFieldValue(Pfn, "nt!_MMPFN", "PteFrame", PteFrame); } else { GetFieldValue(Pfn, "nt!_MMPFN", "u4.InPageError", InPageError); } dprintf("%5I64lx %8p %8p%6x %8p %8p ", Address, u1_Flink, u2_Blink, u3_e2_ReferenceCount, PteAddress, VirtualAddress); dprintf("%8p ", OriginalPte); dprintf("%6I64lx ", PteFrame); dprintf("%s %c%c%c%c%c%c\n", PageLocationList[u3_e1.PageLocation], u3_e1.Modified ? 'M':' ', u3_e1.PrototypePte ? 'P':' ', u3_e1.ReadInProgress ? 'R':' ', u3_e1.WriteInProgress ? 'W':' ', InPageError ? 'E':' ', u3_e1.ParityError ? 'X':' ' ); } if (MatchLocation > 5) { Address += 1; } else { ULONG64 OriginalPte_u_Long=0; sz = sizeof (OriginalPte_u_Long); if (Flags == 7) { ULONG64 P; // // Search the whole database for an OriginalPte field that // points to this PFN - we must do this because this chain // is singly (not doubly) linked. // foundlink = FALSE; P = PfnStart; for (i = 0; i <= HighPage; i += 1, P += PfnSize) { GetFieldValue(P, "nt!_MMPFN", "OriginalPte.u.Long", OriginalPte_u_Long); if (OriginalPte_u_Long == Address) { Address = i; foundlink = TRUE; break; } } if (foundlink == FALSE) { dprintf("No OriginalPte chain found for %lx\n", Address); break; } } else if (Flags == 5) { GetFieldValue(Pfn, "nt!_MMPFN", "OriginalPte.u.Long", OriginalPte_u_Long); Address = OriginalPte_u_Long; } else if (Flags == 3) { Address = u2_Blink; } else { Address = u1_Flink; } } if (CheckControlC()) { goto alldone; } } while (Address < HighPage); alldone: if (PfnArray) { LocalFree((void *)PfnArray); } } VOID PrintPfn64 ( IN ULONG64 PfnAddress ) { MMPFNENTRY u3_e1; ULONG64 PfnDb, PfnStart; ULONG PfnSize; ULONG CacheAttribute; CHAR InPageError, VerifierAllocation; if ((PfnSize = GetTypeSize("nt!_MMPFN")) == 0) { dprintf("Type _MMPFN not found.\n"); return; } PfnDb = GetNtDebuggerData(MmPfnDatabase); if (!ReadPointer(PfnDb, &PfnStart)) { dprintf("%08P: Unable to get PFN database start\n",PfnDb); return; } if (!IsPtr64()) { PfnAddress = (ULONG64) (LONG64) (LONG) PfnAddress; } dprintf(" PFN %08P at address %08P\n", (PfnAddress - PfnStart) / PfnSize, PfnAddress); InitTypeRead(PfnAddress, nt!_MMPFN); dprintf(" flink %08P", ReadField(u1.Flink)); dprintf(" blink / share count %08P", ReadField(u2.Blink)); dprintf(" pteaddress %08P\n", ReadField(PteAddress)); GetFieldValue(PfnAddress, "nt!_MMPFN", "u3.e1", u3_e1); switch (TargetMachine) { case IMAGE_FILE_MACHINE_IA64: case IMAGE_FILE_MACHINE_AMD64: dprintf(" reference count %04hX used entry count %04hX %s color %01hX\n", (ULONG) ReadField(u3.e2.ReferenceCount), (ULONG) ReadField(UsedPageTableEntries), PageAttribute[u3_e1.CacheAttribute], u3_e1.PageColor); break; default: dprintf(" reference count %04hX %s color %01hX\n", (ULONG) ReadField(u3.e2.ReferenceCount), PageAttribute[u3_e1.CacheAttribute], u3_e1.PageColor); break; } dprintf(" restore pte %08I64X ", ReadField(OriginalPte)); if (BuildNo < 2440) { dprintf("containing page %06P ", ReadField(PteFrame)); InPageError = (CHAR) ReadField(u3.e1.InPageError); VerifierAllocation = (CHAR) ReadField(u3.e1.VerifierAllocation); } else { dprintf("containing page %06P ", ReadField(u4.PteFrame)); InPageError = (CHAR) ReadField(u4.InPageError); VerifierAllocation = (CHAR) ReadField(u4.VerifierAllocation); } dprintf("%s %c%c%c%c%c%c\n", PageLocationList[u3_e1.PageLocation], u3_e1.Modified ? 'M':' ', u3_e1.PrototypePte ? 'P':' ', u3_e1.ReadInProgress ? 'R':' ', u3_e1.WriteInProgress ? 'W':' ', InPageError ? 'E':' ', u3_e1.ParityError ? 'X':' ', u3_e1.RemovalRequested ? 'Y':' ', VerifierAllocation ? 'V':' ' ); dprintf(" %s %s %s %s %s %s\n", u3_e1.Modified ? "Modified":" ", u3_e1.PrototypePte ? "Shared":" ", u3_e1.ReadInProgress ? "ReadInProgress":" ", u3_e1.WriteInProgress ? "WriteInProgress":" ", InPageError ? "InPageError":" ", u3_e1.ParityError ? "ParityError":" ", u3_e1.RemovalRequested ? "RemovalRequested":" ", VerifierAllocation ? "VerifierAllocation":" "); return; } VOID MemoryUsage ( IN ULONG64 PfnStart, IN ULONG64 LowPage, IN ULONG64 HighPage, IN ULONG IgnoreInvalidFrames ) /*++ Routine Description: This routine (debugging only) dumps the current memory usage by walking the PFN database. Arguments: None. Return Value: None. --*/ { ULONG PfnSize; ULONG64 LastPfn; ULONG64 Pfn1; ULONG64 Pfn2; ULONG64 Subsection1; UNICODE_STRING NameString; PPFN_INFO Info; PPFN_INFO Info1; PPFN_INFO InfoStart; PPFN_INFO InfoEnd; ULONG InfoSize; PFN_INFO ProcessPfns; PFN_INFO PagedPoolBlock; PPFN_INFO LastProcessInfo = &ProcessPfns; ULONG64 Master; ULONG64 ControlArea1; BOOLEAN Found; ULONG result; ULONG i; ULONG64 PagedPoolStart; ULONG64 VirtualAddress; ULONG64 MmNonPagedPoolEnd; ULONG64 PteFrame; ULONG OriginalPteOffset; ULONG PercentComplete=0; PKERN_MAP pKernelMap; // Get the offset of OriginalPte in MMPFN if (GetFieldOffset("nt!_MMPFN", "OriginalPte", &OriginalPteOffset)) { dprintf("Cannot find _MMPFN type"); return ; } ProcessPfns.Next = NULL; MmNonPagedPoolEnd = GetNtDebuggerDataPtrValue(MmNonPagedPoolEnd); NameString.MaximumLength = sizeof(WCHAR) * 1000; NameString.Buffer = calloc(1, NameString.MaximumLength); if (!NameString.Buffer) { return; } PagedPoolStart = GetNtDebuggerDataPtrValue(MmPagedPoolStart); pKernelMap = calloc(1, sizeof(*pKernelMap)); if (!pKernelMap) { free(NameString.Buffer); return; } dprintf (" Building kernel map\n"); if (BuildKernelMap (pKernelMap) == FALSE) { free(pKernelMap); free(NameString.Buffer); return; } dprintf (" Finished building kernel map\n"); RtlZeroMemory (&PagedPoolBlock, sizeof (PFN_INFO)); PfnSize = GetTypeSize("nt!_MMPFN"); LastPfn = (PfnStart + HighPage * PfnSize); if (MmSubsectionBase == 0) { MmSubsectionBase = GetNtDebuggerDataValue(MmSubsectionBase); } // // Allocate a chunk of memory to hold PFN information. This is resized // if it is later determined that the current size is not large enough. // InfoSize = USAGE_ALLOC_SIZE; restart: InfoStart = VirtualAlloc (NULL, InfoSize, MEM_COMMIT, PAGE_READWRITE); if (InfoStart == NULL) { dprintf ("heap allocation for %d bytes failed\n", InfoSize); free(pKernelMap); free(NameString.Buffer); return; } InfoEnd = InfoStart; Pfn1 = (PfnStart + LowPage * PfnSize); while (Pfn1 < LastPfn) { ULONG PageLocation=0, PrototypePte=0, ReferenceCount=0; ULONG Comp; ULONG64 ShareCount=0, PteFrame1=0, PteAddress; Comp = ((ULONG) (Pfn1 - (PfnStart + LowPage * PfnSize)))*100 / ((ULONG) (LastPfn -(PfnStart + LowPage * PfnSize))); if (Comp > PercentComplete) { PercentComplete = Comp; dprintf("Scanning PFN database - (%02d%% complete) \r", PercentComplete); } if (CheckControlC()) { VirtualFree (InfoStart,0,MEM_RELEASE); free(pKernelMap); free(NameString.Buffer); return; } GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PageLocation", PageLocation); if ((PageLocation != FreePageList) && (PageLocation != ZeroedPageList) && (PageLocation != BadPageList)) { GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e1.PrototypePte", PrototypePte); GetFieldValue(Pfn1, "nt!_MMPFN", "u3.e2.ReferenceCount", ReferenceCount); GetFieldValue(Pfn1, "nt!_MMPFN", "u2.ShareCount", ShareCount); GetFieldValue(Pfn1, "nt!_MMPFN", "PteAddress", PteAddress); if (GetFieldValue(Pfn1, "nt!_MMPFN", "u4.PteFrame", PteFrame1) == FIELDS_DID_NOT_MATCH) { GetFieldValue(Pfn1, "nt!_MMPFN", "PteFrame", PteFrame1); } Subsection1 = 0; if (PrototypePte) { Subsection1 = DbgGetSubsectionAddress (Pfn1 + OriginalPteOffset); } if ((Subsection1) && (Subsection1 < 0xffffffffffbff000UI64)) { Master = Subsection1; } else { PteFrame = PteFrame1; if (IgnoreInvalidFrames) { Master = PteFrame; } else { // dprintf("Pteaddr %p, PagedPoolStart %I64x ", PteAddress, PagedPoolStart); if (PteAddress > PagedPoolStart) { Master = PteFrame; } else { Master=0; Pfn2 = PfnStart + PteFrame*PfnSize; if (GetFieldValue(Pfn2, "nt!_MMPFN", "PteFrame", Master) == FIELDS_DID_NOT_MATCH) { GetFieldValue(Pfn2, "nt!_MMPFN", "u4.PteFrame", Master); } // Master = MI_PFN_PTE FRAME(Pfn2); if ((Master == 0) || (Master > HighPage)) { dprintf("Invalid PTE frame\n"); // PrintPfn((PVOID)(((PCHAR)Pfn1-(PCHAR)PfnStart)/PfnSize),Pfn1); PrintPfn64(Pfn1); PrintPfn64(Pfn2); dprintf(" subsection address: %p\n",Subsection1); goto NextPfn; } } } } // // Tally any pages which are not protos and have a valid PTE // address field. // if ((PteAddress < PagedPoolStart) && (PteAddress >= DbgGetPteAddress(SystemRangeStart) )) { for (i=0; iCount; i++) { VirtualAddress = DbgGetVirtualAddressMappedByPte (PteAddress); if ((VirtualAddress >= pKernelMap->Item[i].StartVa) && (VirtualAddress < pKernelMap->Item[i].EndVa)) { if ((PageLocation == ModifiedPageList) || (PageLocation == ModifiedNoWritePageList)) { pKernelMap->Item[i].ModifiedCount += _KB; if (ReferenceCount > 0) { pKernelMap->Item[i].LockedCount += _KB; } } else if ((PageLocation == StandbyPageList) || (PageLocation == TransitionPage)) { pKernelMap->Item[i].StandbyCount += _KB; if (ReferenceCount > 0) { pKernelMap->Item[i].LockedCount += _KB; } } else { pKernelMap->Item[i].ValidCount += _KB; if (ShareCount > 1) { pKernelMap->Item[i].SharedCount += _KB; if (ReferenceCount > 1) { pKernelMap->Item[i].LockedCount += _KB; } } } goto NextPfn; } } } if (PteAddress >= 0xFFFFFFFFF0000000UI64) { // // This is paged pool, put it in the paged pool cell. // Info = &PagedPoolBlock; Found = TRUE; } else { // // See if there is already a master info block. // Info = InfoStart; Found = FALSE; while (Info < InfoEnd) { if (Info->Master == Master) { Found = TRUE; break; } Info += 1; } } if (!Found) { Info = InfoEnd; InfoEnd += 1; if ((PUCHAR)Info >= ((PUCHAR)InfoStart + InfoSize) - sizeof(PFN_INFO)) { // // Don't bother copying the old array - free it instead to // improve our chances of getting a bigger contiguous chunk. // VirtualFree (InfoStart,0,MEM_RELEASE); InfoSize += USAGE_ALLOC_SIZE; goto restart; } RtlZeroMemory (Info, sizeof (PFN_INFO)); Info->Master = Master; GetFieldValue(Pfn1, "nt!_MMPFN", "OriginalPte.u.Long", Info->OriginalPte); } // dprintf("Pfn1 %p, PageLoc %x, Master %I64x\n", Pfn1, PageLocation, Master); if ((PageLocation == ModifiedPageList) || (PageLocation == ModifiedNoWritePageList)) { Info->ModifiedCount += _KB; if (ReferenceCount > 0) { Info->LockedCount += _KB; } } else if ((PageLocation == StandbyPageList) || (PageLocation == TransitionPage)) { Info->StandbyCount += _KB; if (ReferenceCount > 0) { Info->LockedCount += _KB; } } else { Info->ValidCount += _KB; if (ShareCount > 1) { Info->SharedCount += _KB; if (ReferenceCount > 1) { Info->LockedCount += _KB; } } } if ((PteAddress >= DbgGetPdeAddress (0x0)) && (PteAddress <= DbgGetPdeAddress (0xFFFFFFFFFFFFFFFF))) { Info->PageTableCount += _KB; } } NextPfn: Pfn1 = (Pfn1 + PfnSize); } // // dump the results. // #if 0 dprintf("Physical Page Summary:\n"); dprintf(" - number of physical pages: %ld\n", MmNumberOfPhysicalPages); dprintf(" - Zeroed Pages %ld\n", MmZeroedPageListHead.Total); dprintf(" - Free Pages %ld\n", MmFreePageListHead.Total); dprintf(" - Standby Pages %ld\n", MmStandbyPageListHead.Total); dprintf(" - Modfified Pages %ld\n", MmModifiedPageListHead.Total); dprintf(" - Modfified NoWrite Pages %ld\n", MmModifiedNoWritePageListHead.Total); dprintf(" - Bad Pages %ld\n", MmBadPageListHead.Total); #endif //0 dprintf("\n\n Usage Summary (in Kb):\n"); Info = InfoStart; while (Info < InfoEnd) { if (CheckControlC()) { VirtualFree (InfoStart,0,MEM_RELEASE); free(pKernelMap); free(NameString.Buffer); return; } if (Info->Master > 0x200000) { // // Get the control area from the subsection. // if (GetFieldValue(Info->Master, "nt!_SUBSECTION", "ControlArea", ControlArea1)) { dprintf("unable to get subsection va %p %lx\n",Info->Master,Info->OriginalPte); } // ControlArea1 = Subsection.ControlArea; Info->Master = ControlArea1; // // Loop through the array so far for matching control areas // Info1 = InfoStart; while (Info1 < Info) { if (Info1->Master == ControlArea1) { // // Found a match, collapse these values. // Info1->ValidCount += Info->ValidCount; Info1->StandbyCount += Info->StandbyCount; Info1->ModifiedCount += Info->ModifiedCount; Info1->SharedCount += Info->SharedCount; Info1->LockedCount += Info->LockedCount; Info1->PageTableCount += Info->PageTableCount; Info->Master = 0; break; } Info1++; } } else { LastProcessInfo->Next = Info; LastProcessInfo = Info; } Info++; } Info = InfoStart; dprintf("Control Valid Standby Dirty Shared Locked PageTables name\n"); while (Info < InfoEnd) { ULONG64 FilePointer; if (CheckControlC()) { VirtualFree (InfoStart,0,MEM_RELEASE); free(pKernelMap); free(NameString.Buffer); return; } if (Info->Master > 0x200000) { // // Get the control area. // if (GetFieldValue(Info->Master, "nt!_CONTROL_AREA", "FilePointer", FilePointer)) { dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Bad Control Area\n", Info->Master, Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount ); } else if (FilePointer == 0) { dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Page File Section\n", Info->Master, Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount ); } else { ULONG64 NameBuffer; // // Get the file pointer. // if (GetFieldValue(FilePointer, "nt!_FILE_OBJECT", "FileName.Length", NameString.Length)) { dprintf("unable to get subsection %p\n",FilePointer); } if (NameString.Length != 0) { // // Get the name string. // if (NameString.Length > NameString.MaximumLength) { NameString.Length = NameString.MaximumLength-1; } GetFieldValue(FilePointer, "nt!_FILE_OBJECT", "FileName.Buffer", NameBuffer); if ((!ReadMemory(NameBuffer, NameString.Buffer, NameString.Length, &result)) || (result < NameString.Length)) { dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld Name Not Available\n", Info->Master, Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount ); } else { { WCHAR FileName[MAX_PATH]; WCHAR FullFileName[MAX_PATH]; WCHAR *FilePart; ZeroMemory(FileName,sizeof(FileName)); if (NameString.Length > sizeof(FileName)) { wcscpy(FileName, L"File name length too big - possibly corrupted"); } else { CopyMemory(FileName,NameString.Buffer,NameString.Length); } GetFullPathNameW( FileName, MAX_PATH, FullFileName, &FilePart ); dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld mapped_file( %ws )\n", Info->Master, Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount, FilePart); } } } else { dprintf("%8p %5ld %5ld %5ld %5ld %5ld %5ld No Name for File\n", Info->Master, Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount ); } } } Info += 1; } Info = &PagedPoolBlock; if ((Info->ValidCount != 0) || (Info->StandbyCount != 0) || (Info->ModifiedCount != 0)) { dprintf("00000000 %4ld %5ld %5ld %5ld %5ld %5ld PagedPool\n", Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->SharedCount, Info->LockedCount, Info->PageTableCount ); } // // dump the process information. // BuildDirbaseList(); Info = ProcessPfns.Next; while (Info != NULL) { if (Info->Master != 0) { PUCHAR ImageName; ImageName = DirbaseToImage(Info->Master); if ( ImageName ) { dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld process ( %s )\n", Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->PageTableCount, ImageName ); } else { dprintf("-------- %4ld %5ld %5ld ----- ----- %5ld pagefile section (%lx)\n", Info->ValidCount, Info->StandbyCount, Info->ModifiedCount, Info->PageTableCount, Info->Master ); } } Info = Info->Next; } if (!IgnoreInvalidFrames) { for (i=0;iCount ;i++) { dprintf("-------- %4ld %5ld %5ld ----- %5ld ----- driver ( %ws )\n", pKernelMap->Item[i].ValidCount, pKernelMap->Item[i].StandbyCount, pKernelMap->Item[i].ModifiedCount, pKernelMap->Item[i].LockedCount, pKernelMap->Item[i].Name ); } } VirtualFree (InfoStart,0,MEM_RELEASE); free(pKernelMap); free(NameString.Buffer); return; } NTSTATUS BuildDirbaseList ( VOID ) { ULONG64 Next; ULONG64 ProcessHead; ULONG64 Process; NTSTATUS status=0; ULONG ActiveProcessLinksOffset, DirectoryTableBaseOffset; FIELD_INFO offField[] = { {"ActiveProcessLinks", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL}, {"Pcb.DirectoryTableBase", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL} }; SYM_DUMP_PARAM TypeSym ={ sizeof (SYM_DUMP_PARAM), "_EPROCESS", DBG_DUMP_NO_PRINT, 0, NULL, NULL, NULL, 2, &offField[0] }; // Get the offset of ActiveProcessLinks in EPROCESS if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) { return FALSE; } ActiveProcessLinksOffset = (ULONG) offField[0].address; DirectoryTableBaseOffset = (ULONG) offField[1].address; MaxDirbase = 0; ProcessHead = GetNtDebuggerData(PsActiveProcessHead ); if (!ProcessHead) { return STATUS_OBJECT_NAME_NOT_FOUND; } if (GetFieldValue(ProcessHead, "nt!_LIST_ENTRY", "Flink", Next)) { return STATUS_OBJECT_NAME_NOT_FOUND; } //Next = List.Flink; if (Next == 0) { dprintf("PsActiveProcessHead is NULL!\n"); return STATUS_INVALID_PARAMETER; } while(Next != ProcessHead) { ULONG64 PageFrameNumber=0; Process = Next - ActiveProcessLinksOffset; if (GetFieldValue(Process, "nt!_EPROCESS", "ImageFileName", Names[MaxDirbase])) { dprintf("Unable to read _EPROCESS at %p\n",Process); MaxDirbase = 0; return status; } if ( (Names[ MaxDirbase ])[0] == '\0' ) { strcpy((PCHAR)&Names[MaxDirbase][0],(PCHAR)"SystemProcess"); } GetFieldValue(Process,"_EPROCESS","ImageFileName",Names[MaxDirbase]); GetFieldValue(Process + DirectoryTableBaseOffset, "nt!HARDWARE_PTE", "PageFrameNumber", PageFrameNumber); DirBases[MaxDirbase++] = PageFrameNumber; GetFieldValue(Process, "_EPROCESS", "ActiveProcessLinks.Flink", Next); if (CheckControlC()) { MaxDirbase = 0; return STATUS_INVALID_PARAMETER; } } return STATUS_INVALID_PARAMETER; } PUCHAR DirbaseToImage( IN ULONG64 DirBase ) { ULONG i; for(i=0;iItem[i].Name[0], BaseDllNameLength, &Result)) || (Result < BaseDllNameLength)) { dprintf("Unable to read name string at %08p - status %08lx\n", DataTable, Status); return FALSE; } KernelMap->Item[i].Name[BaseDllNameLength/2] = L'\0'; KernelMap->Item[i].StartVa = DllBase; KernelMap->Item[i].EndVa = KernelMap->Item[i].StartVa + (ULONG)SizeOfImage; i += 1; GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","InLoadOrderLinks.Flink", Next); } KernelMap->Item[i].StartVa = GetNtDebuggerDataPtrValue(MmPagedPoolStart); KernelMap->Item[i].EndVa = GetNtDebuggerDataPtrValue(MmPagedPoolEnd); wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"Paged Pool"); i+= 1; #if 0 KernelMap->Item[i].StartVa = DbgGetPteAddress (0xffffffff80000000UI64); KernelMap->Item[i].EndVa = DbgGetPteAddress (0xffffffffffffffffUI64); wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"System Page Tables"); i+= 1; KernelMap->Item[i].StartVa = DbgGetPdeAddress (0x80000000); KernelMap->Item[i].EndVa = DbgGetPdeAddress (0xffffffff); wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"System Page Tables"); i+= 1; #endif 0 // LWFIX: Both PTEs and nonpaged pool can be in multiple virtually discontiguous // areas. Fix this. KernelMap->Item[i].StartVa = DbgGetVirtualAddressMappedByPte ( GetNtDebuggerDataValue(MmSystemPtesStart)); KernelMap->Item[i].EndVa = DbgGetVirtualAddressMappedByPte ( GetNtDebuggerDataValue(MmSystemPtesEnd)) + 1; wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"Kernel Stacks"); i+= 1; KernelMap->Item[i].StartVa = GetNtDebuggerDataValue(MmNonPagedPoolStart); KernelMap->Item[i].EndVa = GetNtDebuggerDataValue(MmNonPagedPoolEnd); wcscpy (&KernelMap->Item[i].Name[0], (PUSHORT) &L"NonPaged Pool"); i+= 1; KernelMap->Count = i; return TRUE; } ULONG64 SpecialPoolStart; ULONG64 SpecialPoolEnd; #define VI_POOL_FREELIST_END ((ULONG64)-1) LOGICAL VerifierDumpPool ( IN ULONG64 Verifier ) { ULONG64 HashTableAddress; ULONG PoolTag; ULONG i; ULONG64 HashEntry; ULONG64 PoolHashSize; ULONG SizeofEntry; LONG64 FreeListNext; // // Display the current and peak pool usage by allocation & bytes. // #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.') InitTypeRead(Verifier, nt!_MI_VERIFIER_DRIVER_ENTRY); dprintf("\n"); dprintf("Current Pool Allocations %08I64lx %08I64lx\n", ReadField(CurrentPagedPoolAllocations), ReadField(CurrentNonPagedPoolAllocations)); dprintf("Current Pool Bytes %08I64lx %08I64lx\n", ReadField(PagedBytes), ReadField(NonPagedBytes)); dprintf("Peak Pool Allocations %08I64lx %08I64lx\n", ReadField(PeakPagedPoolAllocations), ReadField(PeakNonPagedPoolAllocations)); dprintf("Peak Pool Bytes %08I64lx %08I64lx\n", ReadField(PeakPagedBytes), ReadField(PeakNonPagedBytes)); // // If no current allocations then the dump is over. // if ((ReadField(CurrentPagedPoolAllocations) == 0) && (ReadField(CurrentNonPagedPoolAllocations) == 0)) { dprintf("\n"); return FALSE; } dprintf("\n"); PoolHashSize = ReadField(PoolHashSize); HashTableAddress = ReadField(PoolHash); dprintf("PoolAddress SizeInBytes Tag CallersAddress\n"); i = 0; HashEntry = HashTableAddress; SizeofEntry = GetTypeSize("nt!_VI_POOL_ENTRY"); for (i = 0; i < PoolHashSize; i += 1, HashEntry += SizeofEntry) { if (GetFieldValue(HashEntry, "nt!_VI_POOL_ENTRY", "FreeListNext", FreeListNext)) { dprintf("%08p: Unable to get verifier hash page\n", HashEntry); return FALSE; } // // Sign extend if necessary. // if (!IsPtr64()) { FreeListNext = (ULONG64)(LONG64)(LONG)FreeListNext; } // // Skip freelist entries. // if ((FreeListNext == VI_POOL_FREELIST_END) || ((FreeListNext & MINLONG64_PTR) == 0)) { continue; } InitTypeRead(HashEntry, nt!_VI_POOL_ENTRY); PoolTag = (ULONG) ReadField(InUse.Tag); dprintf("%p 0x%08p %c%c%c%c ", ReadField(InUse.VirtualAddress), ReadField(InUse.NumberOfBytes), (PP(PoolTag) & ~0x80), PP(PoolTag >> 8), PP(PoolTag >> 16), PP(PoolTag >> 24) ); dprintf("%p\n", ReadField(InUse.CallingAddress)); if (CheckControlC()) { return TRUE; } } #undef PP dprintf("\n"); return FALSE; } #if 0 typedef struct _COMMIT_INFO { LPSTR Name; ULONG Index; } COMMIT_INFO, *PCOMMIT_INFO; COMMIT_INFO CommitInfo[] = { "MM_DBG_COMMIT_NONPAGED_POOL_EXPANSION", 0, "MM_DBG_COMMIT_PAGED_POOL_PAGETABLE", 1, "MM_DBG_COMMIT_PAGED_POOL_PAGES", 2, "MM_DBG_COMMIT_SESSION_POOL_PAGE_TABLES", 3, "MM_DBG_COMMIT_ALLOCVM1", 4, "MM_DBG_COMMIT_ALLOCVM_SEGMENT", 5, "MM_DBG_COMMIT_IMAGE", 6, "MM_DBG_COMMIT_PAGEFILE_BACKED_SHMEM", 7, "MM_DBG_COMMIT_INDEPENDENT_PAGES", 8, "MM_DBG_COMMIT_CONTIGUOUS_PAGES", 9, "MM_DBG_COMMIT_MDL_PAGES", 0xA, "MM_DBG_COMMIT_NONCACHED_PAGES", 0xB, "MM_DBG_COMMIT_MAPVIEW_DATA", 0xC, "MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY", 0xD, "MM_DBG_COMMIT_EXTRA_SYSTEM_PTES", 0xE, "MM_DBG_COMMIT_DRIVER_PAGING_AT_INIT", 0xF, "MM_DBG_COMMIT_PAGEFILE_FULL", 0x10, "MM_DBG_COMMIT_PROCESS_CREATE", 0x11, "MM_DBG_COMMIT_KERNEL_STACK_CREATE", 0x12, "MM_DBG_COMMIT_SET_PROTECTION", 0x13, "MM_DBG_COMMIT_SESSION_CREATE", 0x14, "MM_DBG_COMMIT_SESSION_IMAGE_PAGES", 0x15, "MM_DBG_COMMIT_SESSION_PAGETABLE_PAGES", 0x16, "MM_DBG_COMMIT_SESSION_SHARED_IMAGE", 0x17, "MM_DBG_COMMIT_DRIVER_PAGES", 0x18, "MM_DBG_COMMIT_INSERT_VAD", 0x19, "MM_DBG_COMMIT_SESSION_WS_INIT", 0x1A, "MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES", 0x1B, "MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES", 0x1C, "MM_DBG_COMMIT_SPECIAL_POOL_PAGES", 0x1D, "MM_DBG_COMMIT_SMALL", 0x1F, "MM_DBG_COMMIT_EXTRA_WS_PAGES", 0x20, "MM_DBG_COMMIT_EXTRA_INITIAL_SESSION_WS_PAGES", 0x21, "MM_DBG_COMMIT_ALLOCVM_PROCESS", 0x22, "MM_DBG_COMMIT_INSERT_VAD_PT", 0x23, "MM_DBG_COMMIT_ALLOCVM_PROCESS2", 0x24, "MM_DBG_COMMIT_CHARGE_NORMAL", 0x25, "MM_DBG_COMMIT_CHARGE_CAUSE_POPUP", 0x26, "MM_DBG_COMMIT_CHARGE_CANT_EXPAND", 0x27, "MM_DBG_COMMIT_RETURN_NONPAGED_POOL_EXPANSION", 0x40, "MM_DBG_COMMIT_RETURN_PAGED_POOL_PAGES", 0x41, "MM_DBG_COMMIT_RETURN_SESSION_DATAPAGE", 0x42, "MM_DBG_COMMIT_RETURN_ALLOCVM_SEGMENT", 0x43, "MM_DBG_COMMIT_RETURN_ALLOCVM2", 0x44, "MM_DBG_COMMIT_RETURN_IMAGE_NO_LARGE_CA", 0x46, "MM_DBG_COMMIT_RETURN_PTE_RANGE", 0x47, "MM_DBG_COMMIT_RETURN_NTFREEVM1", 0x48, "MM_DBG_COMMIT_RETURN_NTFREEVM2", 0x49, "MM_DBG_COMMIT_RETURN_INDEPENDENT_PAGES", 0x4A, "MM_DBG_COMMIT_RETURN_AWE_EXCESS", 0x4B, "MM_DBG_COMMIT_RETURN_MDL_PAGES", 0x4C, "MM_DBG_COMMIT_RETURN_NONCACHED_PAGES", 0x4D, "MM_DBG_COMMIT_RETURN_SESSION_CREATE_FAILURE", 0x4E, "MM_DBG_COMMIT_RETURN_PAGETABLES", 0x4F, "MM_DBG_COMMIT_RETURN_PROTECTION", 0x50, "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE1", 0x51, "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE2", 0x52, "MM_DBG_COMMIT_RETURN_PAGEFILE_FULL", 0x53, "MM_DBG_COMMIT_RETURN_SESSION_DEREFERENCE", 0x54, "MM_DBG_COMMIT_RETURN_VAD", 0x55, "MM_DBG_COMMIT_RETURN_PROCESS_CREATE_FAILURE1", 0x56, "MM_DBG_COMMIT_RETURN_PROCESS_DELETE", 0x57, "MM_DBG_COMMIT_RETURN_PROCESS_CLEAN_PAGETABLES", 0x58, "MM_DBG_COMMIT_RETURN_KERNEL_STACK_DELETE", 0x59, "MM_DBG_COMMIT_RETURN_SESSION_DRIVER_LOAD_FAILURE1",0x5A, "MM_DBG_COMMIT_RETURN_DRIVER_INIT_CODE", 0x5B, "MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD", 0x5C, "MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD1", 0x5D, "MM_DBG_COMMIT_RETURN_NORMAL", 0x5E, "MM_DBG_COMMIT_RETURN_PF_FULL_EXTEND", 0x5F, "MM_DBG_COMMIT_RETURN_EXTENDED", 0x60, "MM_DBG_COMMIT_RETURN_SEGMENT_DELETE3", 0x61, }; VOID DumpCommitTracker () { ULONG64 MmTrackCommit; ULONG64 PfnEntry; ULONG64 displacement; ULONG64 AcquiredAddress; ULONG64 ReleasedAddress; CHAR SymbolBuffer[80]; PCHAR SymPointer; ULONG EntrySize; ULONG result; ULONG64 ReadCount; ULONG64 i; ULONG64 j; PSIZE_T LocalData; PCHAR local; ULONG64 NumberOfCommitEntries; MmTrackCommit = GetExpression ("nt!MmTrackCommit"); if (MmTrackCommit == 0) { dprintf("%08p: Unable to get commit track data.\n", MmTrackCommit); return; } PfnEntry = MmTrackCommit; #if 0 NumberOfCommitEntries = GetUlongValue ("MiMaxPfnTimings"); EntrySize = GetTypeSize("SIZE_T"); #else NumberOfCommitEntries = 128; EntrySize = 4; #endif ReadCount = NumberOfCommitEntries * EntrySize; dprintf("Scanning %I64u %I64u commit points\n", NumberOfCommitEntries, ReadCount); LocalData = LocalAlloc(LPTR, (ULONG) (NumberOfCommitEntries * EntrySize)); if (!LocalData) { dprintf("unable to get allocate %ld bytes of memory\n", (ULONG)(NumberOfCommitEntries * EntrySize)); return; } if ((!ReadMemory(MmTrackCommit, LocalData, (ULONG) ReadCount, &result)) || (result < (ULONG) ReadCount)) { dprintf("unable to get track commit table - " "address %p - count %I64u\n", LocalData, ReadCount); } else { dprintf("\n%-50s %s\n", "Instance", "HexCount"); for (i = 0; i < NumberOfCommitEntries; i += 1) { if (LocalData[i] != 0) { for (j = 0; j < sizeof(CommitInfo) / sizeof (COMMIT_INFO); j += 1) { if (CommitInfo[j].Index == i) { dprintf ("%-50s %8x\n", CommitInfo[j].Name, LocalData[i]); break; } } } } } if (LocalData) { LocalFree((void *)LocalData); } return; } #endif VOID DumpFaultInjectionTraceLog ( PCSTR Args ); VOID DumpTrackIrqlLog ( PCSTR args ); DECLARE_API( verifier ) /*++ Routine Description: Displays the current Driver Verifier data. Arguments: arg - Supplies 7 for full listing Return Value: None. --*/ { ULONG result; ULONG Flags; ULONG VerifierFlags; ULONG64 VerifierDataPointer; ULONG64 SuspectPointer; ULONG64 NextEntry; ULONG64 VerifierDriverEntry; PUCHAR tempbuffer; UNICODE_STRING unicodeString; LOGICAL Interrupted; CHAR Buf[256]; PCHAR ImageFileName; ANSI_STRING AnsiString; UNICODE_STRING InputDriverName; NTSTATUS st; ULONG Level; PCHAR state; ULONG64 tmp; UNREFERENCED_PARAMETER (Client); // // Display option usage. // if (strstr (args, "?") != NULL) { dprintf ("!verifier \n"); dprintf (" \n"); dprintf (" Dump verifier summary information. \n"); dprintf (" \n"); dprintf ("!verifier [FLAGS [IMAGE]] \n"); dprintf (" \n"); dprintf (" 0x01 : Dump verified drivers pool statistics \n"); dprintf (" \n"); dprintf (" 0x02 : not used \n"); dprintf (" \n"); dprintf (" 0x04 [N] : Dump N traces from fault injection trace log. \n"); dprintf (" \n"); dprintf (" 0x08 [N] : Dump N traces from track IRQL trace log\n"); dprintf (" \n"); dprintf ("To display everything use: \n"); dprintf (" \n"); dprintf (" !verifier 0xf \n"); dprintf (" \n"); return S_OK; } // // Read the Flags parameter. // Flags = 0; Flags = (ULONG) GetExpression (args); // // Display fault injection stacks. // if ((Flags == 0x04)) { DumpFaultInjectionTraceLog (args); return S_OK; } // // Display track irql stacks. // if ((Flags == 0x08)) { DumpTrackIrqlLog (args); return S_OK; } // // Continue with normal processing: !verifier [FLAGS [NAME]] // Flags = 0; RtlZeroMemory(Buf, 256); if (GetExpressionEx(args, &tmp, &args)) { Flags = (ULONG) tmp; while (args && (*args == ' ')) { ++args; } strcpy(Buf, args); } if (Buf[0] != '\0') { ImageFileName = Buf; RtlInitAnsiString(&AnsiString, ImageFileName); st = RtlAnsiStringToUnicodeString(&InputDriverName, &AnsiString, TRUE); if (!NT_SUCCESS(st)) { dprintf("%08lx: Unable to initialize unicode string\n", st); return E_INVALIDARG; } } else { ImageFileName = NULL; } VerifierDataPointer = GetExpression ("nt!MmVerifierData"); if (GetFieldValue(VerifierDataPointer, "nt!_MM_DRIVER_VERIFIER_DATA", "Level", Level)) { dprintf("%08p: Unable to get verifier list.\n",VerifierDataPointer); return E_INVALIDARG; } dprintf("\nVerify Level %x ... enabled options are:", Level); if (Level & DRIVER_VERIFIER_SPECIAL_POOLING) { dprintf("\n\tspecial pool"); } if (Level & DRIVER_VERIFIER_FORCE_IRQL_CHECKING) { dprintf("\n\tspecial irql"); } if (Level & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES) { dprintf("\n\tinject random low-resource API failures"); } if (Level & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS) { dprintf("\n\tall pool allocations checked on unload"); } if (Level & DRIVER_VERIFIER_IO_CHECKING) { dprintf("\n\tIo subsystem checking enabled"); } if (Level & DRIVER_VERIFIER_DEADLOCK_DETECTION) { dprintf("\n\tDeadlock detection enabled"); } if (Level & DRIVER_VERIFIER_ENHANCED_IO_CHECKING) { dprintf("\n\tEnhanced Io checking enabled"); } if (Level & DRIVER_VERIFIER_DMA_VERIFIER) { dprintf("\n\tDMA checking enabled"); } if (InitTypeRead(VerifierDataPointer, nt!MM_DRIVER_VERIFIER_DATA)) { dprintf("Unable to read type nt!MM_DRIVER_VERIFIER_DATA @ %p\n", VerifierDataPointer); } dprintf("\n\nSummary of All Verifier Statistics\n\n"); dprintf("RaiseIrqls 0x%x\n", (ULONG) ReadField(RaiseIrqls)); dprintf("AcquireSpinLocks 0x%x\n", (ULONG) ReadField(AcquireSpinLocks)); dprintf("Synch Executions 0x%x\n", (ULONG) ReadField(SynchronizeExecutions)); dprintf("Trims 0x%x\n", (ULONG) ReadField(Trims)); dprintf("\n"); dprintf("Pool Allocations Attempted 0x%x\n", (ULONG) ReadField(AllocationsAttempted)); dprintf("Pool Allocations Succeeded 0x%x\n", (ULONG) ReadField(AllocationsSucceeded)); dprintf("Pool Allocations Succeeded SpecialPool 0x%x\n", (ULONG) ReadField(AllocationsSucceededSpecialPool)); dprintf("Pool Allocations With NO TAG 0x%x\n", (ULONG) ReadField(AllocationsWithNoTag)); dprintf("Pool Allocations Failed 0x%x\n", (ULONG) ReadField(AllocationsFailed)); dprintf("Resource Allocations Failed Deliberately 0x%x\n", (ULONG) ReadField(AllocationsFailedDeliberately) + (ULONG) ReadField(BurstAllocationsFailedDeliberately)); dprintf("\n"); dprintf("Current paged pool allocations 0x%x for %08P bytes\n", (ULONG) ReadField(CurrentPagedPoolAllocations), ReadField(PagedBytes)); dprintf("Peak paged pool allocations 0x%x for %08P bytes\n", (ULONG)ReadField(PeakPagedPoolAllocations), ReadField(PeakPagedBytes)); dprintf("Current nonpaged pool allocations 0x%x for %08P bytes\n", (ULONG) ReadField(CurrentNonPagedPoolAllocations), ReadField(NonPagedBytes)); dprintf("Peak nonpaged pool allocations 0x%x for %08P bytes\n", (ULONG)ReadField(PeakNonPagedPoolAllocations), ReadField(PeakNonPagedBytes)); dprintf("\n"); SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart"); SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd"); if (Flags & 0x1) { ULONG Off; SuspectPointer = GetExpression ("nt!MiSuspectDriverList"); GetFieldOffset("nt!_MI_VERIFIER_DRIVER_ENTRY", "Links", &Off); if (!ReadPointer(SuspectPointer,&NextEntry)) { dprintf("%08p: Unable to get verifier list %p\n",SuspectPointer); return E_INVALIDARG; } dprintf("Driver Verification List\n\n"); dprintf("Entry State NonPagedPool PagedPool Module\n\n"); while (NextEntry != SuspectPointer) { VerifierDriverEntry = NextEntry - Off; if (GetFieldValue( VerifierDriverEntry, "nt!_MI_VERIFIER_DRIVER_ENTRY", "Flags", VerifierFlags)) { dprintf("%08p: Unable to get verifier data\n", VerifierDriverEntry); return E_INVALIDARG; } InitTypeRead(VerifierDriverEntry, nt!_MI_VERIFIER_DRIVER_ENTRY); if ((VerifierFlags & VI_VERIFYING_DIRECTLY) == 0) { NextEntry = ReadField(Links.Flink); continue; } unicodeString.Length = (USHORT) ReadField(BaseName.Length); tempbuffer = LocalAlloc(LPTR, unicodeString.Length); unicodeString.Buffer = (PWSTR)tempbuffer; unicodeString.MaximumLength = unicodeString.Length; if (!ReadMemory (ReadField(BaseName.Buffer), tempbuffer, unicodeString.Length, &result)) { dprintf("%08p: Unable to get verifier driver name\n", ReadField(BaseName.Buffer)); } if (ImageFileName != NULL) { if (RtlEqualUnicodeString(&InputDriverName, &unicodeString, TRUE) == 0) { NextEntry = ReadField(Links.Flink); continue; } } if (ReadField(Loads) == 0 && ReadField(Unloads) == 0) { state = "Hasn't loaded"; } else if (ReadField(Loads) != ReadField(Unloads)) { if (ReadField(Unloads) != 0) { state = "Loaded&Unloaded"; } else { state = "Loaded"; } } else { state = "Unloaded"; } dprintf("%p %-16s %08p %08p %wZ\n", VerifierDriverEntry, state, ReadField(NonPagedBytes), ReadField(PagedBytes), &unicodeString); Interrupted = FALSE; NextEntry = ReadField(Links.Flink); if ((Flags & 0x2) && (Level & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)) { Interrupted = VerifierDumpPool (VerifierDriverEntry); } LocalFree(tempbuffer); if ((Interrupted == TRUE) || (ImageFileName != NULL) || (CheckControlC())) { break; } } } if ((Flags & 0x04)) { dprintf ("----------------------------------------------- \n"); dprintf ("Fault injection trace log \n"); dprintf ("----------------------------------------------- \n"); DumpFaultInjectionTraceLog (NULL); } if ((Flags & 0x08)) { dprintf ("----------------------------------------------- \n"); dprintf ("Track irql trace log \n"); dprintf ("----------------------------------------------- \n"); DumpTrackIrqlLog (NULL); } return S_OK; } DECLARE_API( fpsearch ) /*++ Routine Description: Free pool searcher. Arguments: arg - Supplies virtual address to match. Return Value: None. --*/ { ULONG i; ULONG BufferSize; ULONG RawCount; PULONG RawPointer; ULONG Flags; ULONG ActualRead; ULONG64 PageFrameNumber; ULONG64 PAddress; ULONG64 Address; ULONG result; ULONG64 PfnDb; ULONG64 Pfn; ULONG64 PfnStart; ULONG PfnSize; ULONG64 ChainedBp; ULONG64 ValidBp; ULONG64 LastBp; ULONG64 ReturnAddress; PCHAR Buffer; ULONG64 MmFreePageListHeadAddress; CHAR SymbolBuffer[80]; ULONG64 displacement; ULONG64 Total; ULONG StkOffset; ULONG PtrSize; ULONG PoolTag; ULONG StackBytes; ULONG64 StackPointer; ULONG64 ChainedBpVal; ULONG64 LastBpVal; ULONG64 Blink; PtrSize = IsPtr64() ? 8 : 4; PfnSize = GetTypeSize("nt!_MMPFN"); BufferSize = GetTypeSize("nt!_MI_FREED_SPECIAL_POOL"); if (BufferSize == 0) { dprintf("Type MI_FREED_SPECIAL_POOL not found.\n"); return E_INVALIDARG; } PfnDb = GetNtDebuggerData(MmPfnDatabase ); if (!PfnDb) { dprintf("unable to get PFN0 database address\n"); return E_INVALIDARG; } result = !ReadPointer(PfnDb,&PfnStart); if (result != 0) { dprintf("unable to get PFN database address %p %x\n", PfnDb, result); return E_INVALIDARG; } Address = 0; Flags = 0; if (!sscanf(args,"%I64lx %lx",&Address, &Flags)) { Address = 0; } // Do not use GetExpression here - the actual address to be searched is phy address // and it can be >32bit for 32bit targets // Address = GetExpression (args); if (Address == 0) { dprintf("Usage: fpsearch address\n"); return E_INVALIDARG; } MmFreePageListHeadAddress = GetExpression ("nt!MmFreePageListHead"); if (GetFieldValue(MmFreePageListHeadAddress, "nt!_MMPFNLIST", "Total", Total)) { dprintf("%08p: Unable to get MmFreePageLocationList\n",MmFreePageListHeadAddress); return E_INVALIDARG; } if (Total == 0) { dprintf("No pages on free list to search\n"); return E_INVALIDARG; } if (Address != (ULONG64)-1) { dprintf("Searching the free page list (%I64x entries) for VA %p\n\n", Total, Address); Address &= ~(ULONG64)(PageSize - 1); } else { dprintf("Searching the free page list (%x entries) for all freed special pool\n\n", Total); } GetFieldValue (MmFreePageListHeadAddress, "nt!_MMPFNLIST", "Blink", PageFrameNumber); GetFieldOffset("_MI_FREED_SPECIAL_POOL", "StackData", &StkOffset); Buffer = LocalAlloc(LPTR, BufferSize); if (Buffer == NULL) { dprintf("Could not allocate a buffer for the search\n"); return E_INVALIDARG; } while (PageFrameNumber != (ULONG64)-1) { PAddress = (ULONG64)PageFrameNumber * PageSize; ReadPhysical (PAddress, Buffer, BufferSize, &ActualRead); if (ActualRead != BufferSize) { dprintf("Physical memory read %I64X %x %x failed\n", PAddress, ActualRead, BufferSize); // break; } if (Flags & 0x1) { // // Print a preview of the raw buffer. // #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.') RawPointer = (PULONG)Buffer; RawCount = BufferSize / sizeof (ULONG); if (RawCount > 32) { RawCount = 32; } RawCount &= ~0x3; for (i = 0; i < RawCount; i += 4) { dprintf ("%I64X %08x %08x %08x %08x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", PageFrameNumber * PageSize, *RawPointer, *(RawPointer + 1), *(RawPointer + 2), *(RawPointer + 3), PP(*RawPointer), PP(*RawPointer >> 8), PP(*RawPointer >> 16), PP(*RawPointer >> 24), PP(*(RawPointer + 1)), PP(*(RawPointer + 1) >> 8), PP(*(RawPointer + 1) >> 16), PP(*(RawPointer + 1) >> 24), PP(*(RawPointer + 2)), PP(*(RawPointer + 2) >> 8), PP(*(RawPointer + 2) >> 16), PP(*(RawPointer + 2) >> 24), PP(*(RawPointer + 3)), PP(*(RawPointer + 3) >> 8), PP(*(RawPointer + 3) >> 16), PP(*(RawPointer + 3) >> 24)); RawPointer += 4; } dprintf ("\n"); } Pfn = (PfnStart + PageFrameNumber * PfnSize); if (GetFieldValue(Pfn,"nt!_MMPFN","u2.Blink", Blink)) { dprintf("%08p: unable to get PFN element %x\n", Pfn, PfnSize); break; } if ((ULONG)Blink == (ULONG)-1) { Blink = (ULONG64)-1; } #define MI_FREED_SPECIAL_POOL_SIGNATURE 0x98764321 InitTypeReadPhysical (PAddress, nt!MI_FREED_SPECIAL_POOL); if ((ULONG) ReadField(Signature) == MI_FREED_SPECIAL_POOL_SIGNATURE) { if ((Address == (ULONG64)-1) || (((ULONG)(ReadField(VirtualAddress)) & ~(ULONG)(PageSize - 1)) == (ULONG)Address)) { PoolTag = (ULONG) ReadField(OverlaidPoolHeader.PoolTag); dprintf("VA PFN Tag Size Pagable Thread Tick\n"); dprintf("%p %6p %c%c%c%c %6x %s %08p %x\n", ReadField(VirtualAddress), PageFrameNumber, #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.') PP(PoolTag), PP(PoolTag >> 8), PP(PoolTag >> 16), PP(PoolTag >> 24), #undef PP (ULONG) ReadField(NumberOfBytesRequested), ReadField(Pagable) ? "Yes" : "No ", ReadField(Thread), ReadField(TickCount)); dprintf("\tCALL STACK AT TIME OF DEALLOCATION\n"); // // Calculate the relative stack and print it here symbolically. // StackBytes = (ULONG) ReadField(StackBytes); StackPointer = ReadField(StackPointer); ValidBp = (StackPointer & ~(ULONG64)(PageSize - 1)); ChainedBp = (PAddress + StkOffset); LastBp = (ChainedBp + (ULONG) ReadField(StackBytes)); while (ChainedBp < LastBp) { // // Read directly from physical memory. // InitTypeReadPhysical(ChainedBp, nt!_LIST_ENTRY); ChainedBpVal = ReadField(Flink); InitTypeReadPhysical(LastBp, nt!_LIST_ENTRY); LastBpVal = ReadField(Flink); // // Find a valid frame register chain. // if ((((ChainedBpVal) & ~(ULONG64)(PageSize - 1)) == ValidBp) && (ChainedBpVal > StackPointer) && ((ChainedBpVal - (StackPointer)) <= StackBytes)) { ULONG64 ReturnAddressVal; // // Increment to the stacked return address. // ReturnAddress = ChainedBp + PtrSize; InitTypeReadPhysical(ReturnAddress, nt!_LIST_ENTRY); ReturnAddressVal = ReadField(Flink); SymbolBuffer[0] = '!'; GetSymbol((ReturnAddressVal), (PUCHAR)SymbolBuffer, &displacement); dprintf ("\t%s", SymbolBuffer); if (displacement) { dprintf( "+0x%x", displacement ); } dprintf( "\n" ); #ifdef SLOW_BUT_THOROUGH ChainedBp += PtrSize; #else if ((ReturnAddressVal & ~MAXLONG64_PTR) == 0) { break; } // // Subtract the stackpointer & add stackdata offset. // ChainedBp = (ChainedBpVal - StackPointer + StkOffset); // // Adjust for relative. // ChainedBp = (PAddress + ChainedBp); #endif } else { ChainedBp += PtrSize; } } dprintf("\n"); if (Address != (ULONG64)-1) { break; } } } if (CheckControlC()) { break; } PageFrameNumber = Blink; } LocalFree(Buffer); return S_OK; } USHORT GetPfnRefCount( IN ULONG64 PageFrameNumber ) { ULONG64 PfnDb; ULONG64 Pfn; ULONG64 PfnStart; ULONG PfnSize; ULONG ReferenceCount; PfnSize = GetTypeSize("nt!_MMPFN"); PfnDb = GetNtDebuggerData(MmPfnDatabase ); if (!PfnDb) { dprintf("unable to get PFN0 database address\n"); return 0; } if (!ReadPointer(PfnDb,&PfnStart)) { dprintf("unable to get PFN database address %p\n", PfnDb); return 0; } Pfn = (PfnStart + PageFrameNumber * PfnSize); if (GetFieldValue(Pfn,"nt!_MMPFN","u3.e2.ReferenceCount", ReferenceCount)) { dprintf("%08p: unable to get PFN element %x\n", Pfn, PfnSize); return 0; } return (USHORT) ReferenceCount; } ///////////////////////////////////////////////////////////////////// ////////////////////////////////////// Dump irql tracking log ///////////////////////////////////////////////////////////////////// VOID DumpTrackIrqlLog ( PCSTR args ) { ULONG64 TrackIrqlQueueAddress; ULONG64 TrackIrqlIndexAddress; ULONG64 TrackIrqlQueueLengthAddress; ULONG64 TrackIrqlQueue; ULONG TrackIrqlIndex; ULONG TrackIrqlQueueLength; ULONG I, Index; ULONG64 Address; ULONG TrackIrqlTypeSize; UCHAR SymbolName[256]; ULONG64 SymbolAddress; ULONG64 SymbolOffset; ULONG Result; ULONG ShowCount; ULONG Flags; // // Read how many traces we want to see. // ShowCount = 0; if (args) { ULONG64 tmp; if (GetExpressionEx(args, &tmp, &args)) { Flags = (ULONG) tmp; if (!sscanf (args, "%u", &ShowCount)) { ShowCount = 0; } } if (ShowCount == 0) { ShowCount = 4; } } else { ShowCount = 4; } // // Read track irql package data // TrackIrqlQueueAddress = GetExpression ("nt!ViTrackIrqlQueue"); TrackIrqlIndexAddress = GetExpression ("nt!ViTrackIrqlIndex"); TrackIrqlQueueLengthAddress = GetExpression ("nt!ViTrackIrqlQueueLength"); if (TrackIrqlQueueAddress == 0 || TrackIrqlIndexAddress == 0 || TrackIrqlIndexAddress == 0) { dprintf ("Incorrect symbols. \n"); return; } ReadPointer (TrackIrqlQueueAddress, &TrackIrqlQueue); if (TrackIrqlQueue == 0) { dprintf ("Irql tracking is not enabled. You need to enable driver verifier \n"); dprintf ("for at least one driver to activate irql tracking. \n"); return; } ReadMemory (TrackIrqlIndexAddress, &TrackIrqlIndex, sizeof(ULONG), &Result); if (Result != sizeof(ULONG)) { dprintf ("Trackirql: read error \n"); return; } ReadMemory (TrackIrqlQueueLengthAddress, &TrackIrqlQueueLength, sizeof(ULONG), &Result); if (Result != sizeof(ULONG)) { dprintf ("Trackirql: read error \n"); return; } TrackIrqlTypeSize = GetTypeSize("nt!_VI_TRACK_IRQL"); // // Dump information // dprintf ("\nSize of track irql queue is 0x%X \n", TrackIrqlQueueLength); for (I = 0, Index = TrackIrqlIndex; I < TrackIrqlQueueLength; I += 1) { if (I >= ShowCount) { break; } Index -= 1; Index &= (TrackIrqlQueueLength - 1); Address = TrackIrqlQueue + Index * TrackIrqlTypeSize; InitTypeRead (Address, nt!_VI_TRACK_IRQL); dprintf ("\n"); dprintf ("Thread: %I64X\n", ReadField (Thread)); dprintf ("Old irql: %I64X\n", ReadField (OldIrql)); dprintf ("New irql: %I64X\n", ReadField (NewIrql)); dprintf ("Processor: %I64X\n", ReadField (Processor)); dprintf ("Time stamp: %I64X\n", ReadField (TickCount)); dprintf ("\n"); SymbolAddress = ReadField(StackTrace[0]); if (SymbolAddress == 0) { continue; } GetSymbol(SymbolAddress, SymbolName, &SymbolOffset); dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset); SymbolAddress = ReadField(StackTrace[1]); if (SymbolAddress == 0) { continue; } GetSymbol(SymbolAddress, SymbolName, &SymbolOffset); dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset); SymbolAddress = ReadField(StackTrace[2]); if (SymbolAddress == 0) { continue; } GetSymbol(SymbolAddress, SymbolName, &SymbolOffset); dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset); SymbolAddress = ReadField(StackTrace[3]); if (SymbolAddress == 0) { continue; } GetSymbol(SymbolAddress, SymbolName, &SymbolOffset); dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset); SymbolAddress = ReadField(StackTrace[4]); if (SymbolAddress == 0) { continue; } GetSymbol(SymbolAddress, SymbolName, &SymbolOffset); dprintf (" %I64X %s+0x%I64x\n", SymbolAddress, SymbolName, SymbolOffset); if (CheckControlC()) { dprintf ("Interrupted \n"); break; } } } ///////////////////////////////////////////////////////////////////// ////////////////////////////////////// Dump fault injection trace log ///////////////////////////////////////////////////////////////////// ULONG64 ReadPvoid ( ULONG64 Address ) { ULONG64 RemoteValue = 0; ReadPointer( Address, &RemoteValue); return RemoteValue; } ULONG ReadUlong( ULONG64 Address ) { ULONG RemoteValue = 0; ReadMemory( Address, &RemoteValue, sizeof( ULONG ), NULL ); return RemoteValue; } VOID DumpFaultInjectionTrace ( ULONG64 Address ) { ULONG64 ReturnAddress; CHAR SymbolName[ 1024 ]; ULONG64 Displacement; ULONG I; ULONG PvoidSize; PvoidSize = IsPtr64() ? 8 : 4; for (I = 0; I < 8; I += 1) { ReturnAddress = ReadPvoid (Address + I * PvoidSize); if (ReturnAddress == 0) { break; } GetSymbol (ReturnAddress, SymbolName, &Displacement); dprintf (" %p %s+0x%p\n", ReturnAddress, SymbolName, Displacement); } } VOID DumpFaultInjectionTraceLog ( PCSTR Args ) { ULONG TracesToDisplay = 0; ULONG64 TraceAddress; ULONG64 Trace; ULONG64 IndexAddress; ULONG Index; ULONG64 LengthAddress; ULONG Length; ULONG I; ULONG PvoidSize; ULONG64 TraceBlockAddress; ULONG64 FirstReturnAddress; ULONG TracesFound = 0; BOOLEAN Interrupted = FALSE; ULONG Flags; if (Args) { ULONG64 tmp; if (GetExpressionEx(Args, &tmp, &Args)) { Flags = (ULONG) tmp; if (!sscanf (Args, "%u", &TracesToDisplay)) { TracesToDisplay = 0; } } if (TracesToDisplay == 0) { TracesToDisplay = 4; } } else { TracesToDisplay = 4; } PvoidSize = IsPtr64() ? 8 : 4; TraceAddress = (ULONG64) GetExpression ("nt!ViFaultTraces"); IndexAddress = (ULONG64) GetExpression ("nt!ViFaultTracesIndex"); LengthAddress = (ULONG64) GetExpression ("nt!ViFaultTracesLength"); Trace = ReadPvoid (TraceAddress); if (Trace == 0) { dprintf ("Driver fault injection is not enabled for this system. \n"); return; } Index = ReadUlong (IndexAddress); Length = ReadUlong (LengthAddress); for (I = 0; I < Length; I += 1) { Index -= 1; Index &= (Length - 1); TraceBlockAddress = Trace + Index * PvoidSize * 8; FirstReturnAddress = ReadPvoid (TraceBlockAddress); if (FirstReturnAddress != 0) { TracesFound += 1; dprintf ("\n"); DumpFaultInjectionTrace (TraceBlockAddress); if (TracesFound >= TracesToDisplay) { break; } } if (CheckControlC()) { Interrupted = TRUE; dprintf ("Interrupted \n"); break; } } if (Interrupted == FALSE && TracesFound == 0) { dprintf ("No fault injection traces found. \n"); } } PUCHAR MemoryDescriptorType[] = { "ExceptionBlock", "SystemBlock", "Free", "Bad", "LoadedProgram", "FirmwareTemporary", "FirmwarePermanent", "OsloaderHeap", "OsloaderStack", "SystemCode", "HalCode", "BootDriver", "ConsoleInDriver", "ConsoleOutDriver", "StartupDpcStack", "StartupKernelStack", "StartupPanicStack", "StartupPcrPage", "StartupPdrPage", "RegistryData", "MemoryData", "NlsData", "SpecialMemory", "BBTMemory", "LoaderReserve", "XIPRom", "HALCachedMemory" }; #define MAXIMUM_MEMORY_TYPE (sizeof(MemoryDescriptorType)/sizeof(UCHAR)) DECLARE_API( loadermemorylist ) /*++ Routine Description: Displays the memory allocation list. This is the list handed to the OS by the OSLOADER that describes physical memory. Displays the corresponding PDE and PTE. Arguments: list - points to the listheader Return Value: None. --*/ { ULONG64 ListHeaderAddress; ULONG64 EntryAddress; ULONG64 LengthInPages; ULONG64 TypeOfMemory; ULONG Count[MAXIMUM_MEMORY_TYPE]; ULONG i; UNREFERENCED_PARAMETER (Client); ListHeaderAddress = 0; ListHeaderAddress = GetExpression(args); if (ListHeaderAddress == 0) { dprintf("Usage: !loadermemorylist \n"); return E_INVALIDARG; } if (!ReadPointer(ListHeaderAddress, &EntryAddress)) { dprintf("Unable to read list header at %p\n", ListHeaderAddress); return E_INVALIDARG; } if (EntryAddress == ListHeaderAddress) { dprintf("List at %p is empty\n", ListHeaderAddress); return S_OK; } dprintf("Base Length Type\n"); RtlZeroMemory(Count, sizeof(Count)); do { InitTypeRead(EntryAddress, nt!MEMORY_ALLOCATION_DESCRIPTOR); TypeOfMemory = ReadField(MemoryType); if (TypeOfMemory < MAXIMUM_MEMORY_TYPE) { LengthInPages = ReadField(PageCount); dprintf("%08x %08x %s\n", (ULONG)ReadField(BasePage), (ULONG)LengthInPages, MemoryDescriptorType[TypeOfMemory]); Count[TypeOfMemory] += (ULONG)LengthInPages; } else { dprintf("Unrecognized Descriptor at %p\n", EntryAddress); } EntryAddress = ReadField(ListEntry.Flink); } while (EntryAddress != ListHeaderAddress); dprintf("\nSummary\nMemory Type Pages\n"); LengthInPages = 0; for (i = 0; i < MAXIMUM_MEMORY_TYPE; i++) { if (Count[i]) { dprintf("%-20s%08x (%8d)\n", MemoryDescriptorType[i], Count[i], Count[i]); LengthInPages += Count[i]; } } dprintf(" ======== ========\n"); dprintf("Total %08x (%8d) = ~%dMB\n", (ULONG)LengthInPages, (ULONG)LengthInPages, (ULONG)LengthInPages / (1024 * 1024 / 4096)); return S_OK; }