Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1456 lines
45 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
memory.c
Abstract:
WinDbg Extension Api
Author:
Lou Perazzoli (loup)
Environment:
User Mode.
Revision History:
Wesley Witt (wesw) 15-Aug-1993: WinDbg environment
--*/
#include "precomp.h"
#pragma hdrstop
#define USAGE_ALLOC_SIZE 256*1024
ULONG MmSubsectionBase;
typedef struct _PFN_INFO {
ULONG Master;
ULONG 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 {
ULONG StartVa;
ULONG EndVa;
ULONG ValidCount;
ULONG StandbyCount;
ULONG ModifiedCount;
ULONG SharedCount;
ULONG LockedCount;
ULONG PageTableCount;
WCHAR Name[50];
} KERN_MAP1, *PKERN_MAP1;
typedef struct _KERN_MAP {
ULONG Count;
KERN_MAP1 Item[50];
} KERN_MAP, *PKERN_MAP;
KERN_MAP KernelMap;
#define PACKET_MAX_SIZE 2048
#define NUMBER_OF_PFN_TO_READ ((PACKET_MAX_SIZE/sizeof(MMPFN))-1)
UCHAR *PageLocationList[] = {
"Zeroed ",
"Free ",
"Standby ",
"Modified",
"ModNoWrt",
"Bad ",
"Active ",
"Trans "
};
ULONG MaxDirbase;
#define MAX_DIRBASEVECTOR 256
ULONG DirBases[MAX_DIRBASEVECTOR];
UCHAR Names[MAX_DIRBASEVECTOR][64];
VOID
PrintPfn (
IN PVOID PfnAddress,
IN PMMPFN PfnContents
);
VOID DumpWholePfn(
IN ULONG Address,
IN ULONG Flags
);
PUCHAR
DirbaseToImage(
IN ULONG DirBase
);
NTSTATUS
BuildDirbaseList( VOID );
VOID
BuildKernelMap (
OUT PKERN_MAP KernelMap
);
DECLARE_API( memusage )
/*++
Routine Description:
Dumps the page frame database table
Arguments:
arg -
Return Value:
None.
--*/
{
ULONG result;
ULONG PfnDb;
ULONG HighPageAddr;
ULONG LowPageAddr;
ULONG HighPage;
ULONG LowPage;
ULONG PageCount;
ULONG ReadCount;
ULONG WasZeroedPage;
ULONG WasFreePage;
ULONG Total;
ULONG WasStandbyPage;
ULONG WasModifiedPage;
ULONG WasModifiedNoWritePage;
ULONG WasBadPage;
ULONG WasActiveAndValidPage;
ULONG WasTransitionPage;
ULONG WasUnknownPage;
ULONG KernelCode = 0;
ULONG NonPagedPoolStart;
ULONG NonPagedSystemStart;
ULONG NPPoolStart;
ULONG NPSystemStart;
PMMPFN Pfn;
PMMPFN PfnStart;
PMMPFN PfnArray;
LowPageAddr = GetExpression( "MmLowestPhysicalPage" );
HighPageAddr = GetExpression( "MmHighestPhysicalPage" );
PfnDb = GetExpression( "MmPfnDatabase" );
NPPoolStart = GetExpression( "MmNonPagedPoolStart" );
NPSystemStart = GetExpression( "MmNonPagedSystemStart" );
if ( LowPageAddr &&
HighPageAddr &&
PfnDb &&
NPPoolStart &&
NPSystemStart ) {
if ( !ReadMemory( (DWORD)LowPageAddr,
&LowPage,
sizeof(ULONG),
&result) ) {
dprintf("%08lx: Unable to get low phyical page\n",LowPageAddr);
return;
}
if ( !ReadMemory( (DWORD)HighPageAddr,
&HighPage,
sizeof(ULONG),
&result) ) {
dprintf("%08lx: Unable to get high phyical page\n",HighPageAddr);
return;
}
if ( !ReadMemory( (DWORD)PfnDb,
&PfnStart,
sizeof(ULONG),
&result) ) {
dprintf("%08lx: Unable to get PFN database address\n",PfnDb);
return;
}
if ( !ReadMemory( (DWORD)NPPoolStart,
&NonPagedPoolStart,
sizeof(ULONG),
&result) ) {
dprintf("%08lx: Unable to get nonpaged pool start address\n",NPPoolStart);
return;
}
if ( !ReadMemory( (DWORD)NPSystemStart,
&NonPagedSystemStart,
sizeof(ULONG),
&result) ) {
dprintf("%08lx: Unable to get non paged system start address\n",NPSystemStart );
return;
}
dprintf(" loading PFN database");
NonPagedSystemStart = (ULONG)MiGetPteAddress (NonPagedSystemStart);
NonPagedPoolStart = (ULONG)MiGetPteAddress (NonPagedPoolStart);
PfnArray = VirtualAlloc (NULL,
(HighPage-LowPage+1) * sizeof (MMPFN),
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!PfnArray) {
dprintf("Unable to get allocate memory of %ld bytes\n",
(HighPage-LowPage+1) * sizeof (MMPFN));
} else {
//dprintf("basic parameters - "
// "LowPage %lx - HighPage %lu - NumToRead %lu\n",
// LowPage, HighPage, NUMBER_OF_PFN_TO_READ);
for (PageCount = LowPage;
PageCount <= HighPage;
PageCount += NUMBER_OF_PFN_TO_READ) {
//dprintf("getting PFN table block - "
// "address %lx - count %lu - page %lu\n",
// Pfn, ReadCount, PageCount);
if ( CheckControlC() ) {
VirtualFree (PfnArray,0,MEM_RELEASE);
return;
}
ReadCount = HighPage - PageCount > NUMBER_OF_PFN_TO_READ ?
NUMBER_OF_PFN_TO_READ :
HighPage - PageCount + 1;
ReadCount *= sizeof (MMPFN);
Pfn = (PMMPFN)((ULONG)PfnStart + PageCount * sizeof (MMPFN));
dprintf(".");
if ( !ReadMemory( (DWORD)Pfn,
&PfnArray[PageCount],
ReadCount,
&result) ) {
dprintf("Unable to get PFN table block - "
"address %lx - count %lu - page %lu\n",
Pfn, ReadCount, PageCount);
VirtualFree (PfnArray,0,MEM_RELEASE);
return;
}
}
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;
for (PageCount = LowPage;
PageCount <= HighPage;
PageCount++) {
if ( CheckControlC() ) {
VirtualFree (PfnArray,0,MEM_RELEASE);
return;
}
Pfn = &PfnArray[PageCount];
switch ((int)Pfn->u3.e1.PageLocation) {
case ZeroedPageList:
if ((Pfn->u1.Flink == 0) &&
(Pfn->u2.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( " Zeroed: %6lu (%6lu kb)\n",
WasZeroedPage, WasZeroedPage * (PAGE_SIZE / 1024));
dprintf( " Free: %6lu (%6lu kb)\n",
WasFreePage, WasFreePage * (PAGE_SIZE / 1024));
dprintf( " Standby: %6lu (%6lu kb)\n",
WasStandbyPage, WasStandbyPage * (PAGE_SIZE / 1024));
dprintf( " Modified: %6lu (%6lu kb)\n",
WasModifiedPage,
WasModifiedPage * (PAGE_SIZE / 1024));
dprintf( " ModifiedNoWrite: %6lu (%6lu kb)\n",
WasModifiedNoWritePage,WasModifiedNoWritePage * (PAGE_SIZE / 1024));
dprintf( " Active/Valid: %6lu (%6lu kb)\n",
WasActiveAndValidPage, WasActiveAndValidPage * (PAGE_SIZE / 1024));
dprintf( " Transition: %6lu (%6lu kb)\n",
WasTransitionPage, WasTransitionPage * (PAGE_SIZE / 1024));
dprintf( " Unknown: %6lu (%6lu kb)\n",
WasUnknownPage, WasUnknownPage * (PAGE_SIZE / 1024));
Total = WasZeroedPage +
WasFreePage +
WasStandbyPage +
WasModifiedPage +
WasModifiedNoWritePage +
WasActiveAndValidPage +
WasTransitionPage +
WasUnknownPage +
WasUnknownPage;
dprintf( " TOTAL: %6lu (%6lu kb)\n",
Total, Total * (PAGE_SIZE / 1024));
}
MemoryUsage (PfnArray,LowPage,HighPage, 0);
VirtualFree (PfnArray,0,MEM_RELEASE);
}
return;
}
DECLARE_API( pfn )
/*++
Routine Description:
Displays the corresponding PDE and PTE.
Arguments:
arg - Supplies the Page frame number in hex.
Return Value:
None.
--*/
{
ULONG Address;
ULONG result;
ULONG PfnDb;
MMPFN PfnContents;
PMMPFN Pfn;
PMMPFN PfnStart;
ULONG Flags;
PfnDb = GetExpression( "MmPfnDatabase" );
if (!PfnDb) {
dprintf("unable to get PFN database address\n");
return;
}
if ((!ReadMemory((DWORD)PfnDb,&PfnStart,sizeof(ULONG),&result)) ||
(result < sizeof(ULONG))) {
dprintf("unable to get PFN database address\n");
return;
}
Flags = 0;
sscanf(args,"%lx %lx",&Address, &Flags);
if (Flags != 0) {
DumpWholePfn (Address, Flags);
return;
}
Pfn = (PMMPFN)((ULONG)PfnStart + Address * sizeof (MMPFN));
if ((!ReadMemory((DWORD)Pfn,&PfnContents,sizeof(MMPFN),&result)) ||
(result < sizeof(MMPFN))) {
dprintf("unable to get PFN element\n");
return;
}
PrintPfn((PVOID)Pfn, &PfnContents);
return;
}
DECLARE_API( vm )
/*++
Routine Description:
Displays physical memory usage by driver.
Arguments:
arg -
Return Value:
None.
--*/
{
ULONG Index;
ULONG MemorySize;
ULONG CommitLimit;
ULONG CommitTotal;
ULONG SharedCommit;
ULONG ProcessCommit;
ULONG PagedPoolCommit;
ULONG DriverCommit;
ULONG ZeroPages;
ULONG FreePages;
ULONG StandbyPages;
ULONG ModifiedPages;
ULONG ModifiedNoWrite;
ULONG NumberOfPagedPools;
ULONG NumberOfPagingFiles;
ULONG AvailablePages;
ULONG ResidentAvailablePages;
ULONG PoolLoc;
POOL_DESCRIPTOR PoolDesc;
ULONG result;
ULONG TotalPages;
ULONG ExtendedCommit;
ULONG TotalProcessCommit;
PPROCESS_COMMIT_USAGE ProcessCommitUsage;
ULONG i, NumberOfProcesses;
dprintf("\n*** Virtual Memory Usage ***\n");
MemorySize = GetUlongValue ("MmNumberOfPhysicalPages");
dprintf ("\tPhysical Memory: %8ld (%6ld Kb)\n",MemorySize,_KB*MemorySize);
NumberOfPagingFiles = GetUlongValue ("MmNumberOfPagingFiles");
if (NumberOfPagingFiles == 0) {
dprintf("\n************ NO PAGING FILE *********************\n\n");
}
CommitLimit = GetUlongValue ("MmTotalCommitLimit");
CommitTotal = GetUlongValue ("MmTotalCommittedPages");
SharedCommit = GetUlongValue ("MmSharedCommit");
DriverCommit = GetUlongValue ("MmDriverCommit");
ProcessCommit = GetUlongValue ("MmProcessCommit");
PagedPoolCommit = GetUlongValue ("MmPagedPoolCommit");
ZeroPages = GetUlongValue ("MmZeroedPageListHead");
FreePages = GetUlongValue ("MmFreePageListHead");
StandbyPages = GetUlongValue ("MmStandbyPageListHead");
ModifiedPages = GetUlongValue ("MmModifiedPageListHead");
ModifiedNoWrite = GetUlongValue ("MmModifiedNoWritePageListHead");
AvailablePages = GetUlongValue ("MmAvailablePages");
ResidentAvailablePages = GetUlongValue ("MmResidentAvailablePages");
ExtendedCommit = GetUlongValue ("MmExtendedCommit");
dprintf ("\tAvailable Pages: %8ld (%6ld Kb)\n",AvailablePages, AvailablePages*_KB);
dprintf ("\tModified Pages: %8ld (%6ld Kb)\n",ModifiedPages,ModifiedPages*_KB);
if ((AvailablePages < 50) && (ModifiedPages > 200)) {
dprintf("\t********** High Number Of Modified Pages ********\n");
}
if (ModifiedNoWrite > 50) {
dprintf("\t********** High Number Of Modified No Write Pages ********\n");
dprintf("\tModified No Write Pages: %ld (%6ld Kb)\n",ModifiedNoWrite,_KB*ModifiedNoWrite);
}
if (ResidentAvailablePages < 100) {
dprintf("\t\nRunning out of physical memory\n");
}
PoolLoc = GetExpression( "NonPagedPoolDescriptor" );
if ( !PoolLoc ||
!ReadMemory( (DWORD)PoolLoc,
&PoolDesc,
sizeof(POOL_DESCRIPTOR),
&result) ) {
dprintf("%08lx: Unable to get pool descriptor\n",PoolLoc);
return;
}
dprintf("\tNonPagedPool Usage: %5ld (%6ld Kb)\n",PoolDesc.TotalPages + PoolDesc.TotalBigPages,
_KB*(PoolDesc.TotalPages + PoolDesc.TotalBigPages));
if ((PoolDesc.TotalPages + PoolDesc.TotalBigPages) > (MemorySize / 5)) {
dprintf("\t********** Excessive NonPaged Pool Usage *****\n");
}
TotalPages = 0;
PoolLoc = GetUlongValue("ExpPagedPoolDescriptor");
NumberOfPagedPools = GetUlongValue("ExpNumberOfPagedPools");
if ((PoolLoc != 0) && (NumberOfPagedPools != 0)) {
for (Index = 0; Index < (NumberOfPagedPools + 1); Index += 1) {
if (!ReadMemory((DWORD)PoolLoc,
&PoolDesc,
sizeof(POOL_DESCRIPTOR),
&result)) {
dprintf("%08lx: Unable to get pool descriptor\n",PoolLoc);
return;
}
dprintf("\tPagedPool %1ld Usage: %5ld (%6ld Kb)\n",
Index,
PoolDesc.TotalPages + PoolDesc.TotalBigPages,
_KB*(PoolDesc.TotalPages + PoolDesc.TotalBigPages));
TotalPages += PoolDesc.TotalPages + PoolDesc.TotalBigPages;
PoolLoc += sizeof(POOL_DESCRIPTOR);
}
}
dprintf("\tPagedPool Usage: %5ld (%6ld Kb)\n", TotalPages,_KB*TotalPages);
dprintf("\tShared Commit: %8ld (%6ld Kb)\n",SharedCommit,_KB*SharedCommit );
dprintf("\tShared Process: %8ld (%6ld Kb)\n",ProcessCommit,_KB*ProcessCommit );
ProcessCommitUsage = GetProcessCommit( &TotalProcessCommit, &NumberOfProcesses );
if (TotalProcessCommit != 0) {
dprintf("\tTotal Private: %8ld (%6ld Kb)\n",TotalProcessCommit,_KB*TotalProcessCommit);
}
for (i=0; i<NumberOfProcesses; i++) {
dprintf( " %-16s %6d (%6ld Kb)\n",
ProcessCommitUsage[i].ImageFileName,
ProcessCommitUsage[i].CommitCharge,
_KB*(ProcessCommitUsage[i].CommitCharge)
);
}
dprintf("\tPagedPool Commit:%8ld (%6ld Kb)\n",PagedPoolCommit,_KB*PagedPoolCommit);
dprintf("\tDriver Commit: %8ld (%6ld Kb)\n",DriverCommit, _KB*DriverCommit );
dprintf("\tCommitted pages: %8ld (%6ld Kb)\n",CommitTotal, _KB*CommitTotal );
dprintf("\tCommit limit: %8ld (%6ld Kb)\n",CommitLimit, _KB*CommitLimit );
if ((CommitTotal + 100) > CommitLimit) {
dprintf("\n\t********** Number of committed pages is near limit ********\n");
}
if (ExtendedCommit != 0) {
dprintf("\n\t********** Commit has been extended with VM popup ********\n");
dprintf("\tExtended by: %8ld (%6ld Kb)\n", ExtendedCommit,_KB*ExtendedCommit);
}
dprintf("\n");
return;
}
VOID DumpWholePfn(
IN ULONG Address,
IN ULONG Flags
)
/*++
Routine Description:
Dumps the PFN database
Arguments:
Address - address to dump at
Flags -
Return Value:
None.
--*/
{
ULONG result;
ULONG HighPage;
ULONG LowPage;
ULONG PageCount;
ULONG ReadCount;
ULONG i;
MMPFN PfnContents;
PMMPFN Pfn;
PMMPFN PfnStart;
PMMPFN PfnArray;
PVOID VirtualAddress;
ULONG MatchLocation;
LowPage = GetUlongValue("MmLowestPhysicalPage");
HighPage = GetUlongValue("MmHighestPhysicalPage");
PfnStart = (PMMPFN)GetUlongValue ("MmPfnDatabase");
dprintf("\n Page Flink Blk/Shr Ref V PTE Address SavedPTE Frame State\n");
if (Address != 0) {
Pfn = (PMMPFN)((ULONG)PfnStart + Address * sizeof (MMPFN));
if ((!ReadMemory((DWORD)Pfn,&PfnContents,sizeof(MMPFN),&result)) ||
(result < sizeof(MMPFN))) {
dprintf("unable to get PFN element\n");
return;
}
MatchLocation = PfnContents.u3.e1.PageLocation;
do {
if (CheckControlC()) {
return;
}
Pfn = (PMMPFN)((ULONG)PfnStart + Address * sizeof (MMPFN));
if ((!ReadMemory((DWORD)Pfn,&PfnContents,sizeof(MMPFN),&result))||
(result < sizeof(MMPFN))) {
dprintf("unable to get PFN element\n");
return;
}
if (PfnContents.u3.e1.PrototypePte == 0) {
VirtualAddress = MiGetVirtualAddressMappedByPte (PfnContents.PteAddress);
} else {
VirtualAddress = NULL;
}
if (PfnContents.u3.e1.PageLocation == MatchLocation) {
dprintf("%5lx %8lx %8lx%6lx %8lx %8lx %8lx%6lx %s %c%c%c%c%c%c\n",
Address,
PfnContents.u1.Flink,
PfnContents.u2.Blink,
PfnContents.u3.e2.ReferenceCount,
PfnContents.PteAddress,
VirtualAddress,
PfnContents.OriginalPte,
PfnContents.PteFrame,
PageLocationList[PfnContents.u3.e1.PageLocation],
PfnContents.u3.e1.Modified ? 'M':' ',
PfnContents.u3.e1.PrototypePte ? 'P':' ',
PfnContents.u3.e1.ReadInProgress ? 'R':' ',
PfnContents.u3.e1.WriteInProgress ? 'W':' ',
PfnContents.u3.e1.InPageError ? 'E':' ',
PfnContents.u3.e1.ParityError ? 'X':' '
);
}
if (MatchLocation > 5) {
Address += 1;
} else {
if (Flags == 3) {
Address = PfnContents.u2.Blink;
} else {
Address = PfnContents.u1.Flink;
}
}
if (CheckControlC()) {
return;
}
} while (Address < HighPage);
return;
}
PfnArray = LocalAlloc(LPTR, (HighPage-LowPage+1) * sizeof (MMPFN));
if (!PfnArray) {
dprintf("unable to get allocate memory of %ld bytes\n",
(HighPage-LowPage+1) * sizeof (MMPFN));
return;
}
for (PageCount = LowPage;
PageCount <= HighPage;
PageCount += NUMBER_OF_PFN_TO_READ) {
if (CheckControlC()) {
LocalFree((void *)PfnArray);
return;
}
ReadCount = HighPage - PageCount > NUMBER_OF_PFN_TO_READ ?
NUMBER_OF_PFN_TO_READ :
HighPage - PageCount + 1;
ReadCount *= sizeof (MMPFN);
Pfn = (PMMPFN)((ULONG)PfnStart + PageCount * sizeof (MMPFN));
if ((!ReadMemory((DWORD)Pfn,
&PfnArray[PageCount],
ReadCount,
&result)) || (result < ReadCount)) {
dprintf("unable to get PFN table block - "
"address %lx - count %lu - page %lu\n",
Pfn, ReadCount, PageCount);
LocalFree((void *)PfnArray);
return;
}
for (i = PageCount;
(i < PageCount + NUMBER_OF_PFN_TO_READ) && (i < HighPage);
i += 1) {
if (PfnArray[i].u3.e1.PrototypePte == 0) {
VirtualAddress = MiGetVirtualAddressMappedByPte (PfnArray[i].PteAddress);
} else {
VirtualAddress = NULL;
}
dprintf("%5lx %8lx %8lx%6lx %8lx %8lx %8lx%6lx %s %c%c%c%c%c%c\n",
i,
PfnArray[i].u1.Flink,
PfnArray[i].u2.Blink,
PfnArray[i].u3.e2.ReferenceCount,
PfnArray[i].PteAddress,
VirtualAddress,
PfnArray[i].OriginalPte,
PfnArray[i].PteFrame,
PageLocationList[PfnArray[i].u3.e1.PageLocation],
PfnArray[i].u3.e1.Modified ? 'M':' ',
PfnArray[i].u3.e1.PrototypePte ? 'P':' ',
PfnArray[i].u3.e1.ReadInProgress ? 'R':' ',
PfnArray[i].u3.e1.WriteInProgress ? 'W':' ',
PfnArray[i].u3.e1.InPageError ? 'E':' ',
PfnArray[i].u3.e1.ParityError ? 'X':' '
);
if (CheckControlC()) {
LocalFree((void *)PfnArray);
return;
}
}
}
LocalFree((void *)PfnArray);
return;
}
VOID
PrintPfn (
IN PVOID PfnAddress,
IN PMMPFN PfnContents
)
{
dprintf(" PFN address %08lX\n",PfnAddress);
dprintf(" flink %08lX blink / share count %08lX pteaddress %08lX\n",
PfnContents->u1.Flink,
PfnContents->u2.Blink,
PfnContents->PteAddress);
dprintf(" reference count %04hX color %01hX\n",
PfnContents->u3.e2.ReferenceCount,
PfnContents->u3.e1.PageColor);
dprintf(" restore pte %08lX containing page %05lX %s %c%c%c%c%c%c\n",
PfnContents->OriginalPte,
PfnContents->PteFrame,
PageLocationList[PfnContents->u3.e1.PageLocation],
PfnContents->u3.e1.Modified ? 'M':' ',
PfnContents->u3.e1.PrototypePte ? 'P':' ',
PfnContents->u3.e1.ReadInProgress ? 'R':' ',
PfnContents->u3.e1.WriteInProgress ? 'W':' ',
PfnContents->u3.e1.InPageError ? 'E':' ',
PfnContents->u3.e1.ParityError ? 'X':' '
);
dprintf(" %s %s %s %s %s %s\n",
PfnContents->u3.e1.Modified ? "Modified":" ",
PfnContents->u3.e1.PrototypePte ? "Shared":" ",
PfnContents->u3.e1.ReadInProgress ? "ReadInProgress":" ",
PfnContents->u3.e1.WriteInProgress ? "WriteInProgress":" ",
PfnContents->u3.e1.InPageError ? "InPageError":" ",
PfnContents->u3.e1.ParityError ? "ParityError":" ");
return;
}
VOID
MemoryUsage (
IN PMMPFN PfnArray,
IN ULONG LowPage,
IN ULONG 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.
--*/
{
PMMPFN LastPfn;
PMMPFN Pfn1;
PMMPFN Pfn2;
SUBSECTION Subsection;
PVOID Subsection1;
FILE_OBJECT FilePointer;
UNICODE_STRING NameString;
WCHAR Buffer[1000];
PPFN_INFO Info;
PPFN_INFO Info1;
PPFN_INFO InfoStart;
PPFN_INFO InfoEnd;
PFN_INFO ProcessPfns;
PFN_INFO PagedPoolBlock;
PPFN_INFO LastProcessInfo = &ProcessPfns;
ULONG Master;
CONTROL_AREA ControlArea;
PVOID ControlArea1;
BOOLEAN Found;
ULONG result;
KERN_MAP KernelMap;
ULONG i;
ULONG VirtualAddress;
ULONG PagedPoolStart;
NameString.Buffer = Buffer;
PagedPoolStart = GetUlongValue("MmPagedPoolStart");
RtlZeroMemory (&KernelMap, sizeof (KernelMap));
BuildKernelMap (&KernelMap);
RtlZeroMemory (&PagedPoolBlock, sizeof (PFN_INFO));
InfoStart = VirtualAlloc (NULL,
USAGE_ALLOC_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
if (InfoStart == NULL) {
dprintf ("heap allocation failed\n");
return;
}
InfoEnd = InfoStart;
Pfn1 = &PfnArray[LowPage];
LastPfn = &PfnArray[HighPage];
if (MmSubsectionBase == 0) {
MmSubsectionBase = GetUlongValue ("MmSubsectionBase");
}
while (Pfn1 < LastPfn) {
if (CheckControlC()) {
return;
}
if ((Pfn1->u3.e1.PageLocation != FreePageList) &&
(Pfn1->u3.e1.PageLocation != ZeroedPageList) &&
(Pfn1->u3.e1.PageLocation != BadPageList)) {
Subsection1 = MiGetSubsectionAddress ((PMMPTE)&Pfn1->OriginalPte.u.Long);
if ((Subsection1) && (Subsection1 < (PVOID)0xffbff000)) {
Master = (ULONG)Subsection1;
} else {
if (IgnoreInvalidFrames) {
Master = Pfn1->PteFrame;
} else {
if ((ULONG)Pfn1->PteAddress > PagedPoolStart) {
Master = Pfn1->PteFrame;
} else {
Pfn2 = &PfnArray[Pfn1->PteFrame];
Master = Pfn2->PteFrame;
if ((Master == 0) || (Master > HighPage)) {
dprintf("Invalid PTE frame\n");
PrintPfn((PVOID)(Pfn1-PfnArray),Pfn1);
PrintPfn(NULL,Pfn2);
dprintf(" subsection address: %lx\n",Subsection1);
Pfn1++;
continue;
}
}
}
}
VirtualAddress = (ULONG)MiGetVirtualAddressMappedByPte (Pfn1->PteAddress);
if (((ULONG)Pfn1->PteAddress < PagedPoolStart) && (VirtualAddress > 0x80000000)) {
for (i=0; i<KernelMap.Count; i++) {
if ((VirtualAddress >= KernelMap.Item[i].StartVa) &&
(VirtualAddress < KernelMap.Item[i].EndVa)) {
if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
(Pfn1->u3.e1.PageLocation == ModifiedNoWritePageList)) {
KernelMap.Item[i].ModifiedCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 0) {
KernelMap.Item[i].LockedCount += _KB;
}
} else if ((Pfn1->u3.e1.PageLocation == StandbyPageList) ||
(Pfn1->u3.e1.PageLocation == TransitionPage)) {
KernelMap.Item[i].StandbyCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 0) {
KernelMap.Item[i].LockedCount += _KB;
}
} else {
KernelMap.Item[i].ValidCount += _KB;
if (Pfn1->u2.ShareCount > 1) {
KernelMap.Item[i].SharedCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 1) {
KernelMap.Item[i].LockedCount += _KB;
}
}
}
goto NextPfn;
}
}
}
if (Pfn1->PteAddress >= (PMMPTE)0xF0000000) {
//
// 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 + USAGE_ALLOC_SIZE) - sizeof(PFN_INFO)) {
dprintf("out of space\n");
VirtualFree (InfoStart,0,MEM_RELEASE);
return;
}
RtlZeroMemory (Info, sizeof (PFN_INFO));
Info->Master = Master;
Info->OriginalPte = Pfn1->OriginalPte.u.Long;
}
if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
(Pfn1->u3.e1.PageLocation == ModifiedNoWritePageList)) {
Info->ModifiedCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 0) {
Info->LockedCount += _KB;
}
} else if ((Pfn1->u3.e1.PageLocation == StandbyPageList) ||
(Pfn1->u3.e1.PageLocation == TransitionPage)) {
Info->StandbyCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 0) {
Info->LockedCount += _KB;
}
} else {
Info->ValidCount += _KB;
if (Pfn1->u2.ShareCount > 1) {
Info->SharedCount += _KB;
if (Pfn1->u3.e2.ReferenceCount > 1) {
Info->LockedCount += _KB;
}
}
}
if ((Pfn1->PteAddress >= MiGetPdeAddress (0x0)) &&
(Pfn1->PteAddress <= MiGetPdeAddress (0xFFFFFFFF))) {
Info->PageTableCount += _KB;
}
}
NextPfn:
Pfn1++;
}
//
// 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 KiloBytes (Kb):\n");
Info = InfoStart;
while (Info < InfoEnd) {
if (CheckControlC()) {
return;
}
if (Info->Master > 0x200000) {
//
// Get the control area from the subsection.
//
if ((!ReadMemory((DWORD)Info->Master,
&Subsection,
sizeof(Subsection),
&result)) || (result < sizeof(Subsection))) {
dprintf("unable to get subsection va %lx %lx\n",Info->Master,Info->OriginalPte);
}
ControlArea1 = Subsection.ControlArea;
Info->Master = (ULONG)ControlArea1;
//
// Loop through the array so far for maching control areas
//
Info1 = InfoStart;
while (Info1 < Info) {
if (Info1->Master == (ULONG)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) {
if (CheckControlC()) {
return;
}
if (Info->Master > 0x200000) {
//
// Get the control area.
//
if ((!ReadMemory((DWORD)Info->Master,
&ControlArea,
sizeof(ControlArea),
&result)) || (result < sizeof(ControlArea))) {
dprintf("%8lx %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 (ControlArea.FilePointer == NULL) {
dprintf("%8lx %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 {
//
// Get the file pointer.
//
if ((!ReadMemory((DWORD)ControlArea.FilePointer,
&FilePointer,
sizeof(FilePointer),
&result)) || (result < sizeof(FilePointer))) {
dprintf("unable to get subsection %lx\n",ControlArea.FilePointer);
}
if (FilePointer.FileName.Length != 0) {
//
// Get the name string.
//
NameString.Length = FilePointer.FileName.Length;
if ((!ReadMemory((DWORD)FilePointer.FileName.Buffer,
NameString.Buffer,
FilePointer.FileName.Length,
&result)) || (result < FilePointer.FileName.Length)) {
dprintf("%8lx %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));
CopyMemory(FileName,NameString.Buffer,NameString.Length);
GetFullPathNameW(
FileName,
MAX_PATH,
FullFileName,
&FilePart
);
dprintf("%8lx %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("%8lx %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<KernelMap.Count ;i++) {
dprintf("-------- %4ld %5ld %5ld ----- %5ld ----- driver ( %ws )\n",
KernelMap.Item[i].ValidCount,
KernelMap.Item[i].StandbyCount,
KernelMap.Item[i].ModifiedCount,
KernelMap.Item[i].LockedCount,
KernelMap.Item[i].Name
);
}
}
VirtualFree (InfoStart,0,MEM_RELEASE);
return;
}
NTSTATUS
BuildDirbaseList( VOID )
{
LIST_ENTRY List;
PLIST_ENTRY Next;
ULONG ProcessHead;
PEPROCESS Process;
EPROCESS ProcessContents;
NTSTATUS status=0;
ULONG Result;
PHARDWARE_PTE HardPte;
MaxDirbase = 0;
ProcessHead = GetExpression( "PsActiveProcessHead" );
if (!ProcessHead) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
if ((!ReadMemory((DWORD)ProcessHead, &List, sizeof(LIST_ENTRY), &Result))
|| (Result < sizeof(LIST_ENTRY))) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
Next = List.Flink;
if (Next == NULL) {
dprintf("PsActiveProcessHead is NULL!\n");
return STATUS_INVALID_PARAMETER;
}
while((ULONG)Next != ProcessHead) {
if (Next != NULL) {
Process = CONTAINING_RECORD(Next,EPROCESS,ActiveProcessLinks);
}
if ((!ReadMemory((DWORD)Process,
&ProcessContents,
sizeof(EPROCESS),
&Result)) || (Result < sizeof(EPROCESS))) {
dprintf("Unable to read _EPROCESS at %lx\n",Process);
MaxDirbase = 0;
return status;
}
if ( ProcessContents.ImageFileName[ 0 ] != '\0' ) {
strcpy(&Names[MaxDirbase][0],ProcessContents.ImageFileName);
} else {
strcpy(&Names[MaxDirbase][0],"SystemProcess");
}
HardPte = (PHARDWARE_PTE)ProcessContents.Pcb.DirectoryTableBase;
DirBases[MaxDirbase++] = HardPte->PageFrameNumber;
Next = ProcessContents.ActiveProcessLinks.Flink;
if (CheckControlC()) {
MaxDirbase = 0;
return STATUS_INVALID_PARAMETER;
}
}
}
PUCHAR
DirbaseToImage(
IN ULONG DirBase
)
{
ULONG i;
for(i=0;i<MaxDirbase;i++) {
if ( DirBases[i] == DirBase ) {
return &Names[i][0];
}
}
return NULL;
}
VOID
BuildKernelMap (
OUT PKERN_MAP KernelMap
)
{
LIST_ENTRY List;
PLIST_ENTRY Next;
ULONG ListHead;
NTSTATUS Status = 0;
ULONG Result;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
ULONG i = 0;
ListHead = GetExpression( "PsLoadedModuleList" );
if (!ListHead) {
dprintf("Couldn't get offset of PsLoadedModuleListHead\n");
return;
} else {
if ((!ReadMemory((DWORD)ListHead,
&List,
sizeof(LIST_ENTRY),
&Result)) || (Result < sizeof(LIST_ENTRY))) {
dprintf("Unable to get value of PsLoadedModuleListHead\n");
return;
}
}
Next = List.Flink;
if (Next == NULL) {
dprintf("PsLoadedModuleList is NULL!\n");
return;
}
while ((ULONG)Next != ListHead) {
if (CheckControlC()) {
return;
}
DataTable = CONTAINING_RECORD(Next,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
if ((!ReadMemory((DWORD)DataTable,
&DataTableBuffer,
sizeof(LDR_DATA_TABLE_ENTRY),
&Result)) || (Result < sizeof(LDR_DATA_TABLE_ENTRY))) {
dprintf("Unable to read LDR_DATA_TABLE_ENTRY at %08lx - status %08lx\n",
DataTable,
Status);
return;
}
//
// Get the base DLL name.
//
if ((!ReadMemory((DWORD)DataTableBuffer.BaseDllName.Buffer,
&KernelMap->Item[i].Name[0],
DataTableBuffer.BaseDllName.Length,
&Result)) || (Result < DataTableBuffer.BaseDllName.Length)) {
dprintf("Unable to read name string at %08lx - status %08lx\n",
DataTable,
Status);
return;
}
KernelMap->Item[i].Name[DataTableBuffer.BaseDllName.Length/2] = L'\0';
KernelMap->Item[i].StartVa = (ULONG)DataTableBuffer.DllBase;
KernelMap->Item[i].EndVa = KernelMap->Item[i].StartVa +
(ULONG)DataTableBuffer.SizeOfImage;
i += 1;
Next = DataTableBuffer.InLoadOrderLinks.Flink;
}
KernelMap->Item[i].StartVa = GetUlongValue("MmPagedPoolStart");
KernelMap->Item[i].EndVa = GetUlongValue("MmPagedPoolEnd");
wcscpy (&KernelMap->Item[i].Name[0], &L"Paged Pool");
i+= 1;
#if 0
KernelMap->Item[i].StartVa = (ULONG)MiGetPteAddress (0x80000000);
KernelMap->Item[i].EndVa = (ULONG)MiGetPteAddress (0xffffffff);
wcscpy (&KernelMap->Item[i].Name[0], &L"System Page Tables");
i+= 1;
KernelMap->Item[i].StartVa = (ULONG)MiGetPdeAddress (0x80000000);
KernelMap->Item[i].EndVa = (ULONG)MiGetPdeAddress (0xffffffff);
wcscpy (&KernelMap->Item[i].Name[0], &L"System Page Tables");
i+= 1;
#endif 0
KernelMap->Item[i].StartVa = (ULONG)MiGetVirtualAddressMappedByPte (
GetUlongValue ("MmSystemPtesStart"));
KernelMap->Item[i].EndVa = (ULONG)MiGetVirtualAddressMappedByPte (
GetUlongValue ("MmSystemPtesEnd")) + 1;
wcscpy (&KernelMap->Item[i].Name[0], &L"Kernel Stacks");
i+= 1;
KernelMap->Item[i].StartVa = GetUlongValue("MmNonPagedPoolStart");
KernelMap->Item[i].EndVa = GetUlongValue("MmNonPagedPoolEnd");
wcscpy (&KernelMap->Item[i].Name[0], &L"NonPaged Pool");
i+= 1;
KernelMap->Count = i;
}