windows-nt/Source/XPSP1/NT/base/tools/kdexts2/memory.c
2020-09-26 16:20:57 +08:00

3874 lines
115 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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<NumberOfProcesses; i++) {
dprintf( " %04I64lx %-15s %6I64d (%8I64ld Kb)\n",
ProcessCommitUsage[i].ClientId,
ProcessCommitUsage[i].ImageFileName,
ProcessCommitUsage[i].CommitCharge,
_KB*(ProcessCommitUsage[i].CommitCharge)
);
}
HeapFree(GetProcessHeap(), 0, ProcessCommitUsage);
}
}
if (Flags & 0x2) {
if (Client &&
(ExtQuery(Client) == S_OK)) {
dprintf("\n\tMemory Management Thread Stacks:\n");
DumpMmThreads ();
ExtRelease();
}
}
if (Flags & 0x4) {
if (Client &&
(ExtQuery(Client) == S_OK)) {
DumpTerminalServerMemory ();
ExtRelease();
}
}
return S_OK;
}
#if (_MSC_VER < 1200) && defined(_M_IX86)
#pragma optimize("", on)
#endif
VOID
DumpWholePfn(
IN ULONG64 Address,
IN ULONG Flags
)
/*++
Routine Description:
Dumps the PFN database
Arguments:
Address - address to dump at
Flags -
Return Value:
None.
--*/
{
ULONG result;
ULONG64 HighPage;
ULONG64 LowPage;
ULONG64 PageCount;
ULONG64 ReadCount;
ULONG64 i;
ULONG64 Pfn;
ULONG64 PfnStart;
PUCHAR PfnArray;
PUCHAR PfnArrayPointer;
ULONG64 VirtualAddress;
ULONG MatchLocation;
BOOLEAN foundlink;
BOOLEAN RandomAccessRequired;
ULONG PfnSize;
ULONG NumberOfPfnToRead;
ULONG sz;
MMPFNENTRY u3_e1;
CHAR InPageError;
LowPage = GetNtDebuggerDataValue(MmLowestPhysicalPage);
HighPage = GetNtDebuggerDataValue(MmHighestPhysicalPage);
PfnStart = GetNtDebuggerDataPtrValue(MmPfnDatabase);
PfnSize = GetTypeSize("nt!_MMPFN");
//
// Read sufficient pages such that htere isn't lot of wait
// before first page dump.
//
NumberOfPfnToRead = 2000;
PfnArray = NULL;
if (Flags == 7) {
RandomAccessRequired = TRUE;
}
else {
RandomAccessRequired = FALSE;
}
if (RandomAccessRequired == FALSE) {
dprintf("\n Page Flink Blk/Shr Ref V PTE Address SavedPTE Frame State\n");
}
//
// If asked to dump the whole database or we're going to need the ability
// to look up random frames, then read in the whole database now.
//
if (Address == 0 || RandomAccessRequired == TRUE) {
PfnArray = LocalAlloc(LPTR, (ULONG) (HighPage+1) * PfnSize);
if (!PfnArray) {
dprintf("unable to get allocate %ld bytes of memory\n",
(HighPage+1) * PfnSize);
return;
}
for (PageCount = LowPage;
PageCount <= HighPage;
PageCount += NumberOfPfnToRead) {
if (CheckControlC()) {
goto alldone;
}
ReadCount = HighPage - PageCount > 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; i<pKernelMap->Count; 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;i<pKernelMap->Count ;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;i<MaxDirbase;i++) {
if ( DirBases[i] == DirBase ) {
return &Names[i][0];
}
}
return NULL;
}
LOGICAL
BuildKernelMap (
OUT PKERN_MAP KernelMap
)
{
ULONG64 Next;
ULONG64 ListHead;
NTSTATUS Status = 0;
ULONG Result;
ULONG64 DataTable;
ULONG i = 0;
ULONG64 Flink;
ULONG InLoadOrderLinksOffset;
FIELD_INFO offField = {"InLoadOrderLinks", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
SYM_DUMP_PARAM TypeSym ={
sizeof (SYM_DUMP_PARAM), "nt!_LDR_DATA_TABLE_ENTRY", DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 1, &offField
};
// Get the offset of InLoadOrderLinks in LDR_DATA_TABLE_ENTRY
if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
return FALSE;
}
InLoadOrderLinksOffset = (ULONG) offField.address;
ListHead = GetNtDebuggerData(PsLoadedModuleList );
if (!ListHead) {
dprintf("Couldn't get offset of PsLoadedModuleListHead\n");
return FALSE;
}
if (GetFieldValue(ListHead, "nt!_LIST_ENTRY", "Flink", Flink)) {
dprintf("Unable to get value of PsLoadedModuleListHead\n");
return FALSE;
}
Next = Flink;
if (Next == 0) {
dprintf("PsLoadedModuleList is NULL!\n");
return FALSE;
}
while (Next != ListHead) {
ULONG64 BaseDllNameBuffer, DllBase;
ULONG BaseDllNameLength=0, SizeOfImage;
if (CheckControlC()) {
return FALSE;
}
DataTable = (Next - InLoadOrderLinksOffset);
if (GetFieldValue(DataTable,
"nt!_LDR_DATA_TABLE_ENTRY",
"BaseDllName.Buffer",
BaseDllNameBuffer)) {
dprintf("Unable to read LDR_DATA_TABLE_ENTRY at %08p\n",
DataTable);
return FALSE;
}
GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","BaseDllName.Length",BaseDllNameLength);
GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","DllBase",DllBase);
GetFieldValue(DataTable, "nt!_LDR_DATA_TABLE_ENTRY","SizeOfImage",SizeOfImage);
//
// Get the base DLL name.
//
if ((!ReadMemory(BaseDllNameBuffer,
&KernelMap->Item[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 <address_of_listhead>\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;
}