/*++ Copyright (c) 1992 Microsoft Corporation Module Name: wsle.c Abstract: WinDbg Extension Api Author: Lou Perazzoli (LouP) 14-Mar-1994 Environment: User Mode. --*/ #include "precomp.h" #pragma hdrstop #define PACKET_MAX_SIZE 4000 #define NUMBER_OF_WSLE_TO_READ 1000 // ((PACKET_MAX_SIZE/sizeof(MMWSLE))-1) USHORT GetPfnRefCount( IN ULONG64 PageFrameNumber ); DECLARE_API( wsle ) /*++ Routine Description: Dumps all wsles for process. Arguments: args - Address Flags Return Value: None --*/ { ULONG Result; ULONG Flags; ULONG index; ULONG64 WorkingSet; ULONG64 WsleBase; ULONG64 Va; ULONG64 Wsle; ULONG next; ULONG j; ULONG k; PCHAR WsleArray; ULONG64 WsleStart; ULONG ReadCount; ULONG result; ULONG found; ULONG64 PteAddress; ULONG SizeofWsle; ULONG64 Quota, HashTable; ULONG FirstFree, FirstDynamic, LastEntry, NextSlot, LastInitializedWsle; ULONG NonDirectCount, HashTableSize; PCHAR pc; Flags = 0; WorkingSet = 0; Flags = (ULONG) GetExpression(args); pc = strchr(args, ' '); WorkingSet = pc ? GetExpression(pc) : 0; if (WorkingSet == 0) { if (TargetMachine == IMAGE_FILE_MACHINE_I386) { WorkingSet = GetPointerValue("nt!MmWorkingSetList"); } else if (TargetMachine == IMAGE_FILE_MACHINE_IA64) { WorkingSet = (ULONG64)0x6FC00a02000; } else if (TargetMachine == IMAGE_FILE_MACHINE_AMD64) { WorkingSet = (ULONG64)0xFFFFF70000082000; } else { dprintf ("No default WSL for target machine %x\n", TargetMachine); return E_INVALIDARG; } } if (GetFieldValue(WorkingSet, "nt!_MMWSL", "Quota", Quota)) { dprintf("%08p: Unable to get contents of WSL\n",WorkingSet ); return E_INVALIDARG; } if (GetTypeSize("nt!_MMWSL") == 0) { dprintf("Type MMWSL not found.\n"); return E_INVALIDARG; } GetFieldValue(WorkingSet,"nt!_MMWSL","FirstDynamic", FirstDynamic); GetFieldValue(WorkingSet,"nt!_MMWSL","FirstFree", FirstFree); GetFieldValue(WorkingSet,"nt!_MMWSL","Wsle", Wsle); GetFieldValue(WorkingSet,"nt!_MMWSL","LastEntry", LastEntry); GetFieldValue(WorkingSet,"nt!_MMWSL","NextSlot", NextSlot); GetFieldValue(WorkingSet,"nt!_MMWSL","LastInitializedWsle", LastInitializedWsle); GetFieldValue(WorkingSet,"nt!_MMWSL","NonDirectCount", NonDirectCount); GetFieldValue(WorkingSet,"nt!_MMWSL","HashTableSize", HashTableSize); GetFieldValue(WorkingSet,"nt!_MMWSL","HashTable", HashTable); dprintf ("\nWorking Set @ %8p\n", WorkingSet); dprintf (" Quota: %8I64lx FirstFree: %8lx FirstDynamic: %8lx\n", Quota, FirstFree, FirstDynamic); dprintf (" LastEntry %8lx NextSlot: %8lx LastInitialized %8lx\n", LastEntry, NextSlot, LastInitializedWsle); dprintf (" NonDirect %8lx HashTable: %8p HashTableSize: %8lx\n", NonDirectCount, HashTable, HashTableSize); if (Flags == 0) { return E_INVALIDARG; } SizeofWsle = GetTypeSize("nt!_MMWSLE"); if (SizeofWsle == 0) { dprintf("Type _MMWSLE not found.\n"); return E_INVALIDARG; } if (Flags == 7) { BOOL FirstTime = TRUE; // // Check free entries in the working set list. // WsleArray = VirtualAlloc (NULL, (LastInitializedWsle + 1) * SizeofWsle, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); // // Copy the working set list over to the debugger. // if (WsleArray == NULL) { dprintf("Unable to get allocate memory of %ld bytes\n", (LastInitializedWsle + 1) * SizeofWsle); return E_INVALIDARG; } dprintf("\nVirtual Address Age Locked ReferenceCount\n"); WsleStart = Wsle; for (j = 0; j <= LastInitializedWsle; j += NUMBER_OF_WSLE_TO_READ) { if ( CheckControlC() ) { VirtualFree (WsleArray,0,MEM_RELEASE); return E_INVALIDARG; } ReadCount = (LastInitializedWsle + 1 - j ) > NUMBER_OF_WSLE_TO_READ ? NUMBER_OF_WSLE_TO_READ : LastInitializedWsle + 1 - j; ReadCount *= SizeofWsle; // // Enough to read and forget - KD will cache the data // if ( !ReadMemory( WsleStart + j*SizeofWsle, WsleArray + j*SizeofWsle, ReadCount, &result) ) { dprintf("Unable to get Wsle table block - " "address %lx - count %lu - page %lu\n", WsleStart + j*SizeofWsle, ReadCount, j); VirtualFree (WsleArray,0,MEM_RELEASE); return E_INVALIDARG; } for (k=0; k> MM_FREE_WSLE_SHIFT) == j) { found = TRUE; #if 0 dprintf(" free entry located @ index %ld. %lx %ld. %lx\n", j, WsleArray[j].u1.Long,k,WsleArray[k]); #endif break; } } } if (!found) { if (FirstFree == j) { // dprintf("first index found\n"); } else { GetFieldValue(WsleToread, "nt!_MMWSLE", "u1.VirtualAddress", Long); dprintf(" free entry not located @ index %ld. %p\n", j, Long); } } } else { ULONG PteValid; GetFieldValue(WsleToread, "nt!_MMWSLE", "u1.VirtualAddress", Long); Va = Long; PteAddress = DbgGetPteAddress (Va); if (!GetFieldValue(PteAddress, "nt!_MMPTE", "u.Hard.Valid", PteValid) ) { if (PteValid == 0) { dprintf(" cannot find valid PTE for WS index %d, VA %p\n", j, Long); } else { ULONG64 PageFrameNumber; USHORT ReferenceCount; GetFieldValue( PteAddress, "nt!_MMPTE", "u.Hard.PageFrameNumber", PageFrameNumber); ReferenceCount = GetPfnRefCount (PageFrameNumber); GetFieldValue(WsleToread, "nt!_MMWSLE", "u1.e1.Age", Age); GetFieldValue(WsleToread, "nt!_MMWSLE", "u1.e1.LockedInWs", LockedInWs); GetFieldValue(WsleToread, "nt!_MMWSLE", "u1.LockedInMemory", LockedInMemory); dprintf("%16p %2u %8ld %8ld\n", Long, Age, (LockedInWs | LockedInMemory) ? 1 : 0, ReferenceCount); } } else { dprintf(" cannot find valid PDE for WS index %d, VA %p\n", j, Long); } } } VirtualFree (WsleArray,0,MEM_RELEASE); } else { ULONG64 nextLong; next = FirstFree; WsleBase = Wsle; while (next != (ULONG) WSLE_NULL_INDEX) { if (CheckControlC()) { return E_INVALIDARG; } if ( GetFieldValue( WsleBase + SizeofWsle*next, "nt!_MMWSLE", "u1.VirtualAddress", nextLong) ) { dprintf("%08p: Unable to get contents of wsle\n", WsleBase+SizeofWsle*next ); return E_INVALIDARG; } dprintf("index %8lx value %8p\n", next, nextLong); next = (ULONG) (nextLong >> MM_FREE_WSLE_SHIFT); } } return S_OK; } typedef struct _MMSECTION_FLAGS { unsigned BeingDeleted : 1; unsigned BeingCreated : 1; unsigned BeingPurged : 1; unsigned NoModifiedWriting : 1; unsigned FailAllIo : 1; unsigned Image : 1; unsigned Based : 1; unsigned File : 1; unsigned Networked : 1; unsigned NoCache : 1; unsigned PhysicalMemory : 1; unsigned CopyOnWrite : 1; unsigned Reserve : 1; // not a spare bit! unsigned Commit : 1; unsigned FloppyMedia : 1; unsigned WasPurged : 1; unsigned UserReference : 1; unsigned GlobalMemory : 1; unsigned DeleteOnClose : 1; unsigned FilePointerNull : 1; unsigned DebugSymbolsLoaded : 1; unsigned SetMappedFileIoComplete : 1; unsigned CollidedFlush : 1; unsigned NoChange : 1; unsigned HadUserReference : 1; unsigned ImageMappedInSystemSpace : 1; unsigned UserWritable : 1; unsigned Accessed : 1; unsigned GlobalOnlyPerSession : 1; unsigned Rom : 1; unsigned filler : 2; } MMSECTION_FLAGS; typedef struct _MMSUBSECTION_FLAGS { unsigned ReadOnly : 1; unsigned ReadWrite : 1; unsigned CopyOnWrite : 1; unsigned GlobalMemory: 1; unsigned Protection : 5; unsigned LargePages : 1; unsigned StartingSector4132 : 10; // 2 ** (42+12) == 4MB*4GB == 16K TB unsigned SectorEndOffset : 12; } MMSUBSECTION_FLAGS; DECLARE_API( ca ) /*++ Routine Description: Dumps a control area. Arguments: args - Address Flags Return Value: None --*/ { LARGE_INTEGER StartingSector; ULONG64 ControlAreaVa; ULONG64 SubsectionVa; ULONG ControlAreaSize; ULONG LargeControlAreaSize; ULONG SubsectionSize; ULONG SubsectionCount; ULONG64 Segment; ULONG64 FileObject; ULONG NumberOfSubsections; MMSECTION_FLAGS ControlAreaFlags; MMSUBSECTION_FLAGS SubsectionFlags; LOGICAL MappedDataFile; LOGICAL PrintedSomething; ControlAreaVa = GetExpression(args); dprintf("\n"); dprintf("ControlArea @%08p\n", ControlAreaVa); ControlAreaSize = GetTypeSize("nt!_CONTROL_AREA"); if (ControlAreaSize == 0) { dprintf("Type CONTROL_AREA not found.\n"); return E_INVALIDARG; } InitTypeRead(ControlAreaVa, nt!_CONTROL_AREA); Segment = ReadField(Segment); NumberOfSubsections = (ULONG)ReadField(NumberOfSubsections); FileObject = ReadField(FilePointer); dprintf (" Segment: %08p Flink %8p Blink %8p\n", Segment, ReadField(DereferenceList.Flink), ReadField(DereferenceList.Blink)); dprintf (" Section Ref %8lx Pfn Ref %8lx Mapped Views %8lx\n", (ULONG) ReadField(NumberOfSectionReferences), (ULONG) ReadField(NumberOfPfnReferences), (ULONG) ReadField(NumberOfMappedViews)); dprintf (" User Ref %8lx Subsections %8lx Flush Count %8lx\n", (ULONG) ReadField(NumberOfUserReferences), NumberOfSubsections, (USHORT) ReadField(FlushInProgressCount)); dprintf (" File Object %08p ModWriteCount%7lx System Views %8lx\n", FileObject, (USHORT) ReadField(ModifiedWriteCount), (USHORT) ReadField(NumberOfSystemCacheViews)); dprintf (" WaitForDel %8p\n", ReadField(WaitingForDeletion)); GetFieldValue(ControlAreaVa, "nt!_CONTROL_AREA", "u.LongFlags", ControlAreaFlags); dprintf (" Flags (%lx) ", ControlAreaFlags); if (ControlAreaFlags.BeingDeleted) { dprintf("BeingDeleted "); } if (ControlAreaFlags.BeingCreated) { dprintf("BeingCreated "); } if (ControlAreaFlags.BeingPurged) { dprintf("BeingPurged "); } if (ControlAreaFlags.NoModifiedWriting) { dprintf("NoModifiedWriting "); } if (ControlAreaFlags.FailAllIo) { dprintf("FailAllIo "); } if (ControlAreaFlags.Image) { dprintf("Image "); } if (ControlAreaFlags.Based) { dprintf("Based "); } if (ControlAreaFlags.File) { dprintf("File "); } if (ControlAreaFlags.Networked) { dprintf("Networked "); } if (ControlAreaFlags.NoCache) { dprintf("NoCache "); } if (ControlAreaFlags.PhysicalMemory) { dprintf("PhysicalMemory "); } if (ControlAreaFlags.CopyOnWrite) { dprintf("CopyOnWrite "); } if (ControlAreaFlags.Reserve) { dprintf("Reserve "); } if (ControlAreaFlags.Commit) { dprintf("Commit "); } if (ControlAreaFlags.FloppyMedia) { dprintf("FloppyMedia "); } if (ControlAreaFlags.WasPurged) { dprintf("WasPurged "); } if (ControlAreaFlags.UserReference) { dprintf("UserReference "); } if (ControlAreaFlags.GlobalMemory) { dprintf("GlobalMemory "); } if (ControlAreaFlags.DeleteOnClose) { dprintf("DeleteOnClose "); } if (ControlAreaFlags.FilePointerNull) { dprintf("FilePointerNull "); } if (ControlAreaFlags.DebugSymbolsLoaded) { dprintf("DebugSymbolsLoaded "); } if (ControlAreaFlags.SetMappedFileIoComplete) { dprintf("SetMappedFileIoComplete "); } if (ControlAreaFlags.CollidedFlush) { dprintf("CollidedFlush "); } if (ControlAreaFlags.NoChange) { dprintf("NoChange "); } if (ControlAreaFlags.HadUserReference) { dprintf("HadUserReference "); } if (ControlAreaFlags.ImageMappedInSystemSpace) { dprintf("ImageMappedInSystemSpace "); } if (ControlAreaFlags.UserWritable) { dprintf("UserWritable "); } if (ControlAreaFlags.Accessed) { dprintf("Accessed "); } if (ControlAreaFlags.GlobalOnlyPerSession) { dprintf("GlobalOnlyPerSession "); } if (ControlAreaFlags.Rom) { dprintf("Rom "); } dprintf ("\n\n"); MappedDataFile = FALSE; // // Dump the file object's name if there is one and it's resident. // if (FileObject != 0) { ULONG64 FileNameLength; ULONG64 FileNameBuffer; PUCHAR tempbuffer; ULONG result; UNICODE_STRING unicodeString; if (GetTypeSize("nt!_FILE_OBJECT") == 0) { dprintf("Type FILE_OBJECT not found.\n"); return E_INVALIDARG; } InitTypeRead(FileObject, nt!_FILE_OBJECT); FileNameBuffer = ReadField(FileName.Buffer); unicodeString.Length = (USHORT) ReadField(FileName.Length); tempbuffer = LocalAlloc(LPTR, unicodeString.Length); unicodeString.Buffer = (PWSTR)tempbuffer; unicodeString.MaximumLength = unicodeString.Length; if (FileNameBuffer == 0) { dprintf("\tNo Name for File\n"); } else if (!ReadMemory ( FileNameBuffer, tempbuffer, unicodeString.Length, &result)) { dprintf("\tFile Name paged out\n"); } else { dprintf("\tFile: %wZ\n", &unicodeString); } LocalFree(tempbuffer); if (ControlAreaFlags.Image == 0) { MappedDataFile = TRUE; } } // // Dump the segment information. // dprintf("\nSegment @ %08p:\n", Segment); if (MappedDataFile == FALSE) { if (GetTypeSize("nt!_SEGMENT") == 0) { dprintf("Type SEGMENT not found.\n"); return E_INVALIDARG; } InitTypeRead(Segment, nt!_SEGMENT); } else { if (GetTypeSize("nt!_MAPPED_FILE_SEGMENT") == 0) { dprintf("Type MAPPED_FILE_SEGMENT not found.\n"); return E_INVALIDARG; } InitTypeRead(Segment, nt!_MAPPED_FILE_SEGMENT); } dprintf(" ControlArea %08p Total Ptes %8lx NonExtendPtes %8lx\n", ReadField(ControlArea), (ULONG) ReadField(TotalNumberOfPtes), (ULONG) ReadField(NonExtendedPtes)); if (ControlAreaVa != ReadField(ControlArea)) { dprintf("SEGMENT is corrupt - bad control area backlink.\n"); return E_INVALIDARG; } dprintf(" WriteUserRef %8lx SizeOfSegment %I64x PTE Template %I64X\n", (ULONG) ReadField(WritableUserReferences), ReadField(SizeOfSegment), ReadField(SegmentPteTemplate.u.Long)); dprintf(" Committed %8p Extend Info %8p Image Base %8p\n", ReadField(NumberOfCommittedPages), ReadField(ExtendInfo), ReadField(SystemImageBase)); dprintf(" Based Addr %8p\n", ReadField(BasedAddress)); if (MappedDataFile == FALSE) { if (ControlAreaFlags.Image == 1) { dprintf(" Image commit %8p Image Info. %8p", ReadField(ImageCommitment), ReadField(ImageInformation)); } else { dprintf(" CreatingProcess %8p FirstMappedVa %8p", ReadField(u1.CreatingProcess), ReadField(u2.FirstMappedVa)); } dprintf(" ProtoPtes %08p\n", ReadField(PrototypePte)); } // // Dump the subsection(s). // SubsectionSize = GetTypeSize("nt!_SUBSECTION"); if (SubsectionSize == 0) { dprintf("Type SUBSECTION not found.\n"); return E_INVALIDARG; } LargeControlAreaSize = GetTypeSize("nt!_LARGE_CONTROL_AREA"); if (LargeControlAreaSize == 0) { dprintf("Type LARGE_CONTROL_AREA not found.\n"); return E_INVALIDARG; } if (ControlAreaFlags.GlobalOnlyPerSession) { SubsectionVa = ControlAreaVa + LargeControlAreaSize; } else { SubsectionVa = ControlAreaVa + ControlAreaSize; } SubsectionCount = 0; do { if (CheckControlC()) { return E_INVALIDARG; } InitTypeRead(SubsectionVa, nt!_SUBSECTION); SubsectionCount += 1; dprintf("\nSubsection %ld. @ %8p\n", SubsectionCount, SubsectionVa); GetFieldValue(SubsectionVa, "nt!_SUBSECTION", "u.LongFlags", SubsectionFlags); StartingSector.LowPart = (ULONG)ReadField(StartingSector); StartingSector.HighPart = (LONG)SubsectionFlags.StartingSector4132; dprintf(" ControlArea: %08p Starting Sector %I64X Number Of Sectors %lx\n", ReadField(ControlArea), StartingSector, (ULONG) ReadField(NumberOfFullSectors)); dprintf(" Base Pte %08p Ptes In subsect %8lx Unused Ptes %8lx\n", ReadField(SubsectionBase), (ULONG) ReadField(PtesInSubsection), (ULONG) ReadField(UnusedPtes)); dprintf(" Flags %8lx Sector Offset %8lx Protection %8lx\n", SubsectionFlags, SubsectionFlags.SectorEndOffset, SubsectionFlags.Protection); PrintedSomething = FALSE; if (SubsectionFlags.ReadOnly) { if (PrintedSomething == FALSE) { dprintf(" "); } PrintedSomething = TRUE; dprintf("ReadOnly "); } if (SubsectionFlags.ReadWrite) { if (PrintedSomething == FALSE) { dprintf(" "); } PrintedSomething = TRUE; dprintf("ReadWrite"); } if (SubsectionFlags.CopyOnWrite) { if (PrintedSomething == FALSE) { dprintf(" "); } PrintedSomething = TRUE; dprintf("CopyOnWrite "); } if (SubsectionFlags.GlobalMemory) { if (PrintedSomething == FALSE) { dprintf(" "); } PrintedSomething = TRUE; dprintf("GlobalMemory "); } if (SubsectionFlags.LargePages) { if (PrintedSomething == FALSE) { dprintf(" "); } PrintedSomething = TRUE; dprintf("Large Pages"); } if (PrintedSomething == TRUE) { dprintf("\n"); } if (MappedDataFile == TRUE) { InitTypeRead(SubsectionVa, nt!_MSUBSECTION); dprintf(" Flink %08p Blink %08p MappedViews %8x\n", ReadField(DereferenceList.Flink), ReadField(DereferenceList.Blink), (ULONG) ReadField(NumberOfMappedViews)); dprintf(" SubsectionDataFlags %8x\n", (ULONG) ReadField(u2.LongFlags2)); } SubsectionVa = ReadField(NextSubsection); } while (SubsectionVa != 0); return S_OK; }