|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
session.cxx
Abstract:
This file contains the routines to handle session.
Author:
Jason Hartman (JasonHa) 2000-09-28
Environment:
User Mode
--*/
#include "precomp.hxx"
#define STRSAFE_NO_DEPRECATE
#include "strsafe.h"
//
// Special defines
//
// ddk\inc\ntddk.h:
#define PROTECTED_POOL 0x80000000
// base\ntos\inc\pool.h:
#define POOL_QUOTA_MASK 8
// Information about how to handle a process listing
// and status about how it was handled.
class CProcessListing { public: IN ULONG m_cListLimit; IN OUT ULONG m_cTotal; IN OUT ULONG m_cProcessed; IN OUT ULONG64 m_oStartProcess; OUT ULONG64 m_oLastProcess;
public: CProcessListing(ULONG cListLimit = -1) { m_cListLimit = cListLimit; m_cTotal = 0; m_cProcessed = 0; m_oStartProcess = 0; m_oLastProcess = 0; }
void PrepareForNextListing() { m_oStartProcess = m_oLastProcess; }
BOOL Unprocessed() { return (m_cTotal > m_cProcessed); } };
#define SESSION_SEARCH_LIMIT 50
ULONG SessionId = CURRENT_SESSION; CHAR SessionStr[16] = "CURRENT";
CachedType HwPte = { FALSE, "NT!HARDWARE_PTE", 0, 0, 0 };
#define NUM_CACHED_SESSIONS 8
struct { ULONG UniqueState; ULONG64 SessionSpaceAddr; } CachedSession[NUM_CACHED_SESSIONS+1] = { { 0, 0 } }; ULONG ExtraCachedSessionId;
#define NUM_CACHED_DIR_BASES 8
struct { ULONG UniqueState; ULONG64 PageDirBase; } CachedDirBase[NUM_CACHED_DIR_BASES+1] = { { FALSE, 0} };
struct { ULONG UniqueState; ULONG64 PhysAddr; ULONG64 Data; } CachedPhysAddr[2] = { { 0, 0, 0} };
BitFieldInfo *MMPTEValid = NULL; BitFieldInfo *MMPTEProto = NULL; BitFieldInfo *MMPTETrans = NULL; BitFieldInfo *MMPTEX86LargePage = NULL; BitFieldInfo *MMPTEpfn = NULL;
HRESULT GetBitMap( PDEBUG_CLIENT Client, ULONG64 pBitMap, PRTL_BITMAP *pBitMapOut );
HRESULT FreeBitMap( PRTL_BITMAP pBitMap );
HRESULT OutputSessionProcesses( PDEBUG_CLIENT Client, OutputControl *OutCtl, ULONG Session, PCSTR args, CProcessListing *pProcessListing );
/**************************************************************************\
* * Routine Name: * * SessionInit * * Routine Description: * * Initialize or reinitialize information to be read from symbols files * * Arguments: * * Client - PDEBUG_CLIENT * * Return Value: * * none * \**************************************************************************/
void SessionInit(PDEBUG_CLIENT Client) { for (int s = 0; s < sizeof(CachedSession)/sizeof(CachedSession[0]); s++) { CachedSession[s].UniqueState = INVALID_UNIQUE_STATE; } ExtraCachedSessionId = INVALID_SESSION;
for (int s = 0; s < sizeof(CachedDirBase)/sizeof(CachedDirBase[0]); s++) { CachedDirBase[s].UniqueState = INVALID_UNIQUE_STATE; }
if (MMPTEValid != NULL) MMPTEValid->Valid = FALSE; if (MMPTEProto != NULL) MMPTEProto->Valid = FALSE; if (MMPTETrans != NULL) MMPTETrans->Valid = FALSE; if (MMPTEX86LargePage != NULL) MMPTEX86LargePage->Valid = FALSE; if (MMPTEpfn != NULL) MMPTEpfn->Valid = FALSE;
CachedPhysAddr[0].UniqueState = INVALID_UNIQUE_STATE; CachedPhysAddr[1].UniqueState = INVALID_UNIQUE_STATE;
return; }
/**************************************************************************\
* * Routine Name: * * SessionExit * * Routine Description: * * Clean up any outstanding allocations or references * * Arguments: * * none * * Return Value: * * none * \**************************************************************************/
void SessionExit() { if (MMPTEValid != NULL) { delete MMPTEValid; MMPTEValid = NULL; }
if (MMPTEProto != NULL) { delete MMPTEProto; MMPTEProto = NULL; }
if (MMPTETrans != NULL) { delete MMPTETrans; MMPTETrans = NULL; }
if (MMPTEX86LargePage != NULL) { delete MMPTEX86LargePage; MMPTEX86LargePage = NULL; }
if (MMPTEpfn != NULL) { delete MMPTEpfn; MMPTEpfn = NULL; }
return; }
/**************************************************************************\
* * Routine Name: * * GetMMPTEValid * * Routine Description: * * Extract Valid value from MMPTE * \**************************************************************************/
HRESULT GetMMPTEValid( PDEBUG_CLIENT Client, ULONG64 MMPTE64, PULONG64 Valid ) { HRESULT hr = S_FALSE;
if (MMPTEValid == NULL) { MMPTEValid = new BitFieldInfo; }
if (MMPTEValid == NULL) { hr = E_OUTOFMEMORY; } else if (MMPTEValid->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, MMPTEValid); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read Valid bit field from symbol file
if (OutState.Execute("dt NT!HARDWARE_PTE Valid") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { MMPTEValid->Valid = MMPTEValid->Compose(0, 1); hr = MMPTEValid->Valid ? S_OK : S_FALSE; } } }
if (Valid != NULL) { if (hr == S_OK) { *Valid = (MMPTE64 & MMPTEValid->Mask) >> MMPTEValid->BitPos; } else { *Valid = 0; } }
return hr; }
/**************************************************************************\
* * Routine Name: * * GetMMPTEProto * * Routine Description: * * Extract Prototype value from MMPTE * \**************************************************************************/
HRESULT GetMMPTEProto( PDEBUG_CLIENT Client, ULONG64 MMPTE64, PULONG64 Proto ) { HRESULT hr = S_FALSE;
if (MMPTEProto == NULL) { MMPTEProto = new BitFieldInfo; }
if (MMPTEProto == NULL) { hr = E_OUTOFMEMORY; } else if (MMPTEProto->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, MMPTEProto); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read Prototype bit field from symbol file
if (OutState.Execute("dt NT!MMPTE_PROTOTYPE Prototype") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { switch (TargetMachine) { case IMAGE_FILE_MACHINE_I386: MMPTEProto->Valid = MMPTEProto->Compose(10, 1); break; case IMAGE_FILE_MACHINE_IA64: MMPTEProto->Valid = MMPTEProto->Compose(1, 1); break; default: { OutputControl OutCtl(Client); OutCtl.OutErr("Couldn't find MMPTE Prototype bit in type info.\n"); } }
hr = MMPTEProto->Valid ? S_OK : S_FALSE; } } }
if (Proto != NULL) { if (hr == S_OK) { *Proto = (MMPTE64 & MMPTEProto->Mask) >> MMPTEProto->BitPos; } else { *Proto = 0; } }
return hr; }
/**************************************************************************\
* * Routine Name: * * GetMMPTETrans * * Routine Description: * * Extract Transition value from MMPTE * \**************************************************************************/
HRESULT GetMMPTETrans( PDEBUG_CLIENT Client, ULONG64 MMPTE64, PULONG64 Trans ) { HRESULT hr = S_FALSE;
if (MMPTETrans == NULL) { MMPTETrans = new BitFieldInfo; }
if (MMPTETrans == NULL) { hr = E_OUTOFMEMORY; } else if (MMPTETrans->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, MMPTETrans); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read Transition bit field from symbol file
if (OutState.Execute("dt NT!PROTOTYPE_PTE Transition") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { switch (TargetMachine) { case IMAGE_FILE_MACHINE_I386: MMPTETrans->Valid = MMPTETrans->Compose(11, 1); break; case IMAGE_FILE_MACHINE_IA64: MMPTETrans->Valid = MMPTETrans->Compose(7, 1); break; default: { OutputControl OutCtl(Client); OutCtl.OutErr("Couldn't find MMPTE Transition bit in type info.\n"); } }
hr = MMPTETrans->Valid ? S_OK : S_FALSE; } } }
if (Trans != NULL) { if (hr == S_OK) { *Trans = (MMPTE64 & MMPTETrans->Mask) >> MMPTETrans->BitPos; } else { *Trans = 0; } }
return hr; }
/**************************************************************************\
* * Routine Name: * * GetMMPTEX86LargePage * * Routine Description: * * Extract LargePage value from X86 MMPTE * \**************************************************************************/
HRESULT GetMMPTEX86LargePage( PDEBUG_CLIENT Client, ULONG64 MMPTE64, PULONG64 X86LargePage ) { HRESULT hr = S_FALSE;
if (TargetMachine != IMAGE_FILE_MACHINE_I386) { if (X86LargePage != NULL) *X86LargePage = 0; return hr; }
if (MMPTEX86LargePage == NULL) { MMPTEX86LargePage = new BitFieldInfo; }
if (MMPTEX86LargePage == NULL) { hr = E_OUTOFMEMORY; } else if (MMPTEX86LargePage->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, MMPTEX86LargePage); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read LargePage bit field from symbol file
if (OutState.Execute("dt NT!HARDWARE_PTE LargePage") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { MMPTEX86LargePage->Valid = MMPTEX86LargePage->Compose(7, 1); hr = MMPTEX86LargePage->Valid ? S_OK : S_FALSE; } } }
if (X86LargePage != NULL) { if (hr == S_OK) { *X86LargePage = (MMPTE64 & MMPTEX86LargePage->Mask) >> MMPTEX86LargePage->BitPos; } else { *X86LargePage = 0; } }
return hr; }
/**************************************************************************\
* * Routine Name: * * GetMMPTEpfn * * Routine Description: * * Extract Page Frame Number value from MMPTE * \**************************************************************************/
HRESULT GetMMPTEpfn( PDEBUG_CLIENT Client, ULONG64 MMPTE64, PULONG64 pfn, FLONG Flags ) { HRESULT hr = S_FALSE;
if (MMPTEpfn == NULL) { MMPTEpfn = new BitFieldInfo; }
if (MMPTEpfn == NULL) { hr = E_OUTOFMEMORY; } else if (MMPTEpfn->Valid) { hr = S_OK; } else { BitFieldParser BitFieldReader(Client, MMPTEpfn); OutputState OutState(Client);
if ((hr = BitFieldReader.Ready()) == S_OK && (hr = OutState.Setup(0, &BitFieldReader)) == S_OK) { // Read PageFrameNumber bit field from symbol file
if (OutState.Execute("dt NT!HARDWARE_PTE PageFrameNumber") != S_OK || BitFieldReader.ParseOutput() != S_OK || BitFieldReader.Complete() != S_OK) { switch (TargetMachine) { case IMAGE_FILE_MACHINE_I386: MMPTEpfn->Valid = MMPTEpfn->Compose(12, PaeEnabled ? 24 : 20); break; case IMAGE_FILE_MACHINE_IA64: if (PageSize) { MMPTEpfn->Valid = MMPTEpfn->Compose(PageShift, 50-PageShift); break; } default: { OutputControl OutCtl(Client); OutCtl.OutErr("Couldn't find MMPTE pfn in type info.\n"); } } hr = MMPTEpfn->Valid ? S_OK : S_FALSE; } } }
if (pfn != NULL) { if (hr == S_OK) { *pfn = (MMPTE64 & MMPTEpfn->Mask); if (!(Flags & GET_BITS_UNSHIFTED)) { *pfn >>= MMPTEpfn->BitPos; } } else { *pfn = 0; } }
return hr; }
HRESULT GetSessionNumbers( IN PDEBUG_CLIENT Client, OUT PULONG CurrentSession, OUT PULONG DefaultSession, OUT PULONG TotalSessions, OUT PRTL_BITMAP *SessionList ) { HRESULT hr = S_FALSE;
if (CurrentSession != NULL) { DEBUG_VALUE RunningSession; BasicOutputParser SessionReader(Client, 1); OutputState OutState(Client);
if ((hr = SessionReader.LookFor(&RunningSession, "SessionId:", DEBUG_VALUE_INT32)) == S_OK && (hr = OutState.Setup(0, &SessionReader)) == S_OK && (hr = OutState.Execute("!process -1 0")) == S_OK && (hr = SessionReader.ParseOutput()) == S_OK && (hr = SessionReader.Complete()) == S_OK) { *CurrentSession = RunningSession.I32; } else { *CurrentSession = INVALID_SESSION; } }
if (DefaultSession != NULL) { *DefaultSession = SessionId; hr = S_OK; }
if ((TotalSessions != NULL) || (SessionList != NULL)) { ULONG SessionCount = 0; PRTL_BITMAP SessionListBitMap = NULL; ULONG64 SessionIdListPointerAddr = 0; ULONG64 SessionIdListAddr = 0;
PDEBUG_SYMBOLS Symbols; PDEBUG_DATA_SPACES Data;
if (TotalSessions) { *TotalSessions = 0; } if (SessionList) { *SessionList = NULL; }
OutputControl OutCtl(Client);
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { return hr; }
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) != S_OK) { Symbols->Release(); return hr; }
CHAR PointerName[] = "NT!MiSessionIdBitmap"; hr = Symbols->GetOffsetByName(PointerName, &SessionIdListPointerAddr); if (hr != S_OK) { OutCtl.OutErr("Unable to locate %s\n", PointerName); } else { hr = Data->ReadPointersVirtual(1, SessionIdListPointerAddr, &SessionIdListAddr);
if (hr == S_OK) { hr = GetBitMap(Client, SessionIdListAddr, &SessionListBitMap);
if (hr == S_OK) { SessionCount = RtlNumberOfSetBits(SessionListBitMap); } } }
if (TotalSessions) { *TotalSessions = SessionCount; }
// Free or return BitMap
if (SessionListBitMap) { if (SessionList) { *SessionList = SessionListBitMap; } else { FreeBitMap(SessionListBitMap); } }
Data->Release(); Symbols->Release(); }
return hr; }
HRESULT SetDefaultSession( IN PDEBUG_CLIENT Client, IN ULONG NewSession, OUT OPTIONAL PULONG OldSession ) { HRESULT hr = S_FALSE;
GetSessionNumbers(Client, NULL, OldSession, NULL, NULL);
if ((NewSession == CURRENT_SESSION) || (GetSessionSpace(Client, NewSession, NULL) == S_OK)) { if (NewSession != SessionId) { SessionId = NewSession;
if (SessionId == CURRENT_SESSION) { strcpy(SessionStr, "CURRENT"); } else { _ultoa(SessionId, SessionStr, 10); }
}
hr = S_OK; }
return hr; }
HRESULT GetCurrentSession( PDEBUG_CLIENT Client, PULONG64 CurSessionSpace, PULONG CurSessionId ) { static ULONG LastCachedUniqueState = INVALID_UNIQUE_STATE; static DEBUG_VALUE LastSessionSpace = { 0, DEBUG_VALUE_INVALID }; static DEBUG_VALUE LastSessionId = { INVALID_SESSION, DEBUG_VALUE_INVALID };
HRESULT hr = S_OK; OutputControl OutCtl(Client); BasicOutputParser SessionSpaceReader(Client); BasicOutputParser SessionIdReader(Client); OutputState OutState(Client); CHAR szCommand[MAX_PATH];
ULONG CurrentUniqueState = UniqueTargetState;
if (CurSessionSpace != NULL) *CurSessionSpace = 0; if (CurSessionId != NULL) *CurSessionId = INVALID_SESSION;
// Get the current session space
if (CurrentUniqueState == INVALID_UNIQUE_STATE || LastCachedUniqueState != CurrentUniqueState || LastSessionSpace.Type == DEBUG_VALUE_INVALID) { PDEBUG_SYSTEM_OBJECTS System; ULONG64 ProcessAddr;
if ((hr = Client->QueryInterface(__uuidof(IDebugSystemObjects), (void **)&System)) == S_OK) { if ((hr = System->GetCurrentProcessDataOffset(&ProcessAddr)) == S_OK) { // Set Output callbacks
if ((hr = SessionSpaceReader.LookFor(&LastSessionSpace, "Session", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &SessionSpaceReader)) == S_OK) { sprintf(szCommand, "dt NT!EPROCESS Session 0x%I64x", ProcessAddr); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = SessionSpaceReader.ParseOutput()) == S_OK && (hr = SessionSpaceReader.Complete()) == S_OK) { if (LastSessionSpace.I64 == 0) { hr = E_FAIL; } } }
} else { OutCtl.OutErr("IDebugSystemObjects::GetCurrentProcessDataOffset returned %s.\n", pszHRESULT(hr)); }
System->Release(); }
if (hr != S_OK) { LastSessionSpace.Type = DEBUG_VALUE_INVALID; } else { OutCtl.OutVerb("Caching current session space @ 0x%p.\n", LastSessionSpace.I64);
// Update CachedUniqueState and make sure SessionID
// is refreshed.
if (CurrentUniqueState == INVALID_UNIQUE_STATE || LastCachedUniqueState != CurrentUniqueState) { LastCachedUniqueState = CurrentUniqueState; LastSessionId.Type = DEBUG_VALUE_INVALID; } } }
if (hr == S_OK && CurSessionId != NULL && LastSessionId.Type == DEBUG_VALUE_INVALID) { DEBUG_VALUE CurrentSessionId;
// Set Output callbacks
if ((hr = SessionIdReader.LookFor(&LastSessionId, "SessionId", DEBUG_VALUE_INT32)) == S_OK && (hr = OutState.Setup(0, &SessionIdReader)) == S_OK) { sprintf(szCommand, "dt NT!MM_SESSION_SPACE SessionId 0x%I64x", LastSessionSpace.I64); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = SessionIdReader.ParseOutput()) == S_OK && (hr = SessionIdReader.Complete()) == S_OK) { if (LastSessionId.I32 == INVALID_SESSION) { hr = E_FAIL; } } }
if (hr != S_OK) { LastSessionId.Type = DEBUG_VALUE_INVALID; } }
if (hr == S_OK) { if (CurSessionSpace != NULL) *CurSessionSpace = LastSessionSpace.I64; if (CurSessionId != NULL) *CurSessionId = LastSessionId.I32; }
return hr; }
HRESULT GetSessionSpace( PDEBUG_CLIENT Client, ULONG Session, PULONG64 SessionSpace ) { HRESULT hr; OutputControl OutCtl(Client); DEBUG_VALUE FoundSession; DEBUG_VALUE SessionSpaceAddr;
ULONG CurrentUniqueState = UniqueTargetState;
if (Session == DEFAULT_SESSION) { Session = SessionId; }
if (Session == CURRENT_SESSION) { ULONG64 CurSessionSpace; ULONG CurSessionId;
hr = GetCurrentSession(Client, &SessionSpaceAddr.I64, &FoundSession.I32); } else { if (CurrentUniqueState != INVALID_UNIQUE_STATE) { if (Session < NUM_CACHED_SESSIONS) { if (CachedSession[Session].UniqueState == CurrentUniqueState && CachedSession[Session].SessionSpaceAddr != 0) { if (SessionSpace != NULL) *SessionSpace = CachedSession[Session].SessionSpaceAddr; return S_OK; } } else if (ExtraCachedSessionId != INVALID_SESSION && Session == ExtraCachedSessionId) { if (CachedSession[NUM_CACHED_SESSIONS].UniqueState == CurrentUniqueState && CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr != 0) { if (SessionSpace != NULL) *SessionSpace = CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr; return S_OK; } } }
ULONG64 FirstSessionSpace; DEBUG_VALUE SessionSpaceWsList; DEBUG_VALUE SessionSpaceWsListOffset; BasicOutputParser OffsetReader(Client); BasicOutputParser FlinkReader(Client); BasicOutputParser SessionReader(Client); OutputState OutState(Client); CHAR szCommand[MAX_PATH];
// Set Output callbacks
// Get ListEntry offset
if ((hr = OffsetReader.LookFor(&SessionSpaceWsListOffset, " +", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &OffsetReader)) == S_OK) { sprintf(szCommand, "dt NT!MM_SESSION_SPACE WsListEntry"); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = OffsetReader.ParseOutput()) == S_OK) { hr = OffsetReader.Complete(); } }
// Get first session space in list
if (hr == S_OK && (hr = FlinkReader.LookFor(&SessionSpaceWsList, "Flink", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &FlinkReader)) == S_OK) { sprintf(szCommand, "dt NT!MiSessionWsList"); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = FlinkReader.ParseOutput()) == S_OK) { hr = FlinkReader.Complete(); } }
// Add SessionId to reader search
if (hr == S_OK && (hr = SessionReader.LookFor(&FoundSession, "SessionId", DEBUG_VALUE_INT32)) == S_OK && (hr = SessionReader.LookFor(&SessionSpaceWsList, "Flink", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &SessionReader)) == S_OK) { SessionSpaceAddr.I64 = SessionSpaceWsList.I64 - SessionSpaceWsListOffset.I64; FirstSessionSpace = SessionSpaceAddr.I64;
OutCtl.OutVerb("First session space @ %p.\n", FirstSessionSpace);
do { // Get SessionId for this session space
SessionReader.DiscardOutput(); SessionReader.Relook(); sprintf(szCommand, "dt NT!MM_SESSION_SPACE SessionId WsListEntry.Flink 0x%I64x", SessionSpaceAddr.I64); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = SessionReader.ParseOutput()) == S_OK && (hr = SessionReader.Complete()) == S_OK) { if (Session == FoundSession.I32) { break; }
// Compute next session space
SessionSpaceAddr.I64 = SessionSpaceWsList.I64 - SessionSpaceWsListOffset.I64;
if (SessionSpaceAddr.I64 == FirstSessionSpace) { hr = S_FALSE; } } else { OutCtl.OutErr("Couldn't get SessionId or next session from \'%s\'\n", szCommand); PSTR pszOutput; if (SessionReader.GetOutputCopy(&pszOutput) == S_OK) { OutCtl.OutVerb(" dt output:\n%s\n", pszOutput); SessionReader.FreeOutputCopy(pszOutput); } } } while (hr == S_OK); } }
if (hr == S_OK) { OutCtl.OutVerb("Session %ld lookup found Session #%ld @ 0x%p.\n", Session, FoundSession.I32, SessionSpaceAddr.I64);
if (FoundSession.I32 < NUM_CACHED_SESSIONS) { CachedSession[FoundSession.I32].UniqueState = CurrentUniqueState; CachedSession[FoundSession.I32].SessionSpaceAddr = SessionSpaceAddr.I64; } else { ExtraCachedSessionId = FoundSession.I32; CachedSession[NUM_CACHED_SESSIONS].UniqueState = CurrentUniqueState; CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr = SessionSpaceAddr.I64; }
if (SessionSpace != NULL) *SessionSpace = SessionSpaceAddr.I64; }
return hr; }
HRESULT GetSessionDirBase( PDEBUG_CLIENT Client, ULONG Session, PULONG64 PageDirBase ) { HRESULT hr = S_FALSE; OutputControl OutCtl(Client); ULONG64 SessionSpaceOffset; ULONG64 Process = -1; DEBUG_VALUE SessionIdCheck; DEBUG_VALUE dvPageDirBase; BasicOutputParser ProcessReader(Client); OutputState OutState(Client); CHAR szCommand[MAX_PATH];
static ULONG LastSession = -2; static ULONG64 LastSessionPageDirBase = 0;
if (Session == DEFAULT_SESSION) { Session = SessionId; }
if (Session == LastSession && LastSessionPageDirBase != 0) { *PageDirBase = LastSessionPageDirBase; return S_OK; }
*PageDirBase = 0;
if ((hr == GetSessionSpace(Client, Session, &SessionSpaceOffset)) == S_OK) { DEBUG_VALUE ProcessSessionListOffset; BasicOutputParser OffsetReader(Client);
if ((hr = OffsetReader.LookFor(&ProcessSessionListOffset, " +", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &OffsetReader)) == S_OK) { sprintf(szCommand, "dt NT!_EPROCESS SessionProcessLinks"); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = OffsetReader.ParseOutput()) == S_OK) { hr = OffsetReader.Complete(); } }
DEBUG_VALUE SessionProcessListAddr; BasicOutputParser FlinkReader(Client);
if (hr == S_OK && (hr = FlinkReader.LookFor(&SessionProcessListAddr, "Flink", DEBUG_VALUE_INT64)) == S_OK && (hr = OutState.Setup(0, &FlinkReader)) == S_OK) { sprintf(szCommand, "dt NT!MM_SESSION_SPACE ProcessList.Flink 0x%I64x", SessionSpaceOffset); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = FlinkReader.ParseOutput()) == S_OK && (hr = FlinkReader.Complete()) == S_OK) { Process = SessionProcessListAddr.I64 - ProcessSessionListOffset.I64; } } } else { OutCtl.OutVerb("GetSessionSpace returned HRESULT 0x%lx.\n", hr); }
if (hr == S_OK && (hr = ProcessReader.LookFor(&SessionIdCheck, "SessionId:", DEBUG_VALUE_INT32)) == S_OK && (hr = ProcessReader.LookFor(&dvPageDirBase, "DirBase:", DEBUG_VALUE_INT64, 16)) == S_OK && (hr = OutState.Setup(0, &ProcessReader)) == S_OK) { sprintf(szCommand, "!process 0x%I64x 0", Process); if ((hr = OutState.Execute(szCommand)) == S_OK && (hr = ProcessReader.ParseOutput()) == S_OK && (hr = ProcessReader.Complete()) == S_OK) { *PageDirBase = dvPageDirBase.I64;
OutCtl.OutVerb("DirBase for session %lu is %p.\n", SessionIdCheck.I32, dvPageDirBase.I64);
if (Session != CURRENT_SESSION && Session != SessionIdCheck.I32) { hr = S_FALSE; } else { LastSession = Session; LastSessionPageDirBase = dvPageDirBase.I64; } } }
return hr; }
HRESULT ReadPageTableEntry( PDEBUG_DATA_SPACES Data, ULONG64 PageTableBase, ULONG64 PageTableIndex, PULONG64 PageTableEntry ) { HRESULT hr; ULONG64 PhysAddr = PageTableBase + PageTableIndex * HwPte.Size; ULONG BytesRead; ULONG CurrentUniqueState = UniqueTargetState;
*PageTableEntry = 0;
if (CurrentUniqueState != INVALID_UNIQUE_STATE) { if (CachedPhysAddr[0].UniqueState == CurrentUniqueState && CachedPhysAddr[0].PhysAddr == PhysAddr) { *PageTableEntry = CachedPhysAddr[0].Data; return S_OK; } else if (CachedPhysAddr[1].UniqueState == CurrentUniqueState && CachedPhysAddr[1].PhysAddr == PhysAddr) { *PageTableEntry = CachedPhysAddr[1].Data; return S_OK; } }
hr = Data->ReadPhysical(PhysAddr, PageTableEntry, HwPte.Size, &BytesRead);
if (hr == S_OK) { if (BytesRead < HwPte.Size) { hr = S_FALSE; } else { static CacheToggle = 1;
CacheToggle = (CacheToggle+1) % 2;
CachedPhysAddr[CacheToggle].UniqueState = CurrentUniqueState; CachedPhysAddr[CacheToggle].PhysAddr = *PageTableEntry; } }
return hr; }
HRESULT GetPageFrameNumber( PDEBUG_CLIENT Client, PDEBUG_DATA_SPACES Data, ULONG64 PageTableBase, ULONG64 PageTableIndex, PULONG64 PageFrameNumber, PBOOL Large ) { HRESULT hr; ULONG64 PageTableEntry; ULONG64 Valid, Proto, Trans, LargePage; ULONG64 pfn;
if ((hr = ReadPageTableEntry(Data, PageTableBase, PageTableIndex, &PageTableEntry)) == S_OK) { if ((hr = GetMMPTEValid(Client, PageTableEntry, &Valid)) == S_OK) { if (Valid) { hr = GetMMPTEpfn(Client, PageTableEntry, PageFrameNumber, GET_BITS_UNSHIFTED);
if (hr == S_OK) { if (GetMMPTEX86LargePage(Client, PageTableEntry, &LargePage) == S_OK && LargePage != 0) { // Large pages map 4MB of space - there shouldn't
// be any bits set below that.
if (*PageFrameNumber & (4*1024*1024 - 1)) { RIP("Found large X86 page with bad frame number.\n"); }
if (Large == NULL) { RIP("Unexpected large X86 page found.\n"); } else { *Large = TRUE; } } else if (Large != NULL) { *Large = FALSE; } } } else { if ((hr = GetMMPTEProto(Client, PageTableEntry, &Proto)) == S_OK && (hr = GetMMPTETrans(Client, PageTableEntry, &Trans)) == S_OK) { if (Proto == 0 && Trans == 1) { hr = GetMMPTEpfn(Client, PageTableEntry, PageFrameNumber, GET_BITS_UNSHIFTED); } else { hr = S_FALSE; } } } } }
return hr; }
HRESULT GetPhysicalBase( PDEBUG_CLIENT Client, ULONG64 PageDirBase, ULONG64 PageDirIndex, ULONG64 PageTableIndex, PULONG64 PhysicalBase ) { HRESULT hr; PDEBUG_DATA_SPACES Data; ULONG64 PageTableBase; BOOL Large;
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) == S_OK) { if ((hr = GetPageFrameNumber(Client, Data, PageDirBase, PageDirIndex, &PageTableBase, &Large)) == S_OK) { if (!Large) { hr = GetPageFrameNumber(Client, Data, PageTableBase, PageTableIndex, PhysicalBase, NULL); } else { *PhysicalBase = PageTableBase; } }
Data->Release(); }
return hr; }
HRESULT GetPhysicalAddress( PDEBUG_CLIENT Client, ULONG Session, ULONG64 VirtAddr, PULONG64 PhysAddr ) { if (Client == NULL) return E_INVALIDARG;
HRESULT hr = S_OK; ULONG64 PageDirIndex; ULONG64 PageTableIndex; ULONG64 PageByteIndex; ULONG64 PageDirBase;
OutputControl OutCtl(Client);
ULONG CurrentUniqueState = UniqueTargetState;
if (Session == DEFAULT_SESSION) { Session = SessionId; }
if (!HwPte.Valid) { PDEBUG_SYMBOLS Symbols;
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) == S_OK) { if ((hr = Symbols->GetSymbolTypeId(HwPte.Type, &HwPte.TypeId, &HwPte.Module)) == S_OK && (hr = Symbols->GetTypeSize(HwPte.Module, HwPte.TypeId, &HwPte.Size)) == S_OK && HwPte.Size != 0) { HwPte.Valid = TRUE; }
Symbols->Release(); } }
if (HwPte.Valid) { ULONG TableEntries = PageSize / HwPte.Size;
PageByteIndex = VirtAddr & (PageSize-1); VirtAddr >>= PageShift; PageTableIndex = VirtAddr % TableEntries; PageDirIndex = (VirtAddr / TableEntries) % TableEntries;
if (Session < NUM_CACHED_DIR_BASES && CurrentUniqueState != INVALID_UNIQUE_STATE && CachedDirBase[Session].UniqueState == CurrentUniqueState && (hr = GetPhysicalBase(Client, CachedDirBase[Session].PageDirBase, PageDirIndex, PageTableIndex, PhysAddr)) == S_OK) { *PhysAddr |= PageByteIndex; } else { DEBUG_VALUE SessionIdCheck; DEBUG_VALUE dvPageDirBase; BasicOutputParser ProcessReader(Client); OutputState OutState(Client); OutputControl OutCtlToProcessReader; BOOL ShortProcessList = (Session == CURRENT_SESSION); BOOL fOutputNewLine = FALSE; CProcessListing ProcessListing(40);
if ((hr = ProcessReader.LookFor(&SessionIdCheck, "SessionId:", DEBUG_VALUE_INT32)) == S_OK && (hr = ProcessReader.LookFor(&dvPageDirBase, "DirBase:", DEBUG_VALUE_INT64, 16)) == S_OK && (hr = OutState.Setup(0, &ProcessReader)) == S_OK && (hr = OutCtlToProcessReader.SetControl( DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_NOT_LOGGED | DEBUG_OUTCTL_OVERRIDE_MASK, OutState.Client)) == S_OK && (hr = (ShortProcessList ? OutState.Execute("!process -1 0") : OutputSessionProcesses(OutState.Client, &OutCtlToProcessReader, Session, "0", &ProcessListing) /*OutState.Execute("!process 0 0")*/ )) == S_OK) { hr = S_FALSE;
while (hr != S_OK && OutCtl.GetInterrupt() != S_OK) { if (ProcessReader.ParseOutput() != S_OK || ProcessReader.Complete() != S_OK) { if (ShortProcessList || !ProcessListing.Unprocessed()) { break; }
// At this point, we have processed some, but
// not all so get the next listing. Since there
// can be a huge process list, output a progress
// indicator.
OutCtl.Output("."); fOutputNewLine = TRUE;
ProcessListing.PrepareForNextListing(); ProcessReader.DiscardOutput();
hr = OutputSessionProcesses(OutState.Client, &OutCtlToProcessReader, Session, "0", &ProcessListing); if (hr != S_OK) { OutCtl.OutErr("OutputSessionProcesses returned 0x%X (!= S_OK)\n", hr); }
ProcessReader.Relook();
if (ProcessReader.ParseOutput() != S_OK || ProcessReader.Complete() != S_OK) { break; } } ProcessReader.Relook();
if (Session == CURRENT_SESSION) { // The current process is always first
// due to the '!process -1 0' above.
Session = SessionIdCheck.I32; }
if (Session != SessionIdCheck.I32) { continue; }
hr = GetPhysicalBase(Client, dvPageDirBase.I64, PageDirIndex, PageTableIndex, PhysAddr);
if (hr == S_OK) { *PhysAddr |= PageByteIndex; if (Session < NUM_CACHED_DIR_BASES) { CachedDirBase[Session].UniqueState = CurrentUniqueState; CachedDirBase[Session].PageDirBase = dvPageDirBase.I64; } else if (Session == CURRENT_SESSION) { CachedDirBase[NUM_CACHED_DIR_BASES].UniqueState = CurrentUniqueState; CachedDirBase[NUM_CACHED_DIR_BASES].PageDirBase = dvPageDirBase.I64; } } else if ((ShortProcessList && SessionId == CURRENT_SESSION)) { ShortProcessList = FALSE; hr = OutputSessionProcesses(OutState.Client, &OutCtlToProcessReader, Session, "0", &ProcessListing); if (hr != S_OK) { OutCtl.OutErr("OutputSessionProcesses returned 0x%X (!= S_OK)\n", hr); } hr = S_FALSE; } }
if (fOutputNewLine) { OutCtl.Output("\n"); } } else { OutCtl.OutVerb("Process reading setup failed.\n"); } } } else { OutCtl.OutVerb("GetPageLookupData returned 0x%lx.\n", hr); }
return hr; }
HRESULT GetNextResidentPage( PDEBUG_CLIENT Client, ULONG64 PageDirBase, ULONG64 VirtAddrStart, ULONG64 VirtAddrLimit, PULONG64 VirtPage, PULONG64 PhysPage ) { HRESULT hr; BOOL Interrupted = FALSE; PDEBUG_CONTROL Control = NULL; PDEBUG_DATA_SPACES Data = NULL; ULONG64 PageDirIndex; ULONG64 PageTableIndex; ULONG64 PageDirIndexLimit; ULONG64 PageTableIndexLimit; ULONG64 PageTableBase; BOOL LargePage; ULONG64 TempAddr;
if (VirtPage == NULL) VirtPage = &TempAddr; if (PhysPage == NULL) PhysPage = &TempAddr;
*VirtPage = 0; *PhysPage = 0;
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) == S_OK && (hr = Client->QueryInterface(__uuidof(IDebugControl), (void **)&Control)) == S_OK) { if (!HwPte.Valid) { PDEBUG_SYMBOLS Symbols;
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) == S_OK) { if ((hr = Symbols->GetSymbolTypeId(HwPte.Type, &HwPte.TypeId, &HwPte.Module)) == S_OK && (hr = Symbols->GetTypeSize(HwPte.Module, HwPte.TypeId, &HwPte.Size)) == S_OK && HwPte.Size != 0) { HwPte.Valid = TRUE; } else if (hr == S_OK) { hr = E_FAIL; }
Symbols->Release(); } }
if (HwPte.Valid) { ULONG TableEntries = PageSize / HwPte.Size; ULONG64 Addr;
*VirtPage = PAGE_ALIGN64(VirtAddrStart);
Addr = VirtAddrStart >> PageShift; PageTableIndex = Addr % TableEntries; PageDirIndex = (Addr / TableEntries) % TableEntries;
Addr = VirtAddrLimit >> PageShift; PageTableIndexLimit = Addr % TableEntries; PageDirIndexLimit = (Addr / TableEntries) % TableEntries;
if (VirtAddrLimit & (PageSize-1)) { PageTableIndexLimit++; }
hr = S_FALSE;
while (PageDirIndex < PageDirIndexLimit && hr != S_OK) { if ((hr = GetPageFrameNumber(Client, Data, PageDirBase, PageDirIndex, &PageTableBase, &LargePage)) == S_OK) { if (LargePage) { *PhysPage = PageTableBase; } else { do { if ((hr = GetPageFrameNumber(Client, Data, PageTableBase, PageTableIndex, PhysPage, NULL)) != S_OK) { hr = Control->GetInterrupt();
if (hr == S_OK) { Interrupted = TRUE; Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE); } else { PageTableIndex++; *VirtPage += PageSize; } } } while (PageTableIndex < TableEntries && hr != S_OK); } } else { *VirtPage += PageSize * (TableEntries - PageTableIndex); }
if (hr != S_OK) { hr = Control->GetInterrupt();
if (hr == S_OK) { Interrupted = TRUE; Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE); } else { PageTableIndex = 0; PageDirIndex++; } } }
if (PageDirIndex == PageDirIndexLimit && PageTableIndex < PageTableIndexLimit && hr != S_OK) { if ((hr = GetPageFrameNumber(Client, Data, PageDirBase, PageDirIndex, &PageTableBase, &LargePage)) == S_OK) { if (LargePage) { *PhysPage = PageTableBase; } else { do { if ((hr = GetPageFrameNumber(Client, Data, PageTableBase, PageTableIndex, PhysPage, NULL)) != S_OK) { hr = Control->GetInterrupt();
if (hr == S_OK) { Interrupted = TRUE; Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE); } else { PageTableIndex++; *VirtPage += PageSize; } } } while (PageTableIndex < PageTableIndexLimit && hr != S_OK); } } } }
}
if (Control != NULL) Control->Release(); if (Data != NULL) Data->Release();
return ((Interrupted) ? E_ABORT : hr); }
HRESULT GetNextResidentAddress( PDEBUG_CLIENT Client, ULONG Session, ULONG64 VirtAddrStart, ULONG64 VirtAddrLimit, PULONG64 VirtAddr, PULONG64 PhysAddr ) { if (Client == NULL) return E_INVALIDARG;
HRESULT hr = S_OK; ULONG64 PageDirBase;
OutputControl OutCtl(Client);
ULONG CurrentUniqueState = UniqueTargetState;
if (Session == DEFAULT_SESSION) { Session = SessionId; }
if (Session < NUM_CACHED_DIR_BASES && CurrentUniqueState != INVALID_UNIQUE_STATE && CachedDirBase[Session].UniqueState == CurrentUniqueState) { PageDirBase = CachedDirBase[Session].PageDirBase; } else if (SessionId == CURRENT_SESSION && CurrentUniqueState != INVALID_UNIQUE_STATE && CachedDirBase[NUM_CACHED_DIR_BASES].UniqueState == CurrentUniqueState) { PageDirBase = CachedDirBase[NUM_CACHED_DIR_BASES].PageDirBase; } else { DEBUG_VALUE SessionIdCheck; DEBUG_VALUE dvPageDirBase; BasicOutputParser ProcessReader(Client); OutputState OutState(Client); BOOL ShortProcessList = (Session == CURRENT_SESSION);
if ((hr = ProcessReader.LookFor(&SessionIdCheck, "SessionId:", DEBUG_VALUE_INT32)) == S_OK && (hr = ProcessReader.LookFor(&dvPageDirBase, "DirBase:", DEBUG_VALUE_INT64, 16)) == S_OK && (hr = OutState.Setup(0, &ProcessReader)) == S_OK && (hr = (ShortProcessList ? OutState.Execute("!process -1 0") : OutState.Execute("!process 0 0"))) == S_OK) { hr = S_FALSE;
while (hr != S_OK && OutCtl.GetInterrupt() != S_OK && ProcessReader.ParseOutput() == S_OK && ProcessReader.Complete() == S_OK) { ProcessReader.Relook();
if (Session == CURRENT_SESSION) { // The current process is always first
// due to the '!process -1 0' above.
Session = SessionIdCheck.I32; }
if (Session == SessionIdCheck.I32) { hr = S_OK; PageDirBase = dvPageDirBase.I64;
if (Session < NUM_CACHED_DIR_BASES) { CachedDirBase[Session].UniqueState = CurrentUniqueState; CachedDirBase[Session].PageDirBase = dvPageDirBase.I64; } else if (Session == CURRENT_SESSION) { CachedDirBase[NUM_CACHED_DIR_BASES].UniqueState = CurrentUniqueState; CachedDirBase[NUM_CACHED_DIR_BASES].PageDirBase = dvPageDirBase.I64; } } } } else { OutCtl.OutVerb("Process reading setup failed.\n"); } }
if (hr == S_OK) { hr = GetNextResidentPage(Client, PageDirBase, VirtAddrStart, VirtAddrLimit, VirtAddr, PhysAddr); } else { OutCtl.OutVerb("Page Directory Base lookup failed.\n"); }
return hr; }
DECLARE_API( session ) { INIT_API();
HRESULT hr; ULONG NewSession = CURRENT_SESSION; ULONG CurrentSession; ULONG SessionCount = 0; PRTL_BITMAP SessionList = NULL; DEBUG_VALUE DebugValue;
while (*args && isspace(*args)) args++; if (args[0] == '-' && args[1] == '?') { ExtOut("session displays number of sessions on machine and\n" " the default SessionId used by session related extensions.\n" "\n" "Usage: session [SessionId]\n" " SessionId - sets default session used for session extensions\n");
EXIT_API(S_OK); }
ULONG OldRadix; g_pExtControl->GetRadix(&OldRadix); g_pExtControl->SetRadix(10); hr = g_pExtControl->Evaluate(args, DEBUG_VALUE_INT32, &DebugValue, NULL); g_pExtControl->SetRadix(OldRadix);
if (GetSessionNumbers(Client, &CurrentSession, NULL, &SessionCount, &SessionList) == S_OK) { if (SessionCount != 0) { ExtOut("Sesssions on machine: %lu\n", SessionCount);
// If a session wasn't specified,
// list valid sessions (up to a point).
if (hr != S_OK) { ULONG SessionLimit = SessionList->SizeOfBitMap;
ExtOut("Valid Sessions:");
for (ULONG CheckSession = 0; CheckSession <= SessionLimit; CheckSession++) { if (RtlCheckBit(SessionList, CheckSession) /*GetSessionSpace(Client, CheckSession, NULL) == S_OK*/) { ExtOut(" %lu", CheckSession); SessionCount--; if (SessionCount == 0) break; }
if (g_pExtControl->GetInterrupt() == S_OK) { ExtWarn("\n User aborted.\n"); break; } }
if (SessionCount > 0) { ExtOut(" ...?"); } ExtOut("\n"); } } else if (SessionList) { ExtOut("There are ZERO session on machine.\n"); } else { ExtErr("Couldn't determine number of sessions.\n"); }
if (SessionList) { FreeBitMap(SessionList); }
if (CurrentSession != INVALID_SESSION) { ExtVerb("Running session: %lu\n", CurrentSession); } }
if (hr == S_OK) { NewSession = DebugValue.I32;
ExtVerb("Previous Default Session: %s\n", SessionStr);
if (SetDefaultSession(Client, NewSession, NULL) != S_OK) { ExtErr("Couldn't set Session %lu.\n", NewSession); } }
ExtOut("Using session %s", SessionStr); if (SessionId == CURRENT_SESSION) { if (GetSessionNumbers(Client, &CurrentSession, NULL, NULL, NULL) == S_OK && CurrentSession != INVALID_SESSION) { ExtOut(" (%d)", CurrentSession); } else { ExtOut(" (?)"); } } ExtOut("\n");
EXIT_API(S_OK); }
DECLARE_API( svtop ) { INIT_API();
HRESULT hr; DEBUG_VALUE SessVirtAddr; ULONG64 PhysAddr;
if (S_OK == g_pExtControl->Evaluate(args, DEBUG_VALUE_INT64, &SessVirtAddr, NULL)) { if ((hr = GetPhysicalAddress(Client, SessionId, SessVirtAddr.I64, &PhysAddr)) == S_OK) { ExtOut("Session %s: %p -> %p\n", SessionStr, SessVirtAddr.I64, PhysAddr); } else { ExtErr("Failed to translate virtual address %p from session %s\n" " HRESULT: 0x%lx\n", SessVirtAddr.I64, SessionStr, hr); } } else { ExtOut("Usage: svtop SessionVirtualAddress\n"); }
EXIT_API(S_OK); }
DECLARE_API( sprocess ) { INIT_API();
HRESULT hr; DEBUG_VALUE Session; ULONG RemainingArgIndex;
while (*args && isspace(*args)) args++; if (args[0] == '-' && args[1] == '?') { ExtOut("sprocess is like !process, but for the SessionId specified.\n" "\n" "Usage: sprocess [SessionId [Flags]]\n" " SessionId - specifies which session to dump.\n" " Special SessionId values:\n" " -1 - current session\n" " -2 - last !session SessionId (default)\n" " Flags - see !process help\n");
EXIT_API(S_OK); }
ULONG OldRadix; g_pExtControl->GetRadix(&OldRadix); g_pExtControl->SetRadix(10); hr = g_pExtControl->Evaluate(args, DEBUG_VALUE_INT32, &Session, &RemainingArgIndex); g_pExtControl->SetRadix(OldRadix);
if (hr != S_OK) { Session.I32 = DEFAULT_SESSION; args = "0"; hr = S_OK; } else { args += RemainingArgIndex; }
CProcessListing ProcessListing;
hr = OutputSessionProcesses(Client, NULL, Session.I32, args, &ProcessListing);
EXIT_API(hr); }
HRESULT OutputSessionProcesses( PDEBUG_CLIENT Client, OutputControl *OutCtl, ULONG Session, PCSTR args, CProcessListing *pProcessListing ) { HRESULT hr; PDEBUG_CONTROL Control = NULL; ULONG64 SessionSpace;
if (OutCtl == NULL) { OutCtl = new OutputControl(Client);
if (OutCtl == NULL) { return E_OUTOFMEMORY; } } else { OutCtl->AddRef(); }
if ((hr = GetSessionSpace(Client, Session, &SessionSpace)) == S_OK) { DEBUG_VALUE ProcessSessionListAddr; DEBUG_VALUE ProcessSessionListOffset; DEBUG_VALUE ProcessesInSession; DEBUG_VALUE Process; BasicOutputParser OffsetReader(Client, 1); BasicOutputParser SessionReader(Client, 2); BasicOutputParser FlinkReader(Client, 1); BasicOutputParser ErrorChecker(Client, 1); OutputFilter OutFilter(Client); OutputState OutState(Client); CHAR szCommand[MAX_PATH];
// General parser setup and get ListEntry offset in _EPROCESS structure
if ((hr = OffsetReader.LookFor(&ProcessSessionListOffset, " +", DEBUG_VALUE_INT64)) == S_OK && (hr = FlinkReader.LookFor(&ProcessSessionListAddr, "Flink", DEBUG_VALUE_INT64)) == S_OK && (hr = ErrorChecker.LookFor(NULL, "Could not find _EPROCESS")) == S_OK && (hr = OutState.Setup(0, &OffsetReader)) == S_OK) { if ((hr = StringCbCopyA(szCommand, sizeof(szCommand), "dt NT!_EPROCESS SessionProcessLinks")) == S_OK && (hr = OutState.Execute(szCommand)) == S_OK && (hr = OffsetReader.ParseOutput()) == S_OK) { hr = OffsetReader.Complete(); } }
// Find first process and number of processes
if (hr == S_OK) { if (pProcessListing->m_oStartProcess && pProcessListing->m_cTotal) { Process.I64 = pProcessListing->m_oStartProcess; ProcessesInSession.I32 = pProcessListing->m_cTotal - pProcessListing->m_cProcessed; } else { if ((hr = SessionReader.LookFor(&ProcessSessionListAddr, "Flink", DEBUG_VALUE_INT64)) == S_OK && (hr = SessionReader.LookFor(&ProcessesInSession, "ProcessReferenceToSession", DEBUG_VALUE_INT32)) == S_OK && (hr = OutState.Setup(0, &SessionReader)) == S_OK) { if ((hr = StringCbPrintfA( szCommand, sizeof(szCommand), "dt NT!MM_SESSION_SPACE ProcessList.Flink ProcessReferenceToSession 0x%I64x", SessionSpace)) == S_OK && (hr = OutState.Execute(szCommand)) == S_OK && (hr = SessionReader.ParseOutput()) == S_OK && (hr = SessionReader.Complete()) == S_OK) { Process.I64 = ProcessSessionListAddr.I64 - ProcessSessionListOffset.I64; pProcessListing->m_cTotal = ProcessesInSession.I32; pProcessListing->m_cProcessed = 0; pProcessListing->m_oStartProcess = Process.I64; pProcessListing->m_oLastProcess = Process.I64; } } } }
if (hr == S_OK) { ULONG cProcessed = 0;
OutCtl->Output("Processes is session: %lu\n", ProcessesInSession.I32);
// Dump all processes
while ((hr == S_OK) && (ProcessesInSession.I32 > 0) && (cProcessed < pProcessListing->m_cListLimit)) { hr = StringCbPrintfA( szCommand, sizeof(szCommand), "!process 0x%I64x %s", Process.I64, args);
// dump process and check that the process was valid
if (SUCCEEDED(hr) && (hr = OutState.Setup(0, &OutFilter)) == S_OK) { OutFilter.DiscardOutput();
hr = OutState.Execute(szCommand); }
OutState.Setup(0, NULL);
OutFilter.OutputText(OutCtl, DEBUG_OUTPUT_NORMAL);
if (hr == S_OK) { // check that the process was valid
PSTR pszText = NULL;
if (SUCCEEDED(OutFilter.GetOutputCopy(&pszText)) && ErrorChecker.Ready() == S_OK && ErrorChecker.Parse(pszText, NULL) == S_OK && ErrorChecker.Complete() == S_OK) { hr = S_FALSE; }
if (pszText) { OutFilter.FreeOutputCopy(pszText); } }
if (hr == S_OK) { // Get next process
FlinkReader.DiscardOutput(); FlinkReader.Relook(); hr = StringCbPrintfA( szCommand, sizeof(szCommand), "dt NT!_EPROCESS SessionProcessLinks.Flink 0x%I64x", Process.I64); if (SUCCEEDED(hr)) { if ((hr = OutState.Setup(0, &FlinkReader)) == S_OK && (hr = OutState.Execute(szCommand)) == S_OK && (hr = FlinkReader.ParseOutput()) == S_OK && (hr = FlinkReader.Complete()) == S_OK) { Process.I64 = ProcessSessionListAddr.I64 - ProcessSessionListOffset.I64;
ProcessesInSession.I32--; } else { OutCtl->OutVerb("Couldn't get next process from '%s'\n", szCommand); } } else { OutCtl->OutVerb("dt command string is too long for buffer.\n"); } }
if (hr == S_OK) { cProcessed++; pProcessListing->m_cProcessed++; pProcessListing->m_oLastProcess = Process.I64; } }
if (ProcessesInSession.I32 > 0) { OutCtl->OutErr("%lu processes weren't dumped.\n", ProcessesInSession.I32); } } } else { OutCtl->OutErr("Couldn't get session %lu's data.\n", Session); }
OutCtl->Release();
return hr; }
HRESULT SearchLinkedList( PDEBUG_CLIENT Client, ULONG64 StartAddr, ULONG64 NextLinkOffset, ULONG64 SearchAddr, PULONG LinksTraversed ) { if (LinksTraversed != NULL) { *LinksTraversed = 0; }
INIT_API();
HRESULT hr = S_OK; ULONG64 PhysAddr; ULONG64 NextAddr = StartAddr; ULONG LinkCount = 0; ULONG PointerSize; ULONG BytesRead;
PointerSize = (g_pExtControl->IsPointer64Bit() == S_OK) ? 8 : 4;
do { if ((hr = GetPhysicalAddress(Client, DEFAULT_SESSION, NextAddr, &PhysAddr)) == S_OK) { if ((hr = g_pExtData->ReadPhysical(PhysAddr + NextLinkOffset, &NextAddr, PointerSize, &BytesRead)) == S_OK) { if (BytesRead == PointerSize) { LinkCount++; if (PointerSize != 8) { NextAddr = DEBUG_EXTEND64(NextAddr); } ExtVerb("NextAddr: %p\n", NextAddr); } else { hr = S_FALSE; } } } } while (hr == S_OK && NextAddr != SearchAddr && NextAddr != 0 && LinkCount < 4 && NextAddr != StartAddr);
if (LinksTraversed != NULL) { *LinksTraversed = LinkCount; }
// Did we really find SearchAddr?
if (hr == S_OK && NextAddr != SearchAddr) { hr = S_FALSE; }
EXIT_API(hr); }
DECLARE_API( walklist ) { INIT_API();
HRESULT hr; BOOL NeedHelp = FALSE; BOOL SearchSessions = FALSE; DEBUG_VALUE StartAddr; DEBUG_VALUE OffsetToNextField = { -1, DEBUG_VALUE_INVALID };//FIELD_OFFSET(Win32PoolHead, pNext);
DEBUG_VALUE SearchAddr; ULONG NextArg; ULONG SessionCount; ULONG Session = 0; ULONG OldDefSession; ULONG LinksToDest = 0;
while (*args && isspace(*args)) args++;
while (args[0] == '-' && !NeedHelp) { if (tolower(args[1]) == 'a' && isspace(args[2])) { SearchSessions = TRUE; args += 2; while (*args && isspace(*args)) args++; } else if (tolower(args[1]) == 'o' && Evaluate(Client, args+2, DEBUG_VALUE_INT64, EVALUATE_DEFAULT_RADIX, &OffsetToNextField, &NextArg, NULL, 0) == S_OK) { args += 2 + NextArg; while (*args && isspace(*args)) args++; } else { NeedHelp = TRUE; } }
if (!NeedHelp && S_OK == g_pExtControl->Evaluate(args, DEBUG_VALUE_INT64, &StartAddr, &NextArg)) { args += NextArg; if (S_OK != g_pExtControl->Evaluate(args, DEBUG_VALUE_INT64, &SearchAddr, &NextArg)) { SearchAddr.I64 = 0; }
if (OffsetToNextField.Type == DEBUG_VALUE_INVALID) { ExtWarn("Assuming next field's offset is +8.\n"); OffsetToNextField.I64 = 8; } else { ExtOut("Using field at offset +0x%I64u for next.\n", OffsetToNextField.I64); }
if (SearchSessions && GetSessionNumbers(Client, NULL, &OldDefSession, &SessionCount, NULL) == S_OK && SessionCount > 0) { ExtOut("Searching all sessions lists @ %p for %p\n", StartAddr.I64, SearchAddr.I64);
do { while (SetDefaultSession(Client, Session, NULL) != S_OK && Session <= SESSION_SEARCH_LIMIT) { Session++; }
if (Session <= SESSION_SEARCH_LIMIT) { if ((hr = SearchLinkedList(Client, StartAddr.I64, OffsetToNextField.I64, SearchAddr.I64, &LinksToDest)) == S_OK) { ExtOut("Session %lu: Found %p after walking %lu linked list entries.\n", Session, SearchAddr.I64, LinksToDest); } else { ExtOut("Session %lu: Couldn't find %p after walking %lu linked list entries.\n", Session, SearchAddr.I64, LinksToDest); }
Session++; SessionCount--; } } while (SessionCount > 0 && Session <= SESSION_SEARCH_LIMIT);
if (SessionCount) { ExtErr("%lu sessions beyond session %lu were not searched.\n", SessionCount, SESSION_SEARCH_LIMIT); }
SetDefaultSession(Client, OldDefSession, NULL); } else { ExtOut("Searching Session %s list @ %p for %p\n", SessionStr, StartAddr.I64, SearchAddr.I64);
if ((hr = SearchLinkedList(Client, StartAddr.I64, OffsetToNextField.I64, SearchAddr.I64, &LinksToDest)) == S_OK) { ExtOut("Found %p after walking %lu linked list entries.\n", SearchAddr.I64, LinksToDest); } else { ExtOut("Couldn't find %p after walking %lu linked list entries.\n", SearchAddr.I64, LinksToDest); } } } else { NeedHelp = TRUE; } if (NeedHelp) { ExtOut("Usage: walklist [-a] StartAddress [SearchAddr]\n"); }
EXIT_API(S_OK); }
HRESULT GetBitMap( PDEBUG_CLIENT Client, ULONG64 pBitMap, PRTL_BITMAP *pBitMapOut ) { HRESULT hr; PRTL_BITMAP p; DEBUG_VALUE Size; DEBUG_VALUE Buffer; ULONG BufferLen; ULONG BytesRead = 0;
OutputControl OutCtl(Client); TypeOutputParser BitMapParser(Client); OutputState OutState(Client);
*pBitMapOut = NULL;
if ((hr = OutState.Setup(0, &BitMapParser)) == S_OK && (hr = OutState.OutputTypeVirtual(pBitMap, "NT!_RTL_BITMAP", 0)) == S_OK && (hr = BitMapParser.Get(&Size, "SizeOfBitMap", DEBUG_VALUE_INT32)) == S_OK && (hr = BitMapParser.Get(&Buffer, "Buffer", DEBUG_VALUE_INT64)) == S_OK) { PDEBUG_DATA_SPACES Data;
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) == S_OK) { BufferLen = (Size.I32 + 7) / 8;
#if DBG
OutCtl.OutVerb("Reading RTL_BITMAP @ 0x%p:\n" " SizeOfBitMap: %lu\n" " Buffer: 0x%p\n" " Length in bytes: 0x%lx\n", pBitMap, Size.I32, Buffer.I64, BufferLen); #endif
p = (PRTL_BITMAP) HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) + BufferLen ); if (p != NULL) { RtlInitializeBitMap(p, (PULONG)(p + 1), Size.I32); hr = Data->ReadVirtual(Buffer.I64, p->Buffer, BufferLen, &BytesRead); if (hr != S_OK) { OutCtl.OutErr("Error reading bitmap contents @ 0x%p\n", Buffer.I64); } else if (BytesRead < BufferLen) { OutCtl.OutErr("Error reading bitmap contents @ 0x%p\n", Buffer.I64 + BytesRead); hr = E_FAIL; }
if (hr != S_OK) { HeapFree( GetProcessHeap(), 0, p ); p = NULL; } else { *pBitMapOut = p; } } else { hr = E_OUTOFMEMORY; }
Data->Release(); } else { OutCtl.OutErr("Error setting up debugger interface.\n"); } } else { OutCtl.OutErr("Error reading bitmap header @ 0x%p.\n", pBitMap); }
return hr; }
HRESULT FreeBitMap( PRTL_BITMAP pBitMap ) { return (HeapFree( GetProcessHeap(), 0, pBitMap) ? S_OK : S_FALSE); }
HRESULT CheckSingleFilter( PUCHAR Tag, PUCHAR Filter ) { ULONG i; UCHAR tc; UCHAR fc;
for ( i = 0; i < 4; i++ ) { tc = (UCHAR) *Tag++; fc = (UCHAR) *Filter++; if ( fc == '*' ) return S_OK; if ( fc == '?' ) continue; if (i == 3 && (tc & ~(PROTECTED_POOL >> 24)) == fc) continue; if ( tc != fc ) return S_FALSE; }
return S_OK; }
HRESULT AccumAllFilter( OutputControl *OutCtl, ULONG64 PoolAddr, ULONG TagFilter, TypeOutputParser *PoolHeadReader, PDEBUG_VALUE Tag, ULONG BlockSize, BOOL bQuotaWithTag, PVOID Context ) { HRESULT hr; DEBUG_VALUE PoolType; PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)Context;
if (AllocStatsAccum == NULL) { return E_INVALIDARG; }
hr = PoolHeadReader->Get(&PoolType, "PoolType", DEBUG_VALUE_INT32);
if (hr == S_OK) { if (PoolType.I32 == 0) { AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } else { DEBUG_VALUE PoolIndex;
if (!NewPool) { hr = PoolHeadReader->Get(&PoolIndex, "PoolIndex", DEBUG_VALUE_INT32); }
if (hr == S_OK) { if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80)) { AllocStatsAccum->Allocated++; AllocStatsAccum->AllocatedSize += BlockSize;
if (AllocStatsAccum->Allocated % 100 == 0) { OutCtl->Output(".");
if (AllocStatsAccum->Allocated % 8000 == 0) { OutCtl->Output("\n"); } } } else { AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } } else { AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; } } } else { AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; }
return hr; }
HRESULT CheckPrintAndAccumFilter( OutputControl *OutCtl, ULONG64 PoolAddr, ULONG TagFilter, TypeOutputParser *PoolHeadReader, PDEBUG_VALUE Tag, ULONG BlockSize, BOOL bQuotaWithTag, PVOID Context ) { HRESULT hr; DEBUG_VALUE PoolType; PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)Context;
if (CheckSingleFilter(Tag->RawBytes, (PUCHAR)&TagFilter) != S_OK) { return S_FALSE; }
OutCtl->Output("0x%p size: %5lx ",//previous size: %4lx ",
PoolAddr, BlockSize << POOL_BLOCK_SHIFT/*,
PreviousSize << POOL_BLOCK_SHIFT*/);
hr = PoolHeadReader->Get(&PoolType, "PoolType", DEBUG_VALUE_INT32);
if (hr == S_OK) { if (PoolType.I32 == 0) { //
// "Free " with a space after it before the parentheses means
// it's been freed to a (pool manager internal) lookaside list.
// We used to print "Lookaside" but that just confused driver
// writers because they didn't know if this meant in use or not
// and many would say "but I don't use lookaside lists - the
// extension or kernel is broken".
//
// "Free" with no space after it before the parentheses means
// it is not on a pool manager internal lookaside list and is
// instead on the regular pool manager internal flink/blink
// chains.
//
// Note to anyone using the pool package, these 2 terms are
// equivalent. The fine distinction is only for those actually
// writing pool internal code.
//
OutCtl->Output(" (Free)"); OutCtl->Output(" %c%c%c%c\n", Tag->RawBytes[0], Tag->RawBytes[1], Tag->RawBytes[2], Tag->RawBytes[3] );
if (AllocStatsAccum != NULL) { AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } } else { DEBUG_VALUE PoolIndex; DEBUG_VALUE ProcessBilled;
if (!NewPool) { hr = PoolHeadReader->Get(&PoolIndex, "PoolIndex", DEBUG_VALUE_INT32); }
if (hr == S_OK) { if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80)) { OutCtl->Output(" (Allocated)");
if (AllocStatsAccum != NULL) { AllocStatsAccum->Allocated++; AllocStatsAccum->AllocatedSize += BlockSize; } } else { //
// "Free " with a space after it before the parentheses means
// it's been freed to a (pool manager internal) lookaside list.
// We used to print "Lookaside" but that just confused driver
// writers because they didn't know if this meant in use or not
// and many would say "but I don't use lookaside lists - the
// extension or kernel is broken".
//
// "Free" with no space after it before the parentheses means
// it is not on a pool manager internal lookaside list and is
// instead on the regular pool manager internal flink/blink
// chains.
//
// Note to anyone using the pool package, these 2 terms are
// equivalent. The fine distinction is only for those actually
// writing pool internal code.
//
OutCtl->Output(" (Free ) ");
if (AllocStatsAccum != NULL) { AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } } } else { OutCtl->Output(" (?) ");
if (AllocStatsAccum != NULL) { AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; } }
if (!(PoolType.I32 & POOL_QUOTA_MASK) || bQuotaWithTag) { OutCtl->Output(" %c%c%c%c%s", Tag->RawBytes[0], Tag->RawBytes[1], Tag->RawBytes[2], (Tag->RawBytes[3] & ~(PROTECTED_POOL >> 24)), ((Tag->I32 & PROTECTED_POOL) ? " (Protected)" : "") );
} if (PoolType.I32 & POOL_QUOTA_MASK && PoolHeadReader->Get(&ProcessBilled, "ProcessBilled", DEBUG_VALUE_INT64) == S_OK && ProcessBilled.I64 != 0) { OutCtl->Output(" Process: 0x%p\n", ProcessBilled.I64); } else { OutCtl->Output("\n"); } } } else { OutCtl->OutErr(" Couldn't determine PoolType\n");
if (AllocStatsAccum != NULL) { AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; } }
return hr; }
typedef struct _TAG_BUCKET : public ALLOCATION_STATS { ULONG Tag; _TAG_BUCKET *pNextTag; } TAG_BUCKET, *PTAG_BUCKET;
typedef enum { AllocatedPool, FreePool, IndeterminatePool, } PoolType;
class AccumTagUsage : public ALLOCATION_STATS { public: AccumTagUsage(ULONG TagFilter); ~AccumTagUsage();
HRESULT Valid(); HRESULT Add(ULONG Tag, PoolType Type, ULONG Size); HRESULT OutputResults(OutputControl *OutCtl, BOOL TagSort); void Reset();
private: ULONG GetHashIndex(ULONG Tag); PTAG_BUCKET GetBucket(ULONG Tag); ULONG SetTagFilter(ULONG TagFilter);
static const HashBitmaskLimit = 10; // For little-endian, must <= 16
HANDLE hHeap; ULONG Buckets; PTAG_BUCKET *Bucket; // Array of buckets
#if BIG_ENDIAN
ULONG HighMask; ULONG HighShift; ULONG LowMask; ULONG LowShift; #else
ULONG HighShiftLeft; ULONG HighShiftRight; ULONG LowShiftRight; ULONG LowMask; #endif
};
AccumTagUsage::AccumTagUsage( ULONG TagFilter ) { hHeap = GetProcessHeap(); Buckets = SetTagFilter(TagFilter); if (Buckets != 0) { Bucket = (PTAG_BUCKET *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, Buckets*sizeof(*Bucket)); Reset(); } else { Bucket = NULL; } }
AccumTagUsage::~AccumTagUsage() { PTAG_BUCKET pB, pBNext; ULONG i;
if (Bucket != NULL) { for (i = 0; i < Buckets; i++) { pB = Bucket[i]; while (pB != NULL) { pBNext = pB->pNextTag; HeapFree(hHeap, 0, pB); pB = pBNext; } }
HeapFree(hHeap, 0, Bucket); } }
HRESULT AccumTagUsage::Valid() { return ((Bucket != NULL) ? S_OK : S_FALSE); }
HRESULT AccumTagUsage::Add( ULONG Tag, PoolType Type, ULONG Size ) { PTAG_BUCKET pBucket = GetBucket(Tag);
if (pBucket == NULL) return E_FAIL;
switch (Type) { case AllocatedPool: pBucket->Allocated++; pBucket->AllocatedSize += Size; break; case FreePool: pBucket->Free++; pBucket->FreeSize += Size; break; case IndeterminatePool: default: pBucket->Indeterminate++; pBucket->IndeterminateSize += Size; break; }
return S_OK; }
HRESULT AccumTagUsage::OutputResults( OutputControl *OutCtl, BOOL AllocSort ) { HRESULT hr; PTAG_BUCKET pB, pBNext; ULONG i;
if (Bucket == NULL) { hr = OutCtl->Output(" No results\n"); } else { CHAR szNormal[] = "%4.4s %8lu %12I64u %8lu %12I64u\n"; CHAR szShowIndeterminate[] = "%4.4s %8lu %12I64u %8lu %12I64u %8lu %12I64u\n"; PSZ pszOutFormat = szNormal;
OutCtl->Output("\n" " %I64u bytes in %lu allocated pages\n" " %I64u bytes in %lu large allocations\n" " %I64u bytes in %lu free pages\n" " %I64u bytes available in %lu expansion pages\n", ((ULONG64) AllocatedPages) << PageShift, AllocatedPages, ((ULONG64) LargePages) << PageShift, LargeAllocs, ((ULONG64) FreePages) << PageShift, FreePages, ((ULONG64) ExpansionPages) << PageShift, ExpansionPages);
OutCtl->Output("\nTag Allocs Bytes Freed Bytes"); if (Indeterminate != 0) { OutCtl->Output(" Unknown Bytes"); pszOutFormat = szShowIndeterminate; } OutCtl->Output("\n");
if (AllocSort) { OutCtl->OutWarn(" Sorting by allocation size isn't supported.\n"); } //else
{ // Output results sorted by Tag (natural storage order)
for (i = 0; i < Buckets; i++) { for (pB = Bucket[i]; pB != NULL; pB = pB->pNextTag) { if (pB->Allocated) { OutCtl->Output(pszOutFormat, &pB->Tag, pB->Allocated, ((ULONG64)pB->AllocatedSize) << POOL_BLOCK_SHIFT, pB->Free, ((ULONG64)pB->FreeSize) << POOL_BLOCK_SHIFT, pB->Indeterminate, ((ULONG64)pB->IndeterminateSize) << POOL_BLOCK_SHIFT ); } } } }
OutCtl->Output("-------------------------------------------------------------------------------\n"); hr = OutCtl->Output(pszOutFormat, "Ttl:", Allocated, ((ULONG64)AllocatedSize) << POOL_BLOCK_SHIFT, Free, ((ULONG64)FreeSize) << POOL_BLOCK_SHIFT, Indeterminate, ((ULONG64)IndeterminateSize) << POOL_BLOCK_SHIFT ); }
return hr; }
void AccumTagUsage::Reset() { PTAG_BUCKET pB, pBNext; ULONG i;
AllocatedPages = 0; LargePages = 0; LargeAllocs = 0; FreePages = 0; ExpansionPages = 0;
Allocated = 0; AllocatedSize = 0; Free = 0; FreeSize = 0; Indeterminate = 0; IndeterminateSize = 0;
if (Bucket != NULL) { for (i = 0; i < Buckets; i++) { pB = Bucket[i]; if (pB != NULL) { do { pBNext = pB->pNextTag; HeapFree(hHeap, 0, pB); pB = pBNext; } while (pB != NULL);
Bucket[i] = NULL; } } } }
ULONG AccumTagUsage::GetHashIndex( ULONG Tag ) { #if BIG_ENDIAN
return (((Tag & HighMask) >> HighShift) | ((Tag & LowMask) >> LowShift)); #else
return ((((Tag << HighShiftLeft) >> HighShiftRight) & ~LowMask) | ((Tag >> LowShiftRight) & LowMask)); #endif
}
PTAG_BUCKET AccumTagUsage::GetBucket( ULONG Tag ) { ULONG Index = GetHashIndex(Tag); PTAG_BUCKET pB = Bucket[Index];
if (pB == NULL || #if BIG_ENDIAN
pB->Tag > Tag #else
strncmp((char *)&pB->Tag, (char *)&Tag, 4) > 0 #endif
) { pB = (PTAG_BUCKET)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(TAG_BUCKET));
if (pB != NULL) { pB->Tag = Tag; pB->pNextTag = Bucket[Index]; Bucket[Index] = pB; } } else { while (pB->pNextTag != NULL) { if ( #if BIG_ENDIAN
pB->pNextTag->Tag > Tag #else
strncmp((char *)&pB->pNextTag->Tag, (char *)&Tag, 4) > 0 #endif
) { break; }
pB = pB->pNextTag; }
if (pB->Tag != Tag) { PTAG_BUCKET pBPrev = pB;
pB = (PTAG_BUCKET)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(TAG_BUCKET));
if (pB != NULL) { pB->Tag = Tag; pB->pNextTag = pBPrev->pNextTag; pBPrev->pNextTag = pB; } } }
return pB; }
ULONG AccumTagUsage::SetTagFilter( ULONG TagFilter ) { ULONG NumBuckets; UCHAR *Filter = (UCHAR *)&TagFilter; ULONG i; ULONG HighMaskBits, LowMaskBits; UCHAR fc;
#if BIG_ENDIAN
ULONG Mask = 0; ULONG MaskBits = 0;
if (Filter[0] == '*') { Mask = -1; MaskBits = 32; } else { for ( i = 0; i < 32; i += 8 ) { Mask <<= 8; fc = *Filter++;
if ( fc == '*' ) { Mask |= ((1 << i) - 1); MaskBits += 32 - i; break; }
if ( fc == '?' ) { Mask |= 0xFF; MaskBits += 8; } } }
if (MaskBits > HashBitmaskLimit) { MaskBits = HashBitmaskLimit; }
NumBuckets = (1 << MaskBits);
for (HighShift = 32, HighMaskBits = 0; HighShift > 0 && HighMaskBits < MaskBits; HighShift--) { if (Mask & (1 << (HighShift-1))) { HighMaskBits++; } else if (HighMaskBits) { break; } }
HighMask = Mask & ~((1 << HighShift) - 1); Mask &= ~HighMask; MaskBits -= HighMaskBits; HighShift -= MaskBits;
for (LowShift = HighShift, LowMaskBits = 0; LowShift > 0 && LowMaskBits < MaskBits; LowShift--) { if (Mask & (1 << (LowShift-1))) { LowMaskBits++; } else if (LowMaskBits) { break; } }
LowMask = Mask & ~((1 << LowShift) - 1);
#else
HighMaskBits = 0; LowMaskBits = 0;
HighShiftLeft = 32; HighShiftRight = 32; LowShiftRight = 32; LowMask = 0;
for ( i = 0; i < 32; i += 8 ) { fc = *Filter++;
if ( fc == '*' ) { if (HighMaskBits == 0) { HighMaskBits = min(8, HashBitmaskLimit); HighShiftLeft = 32 - HighMaskBits - i; HighShiftRight = 32 - HighMaskBits;
LowMaskBits = ((HighShiftLeft != 0) ? min(8, HashBitmaskLimit - HighMaskBits) : 0); HighShiftRight -= LowMaskBits; LowShiftRight = (8 - LowMaskBits) + HighMaskBits + i; LowMask = (1 << LowMaskBits) - 1; } else { LowMaskBits = min(8, HashBitmaskLimit - HighMaskBits); HighShiftRight -= LowMaskBits; LowShiftRight = (8 - LowMaskBits) + i; LowMask = (1 << LowMaskBits) - 1; } break; }
if ( fc == '?' ) { if (HighMaskBits == 0) { HighMaskBits = min(8, HashBitmaskLimit); HighShiftLeft = 32 - HighMaskBits - i; HighShiftRight = 32 - HighMaskBits; } else { LowMaskBits = min(8, HashBitmaskLimit - HighMaskBits); HighShiftRight -= LowMaskBits; LowShiftRight = (8 - LowMaskBits) + i; LowMask = (1 << LowMaskBits) - 1; break; } } }
NumBuckets = 1 << (HighMaskBits + LowMaskBits);
#endif
if (NumBuckets-1 != GetHashIndex(-1)) { DbgPrint("AccumTagUsage::SetTagFilter: Invalid hash was generated.\n"); NumBuckets = 0; }
return NumBuckets; }
HRESULT AccumTagUsageFilter( OutputControl *OutCtl, ULONG64 PoolAddr, ULONG TagFilter, TypeOutputParser *PoolHeadReader, PDEBUG_VALUE Tag, ULONG BlockSize, BOOL bQuotaWithTag, PVOID Context ) { HRESULT hr; DEBUG_VALUE PoolType; AccumTagUsage *atu = (AccumTagUsage *)Context; PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)atu;
if (CheckSingleFilter(Tag->RawBytes, (PUCHAR)&TagFilter) != S_OK) { return S_FALSE; }
hr = PoolHeadReader->Get(&PoolType, "PoolType", DEBUG_VALUE_INT32);
if (hr == S_OK) { if (PoolType.I32 == 0) { hr = atu->Add(Tag->I32, FreePool, BlockSize); AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } else { DEBUG_VALUE PoolIndex;
if (!(PoolType.I32 & POOL_QUOTA_MASK) || bQuotaWithTag) { Tag->I32 &= ~PROTECTED_POOL; } else if (PoolType.I32 & POOL_QUOTA_MASK) { Tag->I32 = 'CORP'; }
if (!NewPool) { hr = PoolHeadReader->Get(&PoolIndex, "PoolIndex", DEBUG_VALUE_INT32); }
if (hr == S_OK) { if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80)) { hr = atu->Add(Tag->I32, AllocatedPool, BlockSize); AllocStatsAccum->Allocated++; AllocStatsAccum->AllocatedSize += BlockSize;
if (AllocStatsAccum->Allocated % 100 == 0) { OutCtl->Output(".");
if (AllocStatsAccum->Allocated % 8000 == 0) { OutCtl->Output("\n"); } } } else { hr = atu->Add(Tag->I32, FreePool, BlockSize); AllocStatsAccum->Free++; AllocStatsAccum->FreeSize += BlockSize; } } else { hr = atu->Add(Tag->I32, IndeterminatePool, BlockSize); AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; } } } else { AllocStatsAccum->Indeterminate++; AllocStatsAccum->IndeterminateSize += BlockSize; }
return hr; }
HRESULT SearchSessionPool( PDEBUG_CLIENT Client, ULONG Session, ULONG TagName, FLONG Flags, ULONG64 RestartAddr, PoolFilterFunc Filter, PALLOCATION_STATS AllocStats, PVOID Context ) /*++
Routine Description:
Engine to search session pool.
Arguments:
TagName - Supplies the tag to search for.
Flags - Supplies 0 if a nonpaged pool search is desired. Supplies 1 if a paged pool search is desired.
RestartAddr - Supplies the address to restart the search from.
Filter - Supplies the filter routine to use.
Context - Supplies the user defined context blob.
Return Value:
HRESULT
--*/ { HRESULT hr;
OutputControl OutCtl(Client);
PDEBUG_SYMBOLS Symbols; PDEBUG_DATA_SPACES Data;
LOGICAL PhysicallyContiguous; ULONG PoolBlockSize; ULONG64 PoolHeader; ULONG64 PoolPage; ULONG64 StartPage; ULONG64 Pool; ULONG Previous; ULONG64 PoolStart; ULONG64 PoolStartPage; ULONG64 PoolPteAddress; ULONG64 PoolEnd; BOOL PageReadFailed; ULONG64 PagesRead; ULONG64 PageReadFailures; ULONG64 PageReadFailuresAtEnd; ULONG64 LastPageRead;
ULONG PoolTypeFlags = Flags & (SEARCH_POOL_NONPAGED | SEARCH_POOL_PAGED);
ULONG64 NTModuleBase; ULONG PoolHeadTypeID; ULONG SessionHeadTypeID; ULONG HdrSize;
ULONG64 SessionSpace;
if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols)) != S_OK) { return hr; }
if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&Data)) != S_OK) { Symbols->Release(); return hr; }
if (Session == DEFAULT_SESSION) { Session = SessionId; }
if ((hr = Symbols->GetSymbolTypeId("NT!_POOL_HEADER", &PoolHeadTypeID, &NTModuleBase)) == S_OK && (hr = Symbols->GetTypeSize(NTModuleBase, PoolHeadTypeID, & HdrSize)) == S_OK && (hr = GetSessionSpace(Client, Session, &SessionSpace)) == S_OK) { ULONG PoolTagOffset, ProcessBilledOffset; BOOL bQuotaWithTag;
DEBUG_VALUE ReadSessionId; DEBUG_VALUE PagedPoolInfo;
DEBUG_VALUE NonPagedPoolBytes; DEBUG_VALUE NonPagedPoolAllocations; DEBUG_VALUE NonPagedPoolStart; DEBUG_VALUE NonPagedPoolEnd;
DEBUG_VALUE PagedPoolPages; DEBUG_VALUE PagedPoolBytes; DEBUG_VALUE PagedPoolAllocations; DEBUG_VALUE PagedPoolStart; DEBUG_VALUE PagedPoolEnd;
ULONG SessionSpaceTypeID; ULONG PagedPoolInfoOffset; TypeOutputParser SessionParser(Client); // Dump of MM_SESSION_SPACE
TypeOutputParser PoolHeadReader(Client); OutputState OutState(Client);
BOOL SearchingPaged = FALSE; PRTL_BITMAP PagedPoolAllocationMap = NULL; PRTL_BITMAP EndOfPagedPoolBitmap = NULL; ULONG BusyStart; PRTL_BITMAP PagedPoolLargeSessionAllocationMap = NULL;
BOOL Continue = TRUE;
bQuotaWithTag = (Symbols->GetFieldOffset(NTModuleBase, PoolHeadTypeID, "PoolTag", &PoolTagOffset) == S_OK && Symbols->GetFieldOffset(NTModuleBase, PoolHeadTypeID, "ProcessBilled", &ProcessBilledOffset) == S_OK && PoolTagOffset != ProcessBilledOffset);
// General parser setup and dump MM_SESSION_SPACE structure
if ((hr = OutState.Setup(0, &SessionParser)) == S_OK && (hr = Symbols->GetTypeId(NTModuleBase, "MM_SESSION_SPACE", &SessionSpaceTypeID)) == S_OK && ((hr = OutState.OutputTypeVirtual(SessionSpace, NTModuleBase, SessionSpaceTypeID, DEBUG_OUTTYPE_BLOCK_RECURSE)) == S_OK || ((hr = OutState.OutputTypeVirtual(SessionSpace, NTModuleBase, SessionSpaceTypeID, 0)) == S_OK && (hr = Symbols->GetFieldOffset(NTModuleBase, SessionSpaceTypeID, "PagedPoolInfo", &PagedPoolInfoOffset)) == S_OK && (hr = OutState.OutputTypeVirtual(SessionSpace + PagedPoolInfoOffset, "NT!_MM_PAGED_POOL_INFO", 0)) == S_OK )) && (hr = SessionParser.Get(&ReadSessionId, "SessionId", DEBUG_VALUE_INT32)) == S_OK) { OutCtl.Output("Searching session %ld pool.\n", ReadSessionId.I32);
// Remaining type output goes to PoolHead reader
hr = OutState.Setup(0, &PoolHeadReader); } else { OutCtl.OutErr("Error getting basic session pool information.\n"); }
while (hr == S_OK && Continue) { OutCtl.Output("\n");
if (PoolTypeFlags & SEARCH_POOL_NONPAGED) { if (SessionParser.Get(&NonPagedPoolBytes, "NonPagedPoolBytes", DEBUG_VALUE_INT64) == S_OK && SessionParser.Get(&NonPagedPoolAllocations, "NonPagedPoolAllocations", DEBUG_VALUE_INT64) == S_OK) { OutCtl.Output("NonPaged pool: %I64u bytes in %I64u allocations\n", NonPagedPoolBytes.I64, NonPagedPoolAllocations.I64); }
OutCtl.Output(" NonPaged pool range reader isn't implemented.\n");
PoolStart = 0; PoolEnd = 0; SearchingPaged = FALSE; } else { if (SessionParser.Get(&PagedPoolBytes, "PagedPoolBytes", DEBUG_VALUE_INT64) == S_OK && SessionParser.Get(&PagedPoolAllocations, "PagedPoolAllocations", DEBUG_VALUE_INT64) == S_OK) { OutCtl.Output("Paged pool: %I64u bytes in %I64u allocations\n", PagedPoolBytes.I64, PagedPoolAllocations.I64);
if (SessionParser.Get(&PagedPoolPages, "AllocatedPagedPool", DEBUG_VALUE_INT64) == S_OK) { OutCtl.Output(" Paged Pool Info: %I64u pages allocated\n", PagedPoolPages.I64); } }
if ((hr = SessionParser.Get(&PagedPoolStart, "PagedPoolStart", DEBUG_VALUE_INT64)) != S_OK || (hr = SessionParser.Get(&PagedPoolEnd, "PagedPoolEnd", DEBUG_VALUE_INT64)) != S_OK) { OutCtl.OutErr(" Couldn't get PagedPool range.\n"); } else { PoolStart = PagedPoolStart.I64; PoolEnd = PagedPoolEnd.I64; SearchingPaged = TRUE;
DEBUG_VALUE PagedBitMap;
if (SessionParser.Get(&PagedBitMap, "PagedPoolAllocationMap", DEBUG_VALUE_INT64) == S_OK && GetBitMap(Client, PagedBitMap.I64, &PagedPoolAllocationMap) == S_OK && SessionParser.Get(&PagedBitMap, "EndOfPagedPoolBitmap", DEBUG_VALUE_INT64) == S_OK && GetBitMap(Client, PagedBitMap.I64, &EndOfPagedPoolBitmap) == S_OK) { ULONG PositionAfterLastAlloc; ULONG AllocBits; ULONG UnusedBusyBits;
if (RtlCheckBit(EndOfPagedPoolBitmap, EndOfPagedPoolBitmap->SizeOfBitMap - 1)) { BusyStart = PagedPoolAllocationMap->SizeOfBitMap; UnusedBusyBits = 0; } else { OSCompat_RtlFindLastBackwardRunClear( EndOfPagedPoolBitmap, EndOfPagedPoolBitmap->SizeOfBitMap - 1, &PositionAfterLastAlloc);
BusyStart = RtlFindSetBits(PagedPoolAllocationMap, 1, PositionAfterLastAlloc); if (BusyStart < PositionAfterLastAlloc || BusyStart == -1) { BusyStart = PagedPoolAllocationMap->SizeOfBitMap; UnusedBusyBits = 0; } else { UnusedBusyBits = PagedPoolAllocationMap->SizeOfBitMap - BusyStart; } }
AllocBits = RtlNumberOfSetBits(PagedPoolAllocationMap) - UnusedBusyBits;
AllocStats->AllocatedPages += AllocBits; AllocStats->FreePages += (BusyStart - AllocBits); AllocStats->ExpansionPages += UnusedBusyBits;
if (SessionParser.Get(&PagedBitMap, "PagedPoolLargeSessionAllocationMap", DEBUG_VALUE_INT64) == S_OK && GetBitMap(Client, PagedBitMap.I64, &PagedPoolLargeSessionAllocationMap) == S_OK) { ULONG AllocStart, AllocEnd; ULONG LargeAllocs = RtlNumberOfSetBits(PagedPoolLargeSessionAllocationMap);
AllocStats->LargeAllocs += LargeAllocs;
AllocStart = 0; AllocEnd = -1;
while (LargeAllocs > 0) { AllocStart = RtlFindSetBits(PagedPoolLargeSessionAllocationMap, 1, AllocStart); if (AllocStart >= AllocEnd+1 && AllocStart != -1) { AllocEnd = RtlFindSetBits(EndOfPagedPoolBitmap, 1, AllocStart); if (AllocEnd >= AllocStart && AllocEnd != -1) { AllocStats->LargePages += AllocEnd - AllocStart + 1; AllocStart++; LargeAllocs--; } else { OutCtl.OutWarn(" Warning Large Pool Allocation Map or End Of Pool Map is invalid.\n"); break; } } else { OutCtl.OutWarn(" Warning Large Pool Allocation Map is invalid.\n"); break; } }
if (LargeAllocs != 0) { OutCtl.OutWarn(" %lu large allocations weren't calculated.\n", LargeAllocs); AllocStats->LargeAllocs -= LargeAllocs; } } } } }
if (hr == S_OK) { OutCtl.Output("Searching %s pool (0x%p : 0x%p) for Tag: %c%c%c%c\r\n\n", ((PoolTypeFlags & SEARCH_POOL_NONPAGED) ? "NonPaged" : "Paged"), PoolStart, PoolEnd, TagName, TagName >> 8, TagName >> 16, TagName >> 24);
PageReadFailed = FALSE; PoolStartPage = PAGE_ALIGN64(PoolStart); PoolPage = PoolStart; PagesRead = 0; PageReadFailures = 0; PageReadFailuresAtEnd = 0; LastPageRead = PAGE_ALIGN64(PoolPage);
while (PoolPage < PoolEnd && hr == S_OK) { Pool = PAGE_ALIGN64(PoolPage); StartPage = Pool; Previous = 0;
if (Session != CURRENT_SESSION) { OutCtl.Output("Currently only searching the current session is supported.\n"); PoolPage = PoolEnd; break; }
if (OutCtl.GetInterrupt() == S_OK) { OutCtl.Output("\n...terminating - searched pool to 0x%p\n", Pool-1); hr = E_ABORT; break; }
if (SearchingPaged) { if (PagedPoolAllocationMap != NULL) { ULONG StartPosition, EndPosition;
StartPosition = (ULONG)((Pool - PoolStartPage) >> PageShift); EndPosition = RtlFindSetBits(EndOfPagedPoolBitmap, 1, StartPosition); if (EndPosition < StartPosition) EndPosition = -1;
if (!RtlCheckBit(PagedPoolAllocationMap, StartPosition)) { if (PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p\n", StartPage-1); }
PageReadFailures += (StartPage - LastPageRead) >> PageShift; LastPageRead = StartPage; PageReadFailed = FALSE; }
if (EndPosition == -1) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn("No remaining pool allocations from 0x%p to 0x%p.\n", Pool, PoolEnd); }
PoolPage = PoolEnd; } else { PoolPage = PoolStartPage + (((ULONG64)EndPosition + 1) << PageShift); }
continue; } else if (EndOfPagedPoolBitmap != NULL) { if (PagedPoolLargeSessionAllocationMap != NULL && RtlCheckBit(PagedPoolLargeSessionAllocationMap, StartPosition)) { if (EndPosition == -1) { OutCtl.OutWarn("No end to large pool allocation @ 0x%p found.\n", Pool); PoolPage = PoolEnd; } else { EndPosition++;
if (PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p\n", StartPage-1); }
PageReadFailures += (StartPage - LastPageRead) >> PageShift; LastPageRead = StartPage; PageReadFailed = FALSE; }
PoolPage = PoolStartPage + (((ULONG64)EndPosition) << PageShift);
if (Flags & SEARCH_POOL_PRINT_LARGE) { OutCtl.Output("0x%p size: %5I64x %s UNTAGGED Large\n", StartPage, PoolPage - StartPage, ((RtlAreBitsSet(PagedPoolAllocationMap, StartPosition, EndPosition - StartPosition)) ? "(Allocated)" : ((RtlAreBitsClear(PagedPoolAllocationMap, StartPosition, EndPosition - StartPosition)) ? "(! Free !) " : "(!! Partially Allocated !!)")) ); }
if (Flags & SEARCH_POOL_LARGE_ONLY) { // Quickly locate next large allocation
StartPosition = RtlFindSetBits(PagedPoolLargeSessionAllocationMap, 1, EndPosition);
if (StartPosition < EndPosition || StartPosition == -1) { OutCtl.OutVerb(" No large allocations found after 0x%p\n", PoolPage-1); PoolPage = PoolEnd; } else { PoolPage = PoolStartPage + (((ULONG64)StartPosition) << PageShift); } } }
continue; } else if (EndPosition == -1) { if (PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p\n", StartPage-1); }
PageReadFailures += (StartPage - LastPageRead) >> PageShift; LastPageRead = StartPage; PageReadFailed = FALSE; }
if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn("No remaining pool allocations from 0x%p to 0x%p.\n", Pool, PoolEnd); }
PoolPage = PoolEnd;
continue; } else if (StartPosition >= BusyStart) { OutCtl.OutWarn("Found end of allocation at %lu within expansion pages starting at %lu.\n", EndPosition, BusyStart); } } } }
if (Flags & SEARCH_POOL_LARGE_ONLY) { OutCtl.OutErr(" Unable to identify large pages. Terminating search at 0x%p.\n", StartPage); PoolPage = PoolEnd; hr = E_FAIL; continue; }
// Search page for small allocations
while (PAGE_ALIGN64(Pool) == StartPage && hr == S_OK) { DEBUG_VALUE HdrPoolTag, BlockSize, PreviousSize, AllocatorBackTraceIndex, PoolTagHash; ULONG PoolType;
PoolHeadReader.DiscardOutput();
if ((hr = OutState.OutputType(FALSE, Pool, NTModuleBase, PoolHeadTypeID, 0)) != S_OK || PoolHeadReader.Get(&HdrPoolTag, "PoolTag", DEBUG_VALUE_INT32) != S_OK) { if (hr != S_OK) { PSTR psz;
OutCtl.OutErr("Type read error %s @ 0x%p.\n", pszHRESULT(hr), Pool);
OutCtl.OutWarn("Failed to read an allocated page @ 0x%p.\n", StartPage);
if (PoolHeadReader.GetOutputCopy(&psz) == S_OK) { if (strchr(psz, '?') != NULL) { hr = S_OK; } else { OutCtl.OutVerb("PoolHeadReader contains:\n" "%s\n", psz);
OutCtl.Output("\n...terminating - searched pool to 0x%p\n", Pool); hr = E_ABORT; }
PoolHeadReader.FreeOutputCopy(psz); }
if (hr == E_ABORT) { break; } }
if (!PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" Couldn't read pool from 0x%p", Pool); }
PagesRead += (StartPage - LastPageRead) / PageSize; LastPageRead = StartPage; PageReadFailed = TRUE; }
if ((hr = GetNextResidentAddress(Client, Session, StartPage + PageSize, PoolEnd, &PoolPage, NULL)) != S_OK) { if (hr != E_ABORT) { hr = S_OK; }
if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p.\n", PoolEnd); OutCtl.OutWarn("No remaining resident page found.\n"); }
PageReadFailuresAtEnd = (PoolEnd - LastPageRead) / PageSize; PageReadFailures += PageReadFailuresAtEnd; LastPageRead = PoolEnd; PageReadFailed = FALSE;
PoolPage = PoolEnd; }
break; }
if (PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p\n", StartPage-1); }
PageReadFailures += (StartPage - LastPageRead) / PageSize; LastPageRead = StartPage; PageReadFailed = FALSE; }
if (PoolHeadReader.Get(&BlockSize, "BlockSize", DEBUG_VALUE_INT32) != S_OK) { OutCtl.OutErr("Error reading BlockSize @ 0x%p.\n", Pool); break; }
if ((BlockSize.I32 << POOL_BLOCK_SHIFT) > PageSize)//POOL_PAGE_SIZE)
{ OutCtl.OutVerb("Bad allocation size @ 0x%p, too large\n", Pool); break; }
if (BlockSize.I32 == 0) { OutCtl.OutVerb("Bad allocation size @ 0x%p, zero is invalid\n", Pool); break; }
if (PoolHeadReader.Get(&PreviousSize, "PreviousSize", DEBUG_VALUE_INT32) != S_OK || PreviousSize.I32 != Previous) { OutCtl.OutVerb("Bad previous allocation size @ 0x%p, last size was 0x%lx\n", Pool, Previous); break; }
Filter(&OutCtl, Pool, TagName, &PoolHeadReader, &HdrPoolTag, BlockSize.I32, bQuotaWithTag, Context );
Previous = BlockSize.I32; Pool += (Previous << POOL_BLOCK_SHIFT);
if ( OutCtl.GetInterrupt() == S_OK) { OutCtl.Output("\n...terminating - searched pool to 0x%p\n", PoolPage-1); hr = E_ABORT; } }
if (hr == S_OK) { PoolPage = (PoolPage + PageSize); } }
if (PageReadFailed) { if (Flags & SEARCH_POOL_PRINT_UNREAD) { OutCtl.OutWarn(" to 0x%p\n", StartPage-1); }
PageReadFailuresAtEnd = (PoolPage - LastPageRead) / PageSize; PageReadFailures += PageReadFailuresAtEnd; PageReadFailed = FALSE; } else { PagesRead += (PoolPage - LastPageRead) / PageSize; }
OutCtl.Output(" Pages Read: %I64d\n" " Failures: %I64d (%I64d at end of search)\n", PagesRead, PageReadFailures, PageReadFailuresAtEnd); }
if (PoolTypeFlags == (SEARCH_POOL_NONPAGED | SEARCH_POOL_PAGED)) { PoolTypeFlags = SEARCH_POOL_PAGED; } else { Continue = FALSE; } }
if (PagedPoolAllocationMap != NULL) FreeBitMap(PagedPoolAllocationMap); if (EndOfPagedPoolBitmap != NULL) FreeBitMap(EndOfPagedPoolBitmap); if (PagedPoolLargeSessionAllocationMap != NULL) FreeBitMap(PagedPoolLargeSessionAllocationMap); }
return hr; }
HRESULT GetTagFilter( PDEBUG_CLIENT Client, PCSTR *pArgs, PDEBUG_VALUE TagFilter ) { HRESULT hr;
PCSTR args; PCSTR TagArg;
ULONG TagLen; CHAR TagEnd; ULONG WildCardPos;
OutputControl OutCtl(Client);
TagArg = args = *pArgs; TagFilter->Type = DEBUG_VALUE_INVALID;
do { args++; } while (*args != '\0' && !isspace(*args));
while (isspace(*args)) args++;
if (TagArg[0] == '0' && TagArg[1] == 'x') { hr = Evaluate(Client, TagArg, DEBUG_VALUE_INT64, EVALUATE_DEFAULT_RADIX, TagFilter, NULL, NULL, EVALUATE_COMPACT_EXPR); } else { if (TagArg[0] == '`' || TagArg[0] == '\'' || TagArg[0] == '\"') { TagEnd = TagArg[0]; TagArg++; args = TagArg;
while (args - TagArg < 4 && *args != '\0' && *args != TagEnd) { args++; } TagLen = (ULONG)(args - TagArg); if (*args == TagEnd) args++; while (isspace(*args)) args++; } else { TagLen = (ULONG)(args - TagArg); TagEnd = '\0'; }
if (TagLen == 0 || (TagLen < 4 && TagArg[TagLen-1] != '*' ) || (TagLen >= 4 && TagArg[4] != '\0' && !isspace(TagArg[4]) && (TagArg[4] != TagEnd || (TagArg[5] != '\0' && !isspace(TagArg[5]))) ) ) { OutCtl.OutErr(" Invalid Tag filter.\n"); hr = E_INVALIDARG; } else { hr = S_OK;
for (WildCardPos = 0; WildCardPos < TagLen; WildCardPos++) { if (TagArg[WildCardPos] == '*') { ULONG NewTagLen = WildCardPos + 1; if (NewTagLen < TagLen) { OutCtl.OutWarn(" Ignoring %lu characters after * in Tag.\n", TagLen - NewTagLen); } TagLen = NewTagLen; // loop will terminate
} }
if (TagLen < 4) { TagFilter->I32 = ' '; while (TagLen-- > 0) { TagFilter->RawBytes[TagLen] = TagArg[TagLen]; } } else { TagFilter->I32 = TagArg[0] | (TagArg[1] << 8) | (TagArg[2] << 16) | (TagArg[3] << 24); } TagFilter->Type = DEBUG_VALUE_INT32; } }
if (hr == S_OK) { *pArgs = args; }
return hr; }
HRESULT OutputAllocStats( OutputControl *OutCtl, PALLOCATION_STATS AllocStats, BOOL PartialResults ) { return OutCtl->Output("\n" " %I64u bytes in %lu allocated pages\n" " %I64u bytes in %lu large allocations\n" " %I64u bytes in %lu free pages\n" " %I64u bytes available in %lu expansion pages\n" "\n" "%s found (small allocations only): %lu\n" " Allocated: %I64u bytes in %lu entries\n" " Free: %I64u bytes in %lu entries\n" " Undetermined: %I64u bytes in %lu entries\n", ((ULONG64) AllocStats->AllocatedPages) << PageShift, AllocStats->AllocatedPages, ((ULONG64) AllocStats->LargePages) << PageShift, AllocStats->LargeAllocs, ((ULONG64) AllocStats->FreePages) << PageShift, AllocStats->FreePages, ((ULONG64) AllocStats->ExpansionPages) << PageShift, AllocStats->ExpansionPages, ((PartialResults) ? "PARTIAL entries" : "Entries"), AllocStats->Allocated + AllocStats->Free + AllocStats->Indeterminate, ((ULONG64)AllocStats->AllocatedSize) << POOL_BLOCK_SHIFT, AllocStats->Allocated, ((ULONG64)AllocStats->FreeSize) << POOL_BLOCK_SHIFT, AllocStats->Free, ((ULONG64)AllocStats->IndeterminateSize) << POOL_BLOCK_SHIFT, AllocStats->Indeterminate ); }
DECLARE_API( spoolfind ) { HRESULT hr = S_OK; BEGIN_API( spoolfind );
BOOL BadArg = FALSE; ULONG RemainingArgIndex;
DEBUG_VALUE TagName = { 0, DEBUG_VALUE_INVALID };
FLONG Flags = 0; DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID }; OutputControl OutCtl(Client);
while (isspace(*args)) args++;
while (!BadArg && hr == S_OK) { while (isspace(*args)) args++;
if (*args == '-') { // Process switches
args++; BadArg = (*args == '\0' || isspace(*args));
while (*args != '\0' && !isspace(*args)) { switch (tolower(*args)) { case 'f': Flags |= SEARCH_POOL_PRINT_UNREAD; args++; break;
case 'l': Flags |= SEARCH_POOL_PRINT_LARGE; args++; break;
case 'n': Flags |= SEARCH_POOL_NONPAGED; args++; break;
case 'p': Flags |= SEARCH_POOL_PAGED; args++; break;
case 's': if (Session.Type != DEBUG_VALUE_INVALID) { OutCtl.OutErr("Session argument specified multiple times.\n"); BadArg = TRUE; } else { args++; hr = Evaluate(Client, args, DEBUG_VALUE_INT32, 10, &Session, &RemainingArgIndex); if (hr != S_OK) { OutCtl.OutErr("Invalid Session.\n"); } else { args += RemainingArgIndex; } } break;
default: BadArg = TRUE; break; }
if (BadArg) break; } } else { if (*args == '\0') break;
if (TagName.Type == DEBUG_VALUE_INVALID) { hr = GetTagFilter(Client, &args, &TagName); } else { OutCtl.OutErr("Unrecognized argument @ %s\n", args); BadArg = TRUE; } } }
if (!BadArg && hr == S_OK) { if (TagName.Type == DEBUG_VALUE_INVALID) { if (Flags & SEARCH_POOL_PRINT_LARGE) { TagName.I32 = ' *'; Flags |= SEARCH_POOL_LARGE_ONLY; } else { OutCtl.OutErr("Missing Tag.\n"); hr = E_INVALIDARG; } } }
if (BadArg || hr != S_OK) { if (*args == '?') { OutCtl.Output("spoolfind is like !kdexts.poolfind, but for the SessionId specified.\n" "\n"); }
OutCtl.Output("Usage: spoolfind [-lnpf] [-s SessionId] Tag\n" " -f - show read failure ranges\n" " -l - show large allocations\n" " -n - show non-paged pool\n" " -p - show paged pool\n" "\n" " Tag - Pool tag to search for\n" " Can be 4 character string or\n" " hex value in 0xXXXX format\n" "\n" " SessionId - session to dump\n" " Special SessionId values:\n" " -1 - current session\n" " -2 - last !session SessionId (default)\n" ); } else { ALLOCATION_STATS AllocStats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
if ((Flags & (SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED)) == 0) { Flags |= SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED; }
if (Session.Type == DEBUG_VALUE_INVALID) { Session.I32 = DEFAULT_SESSION; }
hr = SearchSessionPool(Client, Session.I32, TagName.I32, Flags, 0, CheckPrintAndAccumFilter, &AllocStats, &AllocStats);
if (hr == S_OK || hr == E_ABORT) { OutputAllocStats(&OutCtl, &AllocStats, (hr != S_OK)); } else { OutCtl.OutWarn("SearchSessionPool returned %s\n", pszHRESULT(hr)); } }
return hr; }
DECLARE_API( spoolsum ) { HRESULT hr = S_OK; BEGIN_API( spoolsum );
ULONG RemainingArgIndex;
FLONG Flags = 0; DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID }; OutputControl OutCtl(Client);
while (isspace(*args)) args++;
while (hr == S_OK) { while (isspace(*args)) args++;
if (*args == '-') { // Process switches
args++; if (*args == '\0' || isspace(*args)) hr = E_INVALIDARG;
while (*args != '\0' && !isspace(*args)) { switch (tolower(*args)) { case 'f': Flags |= SEARCH_POOL_PRINT_UNREAD; args++; break;
case 'n': Flags |= SEARCH_POOL_NONPAGED; args++; break;
case 'p': Flags |= SEARCH_POOL_PAGED; args++; break;
case 's': if (Session.Type != DEBUG_VALUE_INVALID) { OutCtl.OutErr("Session argument specified multiple times.\n"); hr = E_INVALIDARG; } else { args++; hr = Evaluate(Client, args, DEBUG_VALUE_INT32, 10, &Session, &RemainingArgIndex); if (hr != S_OK) { OutCtl.OutErr("Invalid Session.\n"); } else { args += RemainingArgIndex; } } break;
default: hr = E_INVALIDARG; break; }
if (hr != S_OK) break; } } else { if (*args == '\0') break;
if (Session.Type == DEBUG_VALUE_INVALID) { hr = Evaluate(Client, args, DEBUG_VALUE_INT32, 10, &Session, &RemainingArgIndex); if (hr != S_OK) { OutCtl.OutErr("Invalid Session.\n"); } else { args += RemainingArgIndex; } } else { OutCtl.OutErr("Unrecognized argument @ %s\n", args); hr = E_INVALIDARG; } } }
if (hr != S_OK) { if (*args == '?') { OutCtl.Output("spoolsum summarizes session pool information for SessionId specified.\n" "\n"); hr = S_OK; }
OutCtl.Output("Usage: spoolsum [-fnp] [[-s] SessionId]\n" " f - show read failure ranges\n" " n - show non-paged pool\n" " p - show paged pool (Default)\n" "\n" " SessionId - session to dump\n" " Special SessionId values:\n" " -1 - current session\n" " -2 - last !session SessionId (default)\n" ); } else { ALLOCATION_STATS AllocStats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; if ((Flags & (SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED)) == 0) { Flags |= SEARCH_POOL_PAGED; }
hr = SearchSessionPool(Client, DEFAULT_SESSION, ' *', Flags, 0, AccumAllFilter, &AllocStats, &AllocStats); if (hr == S_OK || hr == E_ABORT) { OutputAllocStats(&OutCtl, &AllocStats, (hr != S_OK)); } else { OutCtl.OutWarn("SearchSessionPool returned %s\n", pszHRESULT(hr)); } }
return hr; }
DECLARE_API( spoolused ) { HRESULT hr = S_OK; BEGIN_API( spoolused );
BOOL BadArg = FALSE; ULONG RemainingArgIndex;
DEBUG_VALUE TagName = { 0, DEBUG_VALUE_INVALID };
BOOL NonPagedUsage = FALSE; BOOL PagedUsage = FALSE; BOOL AllocSort = FALSE; DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID }; OutputControl OutCtl(Client);
while (isspace(*args)) args++;
while (!BadArg && hr == S_OK) { while (isspace(*args)) args++;
if (*args == '-') { // Process switches
args++; BadArg = (*args == '\0' || isspace(*args));
while (*args != '\0' && !isspace(*args)) { switch (tolower(*args)) { case 'a': AllocSort = TRUE; args++; break;
case 'n': NonPagedUsage = TRUE; args++; break;
case 'p': PagedUsage = TRUE; args++; break;
case 's': if (Session.Type != DEBUG_VALUE_INVALID) { OutCtl.OutErr("Session argument specified multiple times.\n"); BadArg = TRUE; } else { args++; hr = Evaluate(Client, args, DEBUG_VALUE_INT32, 10, &Session, &RemainingArgIndex); if (hr != S_OK) { OutCtl.OutErr("Invalid Session.\n"); } else { args += RemainingArgIndex; } } break;
default: BadArg = TRUE; break; }
if (BadArg) break; } } else { if (*args == '\0') break;
if (TagName.Type == DEBUG_VALUE_INVALID) { hr = GetTagFilter(Client, &args, &TagName); } else { OutCtl.OutErr("Unrecognized argument @ %s\n", args); BadArg = TRUE; } } }
if (BadArg || hr != S_OK) { if (*args == '?') { OutCtl.Output("spoolused is like !kdexts.poolused, but for the SessionId specified.\n" "\n"); }
OutCtl.Output("Usage: spoolused [-anp] [-s SessionId] [Tag]\n" " -a - sort by allocation size (Not Implemented)\n" " -n - show non-paged pool\n" " -p - show paged pool\n" "\n" " SessionId - session to dump\n" " Special SessionId values:\n" " -1 - current session\n" " -2 - last !session SessionId (default)\n" "\n" " Tag - Pool tag filter\n" " Can be 4 character string or\n" " hex value in 0xXXXX format\n" ); } else { if (!NonPagedUsage && !PagedUsage) { NonPagedUsage = TRUE; PagedUsage = TRUE; }
if (Session.Type == DEBUG_VALUE_INVALID) { Session.I32 = DEFAULT_SESSION; }
if (TagName.Type == DEBUG_VALUE_INVALID) { TagName.I32 = ' *'; }
AccumTagUsage atu(TagName.I32);
if (atu.Valid() != S_OK) { OutCtl.OutErr("Error: failed to prepare tag usage reader.\n"); hr = E_FAIL; }
if (hr == S_OK && NonPagedUsage) { hr = SearchSessionPool(Client, Session.I32, TagName.I32, SEARCH_POOL_NONPAGED, 0, AccumTagUsageFilter, &atu, &atu);
if (hr == S_OK || hr == E_ABORT) { atu.OutputResults(&OutCtl, AllocSort); } else { OutCtl.OutWarn("SearchSessionPool returned %s\n", pszHRESULT(hr)); } }
if (hr == S_OK && PagedUsage) { if (NonPagedUsage) atu.Reset();
hr = SearchSessionPool(Client, Session.I32, TagName.I32, SEARCH_POOL_PAGED, 0, AccumTagUsageFilter, &atu, &atu);
if (hr == S_OK || hr == E_ABORT) { atu.OutputResults(&OutCtl, AllocSort); } else { OutCtl.OutWarn("SearchSessionPool returned %s\n", pszHRESULT(hr)); } } }
return hr; }
|