mirror of https://github.com/lianthony/NT4.0
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.
879 lines
23 KiB
879 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dmpaddr.c
|
|
|
|
Abstract:
|
|
|
|
Temporary routine to print valid addresses within an
|
|
address space.
|
|
|
|
Author:
|
|
|
|
Lou Perazzoli (loup) 20-Mar-1989
|
|
|
|
Environment:
|
|
|
|
Kernel Mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mi.h"
|
|
|
|
#if DBG
|
|
|
|
BOOLEAN
|
|
MiFlushUnusedSectionInternal (
|
|
IN PCONTROL_AREA ControlArea
|
|
);
|
|
|
|
#endif //DBG
|
|
|
|
#if DBG
|
|
VOID
|
|
MiDumpValidAddresses (
|
|
)
|
|
|
|
{
|
|
ULONG va = 0;
|
|
ULONG i,j;
|
|
PMMPTE PointerPde;
|
|
PMMPTE PointerPte;
|
|
|
|
PointerPde = MiGetPdeAddress (va);
|
|
|
|
|
|
for (i = 0; i < PDE_PER_PAGE; i++) {
|
|
if (PointerPde->u.Hard.Valid) {
|
|
DbgPrint(" **valid PDE, element %ld %lx %lx\n",i,i,
|
|
PointerPde->u.Long);
|
|
PointerPte = MiGetPteAddress (va);
|
|
for (j = 0 ; j < PTE_PER_PAGE; j++) {
|
|
if (PointerPte->u.Hard.Valid) {
|
|
DbgPrint("Valid address at %lx pte %lx\n", (ULONG)va,
|
|
PointerPte->u.Long);
|
|
}
|
|
va += PAGE_SIZE;
|
|
PointerPte++;
|
|
}
|
|
} else {
|
|
va += (ULONG)PDE_PER_PAGE * (ULONG)PAGE_SIZE;
|
|
}
|
|
|
|
PointerPde++;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
#if DBG
|
|
VOID
|
|
MiFormatPte (
|
|
IN PMMPTE PointerPte
|
|
)
|
|
|
|
{
|
|
// int j;
|
|
// unsigned long pte;
|
|
PMMPTE proto_pte;
|
|
PSUBSECTION subsect;
|
|
|
|
// struct a_bit {
|
|
// unsigned long biggies : 31;
|
|
// unsigned long bitties : 1;
|
|
// };
|
|
//
|
|
// struct a_bit print_pte;
|
|
|
|
|
|
proto_pte = MiPteToProto(PointerPte);
|
|
subsect = MiGetSubsectionAddress(PointerPte);
|
|
|
|
DbgPrint("***DumpPTE at %lx contains %lx protoaddr %lx subsect %lx\n\n",
|
|
(ULONG)PointerPte, PointerPte->u.Long, (ULONG)proto_pte,
|
|
(ULONG)subsect);
|
|
|
|
return;
|
|
|
|
// DbgPrint("page frame number 0x%lx proto PTE address 0x%lx\n",
|
|
//
|
|
// DbgPrint("PTE is 0x%lx\n", PTETOULONG(the_pte));
|
|
//
|
|
// proto_pte = MiPteToProto(PointerPte);
|
|
//
|
|
// DbgPrint("page frame number 0x%lx proto PTE address 0x%lx\n",
|
|
// PointerPte->u.Hard.PageFrameNumber,*(PULONG)&proto_pte);
|
|
//
|
|
// DbgPrint(" 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 \n");
|
|
// DbgPrint(" +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \n");
|
|
// DbgPrint(" | pfn |c|p|t|r|r|d|a|c|p|o|w|v| \n");
|
|
// DbgPrint(" | |o|r|r|s|s|t|c|a|b|w|r|l| \n");
|
|
// DbgPrint(" | |w|o|n|v|v|y|c|c|o|n|t|d| \n");
|
|
// DbgPrint(" +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \n ");
|
|
// pte = PTETOULONG(the_pte);
|
|
//
|
|
// for (j = 0; j < 32; j++) {
|
|
// *(PULONG)& print_pte = pte;
|
|
// DbgPrint(" %lx",print_pte.bitties);
|
|
// pte = pte << 1;
|
|
// }
|
|
// DbgPrint("\n");
|
|
//
|
|
|
|
}
|
|
#endif //DBG
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
MiDumpWsl ( )
|
|
|
|
{
|
|
ULONG i;
|
|
PMMWSLE wsle;
|
|
|
|
DbgPrint("***WSLE cursize %lx frstfree %lx Min %lx Max %lx\n",
|
|
PsGetCurrentProcess()->Vm.WorkingSetSize,
|
|
MmWorkingSetList->FirstFree,
|
|
PsGetCurrentProcess()->Vm.MinimumWorkingSetSize,
|
|
PsGetCurrentProcess()->Vm.MaximumWorkingSetSize);
|
|
|
|
DbgPrint(" quota %lx firstdyn %lx last ent %lx next slot %lx\n",
|
|
MmWorkingSetList->Quota,
|
|
MmWorkingSetList->FirstDynamic,
|
|
MmWorkingSetList->LastEntry,
|
|
MmWorkingSetList->NextSlot);
|
|
|
|
wsle = MmWsle;
|
|
|
|
for (i = 0; i < MmWorkingSetList->LastEntry; i++) {
|
|
DbgPrint(" index %lx %lx\n",i,wsle->u1.Long);
|
|
wsle++;
|
|
}
|
|
return;
|
|
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
#if 0 //COMMENTED OUT!!!
|
|
VOID
|
|
MiFlushUnusedSections (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine rumages through the PFN database and attempts
|
|
to close any unused sections.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMPFN LastPfn;
|
|
PMMPFN Pfn1;
|
|
PSUBSECTION Subsection;
|
|
KIRQL OldIrql;
|
|
|
|
LOCK_PFN (OldIrql);
|
|
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage + 1);
|
|
LastPfn = MI_PFN_ELEMENT(MmHighestPhysicalPage);
|
|
|
|
while (Pfn1 < LastPfn) {
|
|
if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
|
|
if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
|
|
(Pfn1->u3.e1.PageLocation == StandbyPageList)) {
|
|
|
|
//
|
|
// Make sure the PTE is not waiting for I/O to complete.
|
|
//
|
|
|
|
if (MI_IS_PFN_DELETED (Pfn1)) {
|
|
|
|
Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
|
|
MiFlushUnusedSectionInternal (Subsection->ControlArea);
|
|
}
|
|
}
|
|
}
|
|
Pfn1++;
|
|
}
|
|
|
|
UNLOCK_PFN (OldIrql);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
MiFlushUnusedSectionInternal (
|
|
IN PCONTROL_AREA ControlArea
|
|
)
|
|
|
|
{
|
|
BOOLEAN result;
|
|
KIRQL OldIrql = APC_LEVEL;
|
|
|
|
if ((ControlArea->NumberOfMappedViews != 0) ||
|
|
(ControlArea->NumberOfSectionReferences != 0)) {
|
|
|
|
//
|
|
// The segment is currently in use.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The segment has no references, delete it. If the segment
|
|
// is already being deleted, set the event field in the control
|
|
// area and wait on the event.
|
|
//
|
|
|
|
if ((ControlArea->u.Flags.BeingDeleted) ||
|
|
(ControlArea->u.Flags.BeingCreated)) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Set the being deleted flag and up the number of mapped views
|
|
// for the segment. Upping the number of mapped views prevents
|
|
// the segment from being deleted and passed to the deletion thread
|
|
// while we are forcing a delete.
|
|
//
|
|
|
|
ControlArea->u.Flags.BeingDeleted = 1;
|
|
ControlArea->NumberOfMappedViews = 1;
|
|
|
|
//
|
|
// This is a page file backed or image Segment. The Segment is being
|
|
// deleted, remove all references to the paging file and physical memory.
|
|
//
|
|
|
|
UNLOCK_PFN (OldIrql);
|
|
|
|
MiCleanSection (ControlArea);
|
|
|
|
LOCK_PFN (OldIrql);
|
|
return TRUE;
|
|
}
|
|
#endif //0
|
|
|
|
|
|
#if DBG
|
|
|
|
#define ALLOC_SIZE ((ULONG)8*1024)
|
|
#define MM_SAVED_CONTROL 64
|
|
#define MM_KERN_MAP_SIZE 64
|
|
|
|
#define MM_NONPAGED_POOL_MARK ((PUCHAR)0xfffff123)
|
|
#define MM_PAGED_POOL_MARK ((PUCHAR)0xfffff124)
|
|
#define MM_KERNEL_STACK_MARK ((PUCHAR)0xfffff125)
|
|
|
|
extern ULONG MmSystemPtesStart[MaximumPtePoolTypes];
|
|
extern ULONG MmSystemPtesEnd[MaximumPtePoolTypes];
|
|
|
|
typedef struct _KERN_MAP {
|
|
ULONG StartVa;
|
|
ULONG EndVa;
|
|
PLDR_DATA_TABLE_ENTRY Entry;
|
|
} KERN_MAP, *PKERN_MAP;
|
|
|
|
ULONG
|
|
MiBuildKernelMap (
|
|
IN ULONG NumberOfElements,
|
|
IN OUT PKERN_MAP KernelMap
|
|
);
|
|
|
|
NTSTATUS
|
|
MmMemoryUsage (
|
|
IN PVOID Buffer,
|
|
IN ULONG Size,
|
|
IN ULONG Type,
|
|
OUT PULONG OutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine (debugging only) dumps the current memory usage by
|
|
walking the PFN database.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a buffer in which to copy the data.
|
|
|
|
Size - Supplies the size of the buffer.
|
|
|
|
Type - Supplies a value of 0 to dump everything,
|
|
a value of 1 to dump only valid pages.
|
|
|
|
OutLength - Returns how much data was written into the buffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMPFN LastPfn;
|
|
PMMPFN Pfn1;
|
|
PMMPFN Pfn2;
|
|
PSUBSECTION Subsection;
|
|
KIRQL OldIrql;
|
|
PSYSTEM_MEMORY_INFORMATION MemInfo;
|
|
PSYSTEM_MEMORY_INFO Info;
|
|
PSYSTEM_MEMORY_INFO InfoStart;
|
|
PSYSTEM_MEMORY_INFO InfoEnd;
|
|
PUCHAR String;
|
|
PUCHAR Master;
|
|
PCONTROL_AREA ControlArea;
|
|
BOOLEAN Found;
|
|
BOOLEAN FoundMap;
|
|
PMDL Mdl;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG Length;
|
|
PEPROCESS Process;
|
|
PUCHAR End;
|
|
PCONTROL_AREA SavedControl[MM_SAVED_CONTROL];
|
|
PSYSTEM_MEMORY_INFO SavedInfo[MM_SAVED_CONTROL];
|
|
ULONG j;
|
|
ULONG ControlCount = 0;
|
|
PUCHAR PagedSection = NULL;
|
|
ULONG Failed;
|
|
UCHAR PageFileMapped[] = "PageFile Mapped";
|
|
UCHAR MetaFile[] = "Fs Meta File";
|
|
UCHAR NoName[] = "No File Name";
|
|
UCHAR NonPagedPool[] = "NonPagedPool";
|
|
UCHAR PagedPool[] = "PagedPool";
|
|
UCHAR KernelStack[] = "Kernel Stack";
|
|
PUCHAR NameString;
|
|
KERN_MAP KernMap[MM_KERN_MAP_SIZE];
|
|
ULONG KernSize;
|
|
ULONG VirtualAddress;
|
|
PLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
|
|
Mdl = MmCreateMdl (NULL, Buffer, Size);
|
|
try {
|
|
|
|
MmProbeAndLockPages (Mdl, KeGetPreviousMode(), IoWriteAccess);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ExFreePool (Mdl);
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
MemInfo = MmGetSystemAddressForMdl (Mdl);
|
|
InfoStart = &MemInfo->Memory[0];
|
|
InfoEnd = InfoStart;
|
|
End = (PUCHAR)MemInfo + Size;
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage + 1);
|
|
LastPfn = MI_PFN_ELEMENT(MmHighestPhysicalPage);
|
|
|
|
KernSize = MiBuildKernelMap (MM_KERN_MAP_SIZE, &KernMap[0]);
|
|
|
|
LOCK_PFN (OldIrql);
|
|
|
|
while (Pfn1 < LastPfn) {
|
|
|
|
Info = InfoStart;
|
|
FoundMap = FALSE;
|
|
|
|
if ((Pfn1->u3.e1.PageLocation != FreePageList) &&
|
|
(Pfn1->u3.e1.PageLocation != ZeroedPageList) &&
|
|
(Pfn1->u3.e1.PageLocation != BadPageList)) {
|
|
|
|
if (Type == 1) {
|
|
if (Pfn1->u3.e1.PageLocation != ActiveAndValid) {
|
|
Pfn1++;
|
|
continue;
|
|
}
|
|
}
|
|
if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
|
|
Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
|
|
Master = (PUCHAR)Subsection->ControlArea;
|
|
ControlArea = Subsection->ControlArea;
|
|
if (!MmIsAddressValid(ControlArea)) {
|
|
DbgPrint ("Pfnp %lx not found %lx\n",Pfn1 - MmPfnDatabase,
|
|
(ULONG)Pfn1->PteAddress);
|
|
Pfn1++;
|
|
continue;
|
|
}
|
|
if (ControlArea->FilePointer != NULL) {
|
|
if (!MmIsAddressValid(ControlArea->FilePointer)) {
|
|
Pfn1++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
FoundMap = TRUE;
|
|
VirtualAddress = (ULONG)MiGetVirtualAddressMappedByPte (Pfn1->PteAddress);
|
|
|
|
if ((VirtualAddress >= (ULONG)MmPagedPoolStart) &&
|
|
(VirtualAddress <= (ULONG)MmPagedPoolEnd)) {
|
|
|
|
//
|
|
// This is paged pool, put it in the paged pool cell.
|
|
//
|
|
|
|
Master = MM_PAGED_POOL_MARK;
|
|
|
|
} else if ((VirtualAddress >= (ULONG)MmNonPagedPoolStart) &&
|
|
(VirtualAddress <= (ULONG)MmNonPagedPoolEnd)) {
|
|
|
|
//
|
|
// This is nonpaged pool, put it in the nonpaged pool cell.
|
|
//
|
|
|
|
Master = MM_NONPAGED_POOL_MARK;
|
|
|
|
} else {
|
|
FoundMap = FALSE;
|
|
for (j=0; j < KernSize; j++) {
|
|
if ((VirtualAddress >= KernMap[j].StartVa) &&
|
|
(VirtualAddress < KernMap[j].EndVa)) {
|
|
Master = (PUCHAR)&KernMap[j];
|
|
FoundMap = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FoundMap) {
|
|
if (((ULONG)Pfn1->PteAddress >= MmSystemPtesStart[SystemPteSpace]) &&
|
|
((ULONG)Pfn1->PteAddress <= MmSystemPtesEnd[SystemPteSpace])) {
|
|
|
|
//
|
|
// This is kernel stack.
|
|
//
|
|
|
|
Master = MM_KERNEL_STACK_MARK;
|
|
} else {
|
|
Pfn2 = MI_PFN_ELEMENT (Pfn1->PteFrame);
|
|
Master = (PUCHAR)Pfn2->PteFrame;
|
|
if (((ULONG)Master == 0) || ((ULONG)Master > MmHighestPhysicalPage)) {
|
|
DbgPrint ("Pfn %lx not found %lx\n",Pfn1 - MmPfnDatabase,
|
|
(ULONG)Pfn1->PteAddress);
|
|
Pfn1++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if there is already a master info block.
|
|
//
|
|
|
|
Found = FALSE;
|
|
while (Info < InfoEnd) {
|
|
if (Info->StringOffset == Master) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
Info += 1;
|
|
}
|
|
|
|
if (!Found) {
|
|
|
|
Info = InfoEnd;
|
|
InfoEnd += 1;
|
|
if ((PUCHAR)Info >= ((PUCHAR)InfoStart + Size) - sizeof(SYSTEM_MEMORY_INFO)) {
|
|
status = STATUS_DATA_OVERRUN;
|
|
goto Done;
|
|
}
|
|
|
|
RtlZeroMemory (Info, sizeof(*Info));
|
|
Info->StringOffset = Master;
|
|
}
|
|
|
|
if ((Pfn1->u3.e1.PageLocation == StandbyPageList) ||
|
|
(Pfn1->u3.e1.PageLocation == TransitionPage)) {
|
|
|
|
Info->TransitionCount += 1;
|
|
|
|
} else if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
|
|
(Pfn1->u3.e1.PageLocation == ModifiedNoWritePageList)) {
|
|
Info->ModifiedCount += 1;
|
|
|
|
} else {
|
|
Info->ValidCount += 1;
|
|
if (Type == 1) {
|
|
if ((Pfn1->PteAddress >= MiGetPdeAddress (0x0)) &&
|
|
(Pfn1->PteAddress <= MiGetPdeAddress (0xFFFFFFFF))) {
|
|
Info->PageTableCount += 1;
|
|
}
|
|
}
|
|
}
|
|
if (Type != 1) {
|
|
if ((Pfn1->PteAddress >= MiGetPdeAddress (0x0)) &&
|
|
(Pfn1->PteAddress <= MiGetPdeAddress (0xFFFFFFFF))) {
|
|
Info->PageTableCount += 1;
|
|
}
|
|
}
|
|
}
|
|
Pfn1++;
|
|
}
|
|
|
|
MemInfo->StringStart = (ULONG)Buffer + (PUCHAR)InfoEnd - (PUCHAR)MemInfo;
|
|
String = (PUCHAR)InfoEnd;
|
|
|
|
//
|
|
// Process strings...
|
|
//
|
|
|
|
Info = InfoStart;
|
|
while (Info < InfoEnd) {
|
|
if (Info->StringOffset > (PUCHAR)0x80000000) {
|
|
|
|
//
|
|
// Make sure this is not stacks or other areas.
|
|
//
|
|
|
|
Length = 0;
|
|
ControlArea = NULL;
|
|
|
|
if (Info->StringOffset == MM_NONPAGED_POOL_MARK) {
|
|
Length = 14;
|
|
NameString = NonPagedPool;
|
|
} else if (Info->StringOffset == MM_PAGED_POOL_MARK) {
|
|
Length = 14;
|
|
NameString = PagedPool;
|
|
} else if (Info->StringOffset == MM_KERNEL_STACK_MARK) {
|
|
Length = 14;
|
|
NameString = KernelStack;
|
|
} else if (((PUCHAR)Info->StringOffset >= (PUCHAR)&KernMap[0]) &&
|
|
((PUCHAR)Info->StringOffset <= (PUCHAR)&KernMap[MM_KERN_MAP_SIZE])) {
|
|
|
|
DataTableEntry = ((PKERN_MAP)Info->StringOffset)->Entry;
|
|
NameString = (PUCHAR)DataTableEntry->BaseDllName.Buffer;
|
|
Length = DataTableEntry->BaseDllName.Length;
|
|
} else {
|
|
//
|
|
// This points to a control area.
|
|
// Get the file name.
|
|
//
|
|
|
|
ControlArea = (PCONTROL_AREA)(Info->StringOffset);
|
|
NameString = (PUCHAR)&ControlArea->FilePointer->FileName.Buffer[0];
|
|
}
|
|
|
|
Info->StringOffset = NULL;
|
|
Failed = TRUE;
|
|
if (Length == 0) {
|
|
if (MmIsAddressValid (&ControlArea->FilePointer->FileName.Length)) {
|
|
Length = ControlArea->FilePointer->FileName.Length;
|
|
if (Length == 0) {
|
|
if (ControlArea->u.Flags.NoModifiedWriting) {
|
|
Length = 14;
|
|
NameString = MetaFile;
|
|
} else if (ControlArea->u.Flags.File == 0) {
|
|
NameString = PageFileMapped;
|
|
Length = 16;
|
|
|
|
} else {
|
|
NameString = NoName;
|
|
Length = 14;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((String+Length+2) >= End) {
|
|
status = STATUS_DATA_OVERRUN;
|
|
goto Done;
|
|
}
|
|
if (MmIsAddressValid (&NameString[0]) &&
|
|
MmIsAddressValid (&NameString[Length - 1])) {
|
|
RtlMoveMemory (String,
|
|
NameString,
|
|
Length );
|
|
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
|
|
String[Length] = 0;
|
|
String[Length + 1] = 0;
|
|
String += Length + 2;
|
|
Failed = FALSE;
|
|
}
|
|
if (Failed && ControlArea) {
|
|
if (!(ControlArea->u.Flags.BeingCreated ||
|
|
ControlArea->u.Flags.BeingDeleted) &&
|
|
(ControlCount < MM_SAVED_CONTROL)) {
|
|
SavedControl[ControlCount] = ControlArea;
|
|
SavedInfo[ControlCount] = Info;
|
|
ControlArea->NumberOfSectionReferences += 1;
|
|
ControlCount += 1;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Process...
|
|
//
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (Info->StringOffset);
|
|
Info->StringOffset = NULL;
|
|
if ((String+16) >= End) {
|
|
status = STATUS_DATA_OVERRUN;
|
|
goto Done;
|
|
}
|
|
|
|
Process = (PEPROCESS)Pfn1->u1.Event;
|
|
if (Pfn1->PteAddress == MiGetPteAddress (PDE_BASE)) {
|
|
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
|
|
RtlMoveMemory (String,
|
|
&Process->ImageFileName[0],
|
|
16);
|
|
String += 16;
|
|
} else {
|
|
|
|
Info->StringOffset = PagedSection;
|
|
if (PagedSection == NULL) {
|
|
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
|
|
RtlMoveMemory (String,
|
|
&PageFileMapped,
|
|
16);
|
|
PagedSection = Info->StringOffset;
|
|
String += 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
Info += 1;
|
|
}
|
|
|
|
Done:
|
|
UNLOCK_PFN (OldIrql);
|
|
while (ControlCount != 0) {
|
|
|
|
//
|
|
// Process all the pagable name strings.
|
|
//
|
|
|
|
ControlCount -= 1;
|
|
ControlArea = SavedControl[ControlCount];
|
|
Info = SavedInfo[ControlCount];
|
|
NameString = (PUCHAR)&ControlArea->FilePointer->FileName.Buffer[0];
|
|
Length = ControlArea->FilePointer->FileName.Length;
|
|
if (Length == 0) {
|
|
if (ControlArea->u.Flags.NoModifiedWriting) {
|
|
Length = 12;
|
|
NameString = MetaFile;
|
|
} else if (ControlArea->u.Flags.File == 0) {
|
|
NameString = PageFileMapped;
|
|
Length = 16;
|
|
|
|
} else {
|
|
NameString = NoName;
|
|
Length = 12;
|
|
}
|
|
}
|
|
if ((String+Length+2) >= End) {
|
|
status = STATUS_DATA_OVERRUN;
|
|
}
|
|
if (status != STATUS_DATA_OVERRUN) {
|
|
RtlMoveMemory (String,
|
|
NameString,
|
|
Length );
|
|
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
|
|
String[Length] = 0;
|
|
String[Length + 1] = 0;
|
|
String += Length + 2;
|
|
}
|
|
|
|
LOCK_PFN (OldIrql);
|
|
ControlArea->NumberOfSectionReferences -= 1;
|
|
MiCheckForControlAreaDeletion (ControlArea);
|
|
UNLOCK_PFN (OldIrql);
|
|
}
|
|
*OutLength = ((PUCHAR)String - (PUCHAR)MemInfo);
|
|
MmUnlockPages (Mdl);
|
|
ExFreePool (Mdl);;
|
|
return status;
|
|
}
|
|
#else //DBG
|
|
|
|
NTSTATUS
|
|
MmMemoryUsage (
|
|
IN PVOID Buffer,
|
|
IN ULONG Size,
|
|
IN ULONG Type,
|
|
OUT PULONG OutLength
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
|
|
#if DBG
|
|
ULONG
|
|
MiBuildKernelMap (
|
|
IN ULONG NumberOfElements,
|
|
IN OUT PKERN_MAP KernelMap
|
|
)
|
|
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PLIST_ENTRY NextEntry;
|
|
PLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
ULONG i = 0;
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceShared (&PsLoadedModuleResource, TRUE);
|
|
|
|
NextEntry = PsLoadedModuleList.Flink;
|
|
do {
|
|
|
|
DataTableEntry = CONTAINING_RECORD(NextEntry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks);
|
|
|
|
KernelMap[i].Entry = DataTableEntry;
|
|
KernelMap[i].StartVa = (ULONG)DataTableEntry->DllBase;
|
|
KernelMap[i].EndVa = KernelMap[i].StartVa +
|
|
(ULONG)DataTableEntry->SizeOfImage;
|
|
i += 1;
|
|
if (i == NumberOfElements) {
|
|
break;
|
|
}
|
|
Next = DataTableEntry->InLoadOrderLinks.Flink;
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
} while (NextEntry != &PsLoadedModuleList);
|
|
|
|
ExReleaseResource (&PsLoadedModuleResource);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return i;
|
|
}
|
|
#endif //DBG
|
|
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
MiFlushCache (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine (debugging only) flushes the "cache" by moving
|
|
all pages from the standby list to the free list. Modified
|
|
pages are not effected.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
ULONG Page;
|
|
|
|
LOCK_PFN (OldIrql);
|
|
|
|
while (MmPageLocationList[StandbyPageList]->Total != 0) {
|
|
|
|
Page = MiRemovePageFromList (MmPageLocationList[StandbyPageList]);
|
|
|
|
//
|
|
// A page has been removed from the standby list. The
|
|
// PTE which refers to this page is currently in the transtion
|
|
// state and must have its original contents restored to free
|
|
// the the last reference to this physical page.
|
|
//
|
|
|
|
MiRestoreTransitionPte (Page);
|
|
|
|
//
|
|
// Put the page into the free list.
|
|
//
|
|
|
|
MiInsertPageInList (MmPageLocationList[FreePageList], Page);
|
|
}
|
|
|
|
UNLOCK_PFN (OldIrql);
|
|
return;
|
|
}
|
|
VOID
|
|
MiDumpReferencedPages (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine (debugging only) dumps all PFN entries which appear
|
|
to be locked in memory for i/o.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
PMMPFN Pfn1;
|
|
PMMPFN PfnLast;
|
|
|
|
LOCK_PFN (OldIrql);
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage);
|
|
PfnLast = MI_PFN_ELEMENT (MmHighestPhysicalPage);
|
|
|
|
while (Pfn1 <= PfnLast) {
|
|
|
|
if ((Pfn1->u2.ShareCount == 0) && (Pfn1->u3.e2.ReferenceCount != 0)) {
|
|
MiFormatPfn (Pfn1);
|
|
}
|
|
|
|
if (Pfn1->u3.e2.ReferenceCount > 1) {
|
|
MiFormatPfn (Pfn1);
|
|
}
|
|
|
|
Pfn1 += 1;
|
|
}
|
|
|
|
UNLOCK_PFN (OldIrql);
|
|
return;
|
|
}
|
|
|
|
#endif //DBG
|