|
|
/*++
Copyright (c) 1992-2000 Microsoft Corporation
Module Name: dpa.c
Abstract: Module to dump pool allocations
Environment:
User Mode.
Revision History: Code taken from userkdx.dll ( windows\core\ntuser\kdexts\userexts.c )
Kshitiz K. Sharma (kksharma) 1/11/2002
--*/ #include "precomp.h"
#pragma hdrstop
#define RECORD_STACK_TRACE_SIZE 6
#define POOL_ALLOC_TRACE_SIZE 8
/*
* Pool allocation flags */
#define POOL_HEAVY_ALLOCS 0x00000001 // use HeavyAllocPool
#define POOL_CAPTURE_STACK 0x00000002 // stack traces are captured
#define POOL_FAIL_ALLOCS 0x00000004 // fail pool allocations
#define POOL_FAIL_BY_INDEX 0x00000008 // fail allocations by index
#define POOL_TAIL_CHECK 0x00000010 // append tail string
#define POOL_KEEP_FREE_RECORD 0x00000020 // keep a list with last x frees
#define POOL_KEEP_FAIL_RECORD 0x00000040 // keep a list with last x failed a
#define POOL_BREAK_FOR_LEAKS 0x00000080 // break on pool leaks (remote sess
enum DumpPolllAllocOptions { DpaCurrentAllocStats = 1, DpaAllCurrentAllocs = 2, DpaIncludeStack = 4, DpaFailedAllocs = 8, DpaFreePool = 0x10, DpaContainsPointer = 0x20, };
VOID PrintStackTrace( ULONG64 pStackTrace, int tracesCount) { int traceInd; ULONG64 dwOffset, pSymbol; CHAR symbol[MAX_PATH]; DWORD dwPointerSize = DBG_PTR_SIZE;
for (traceInd = 0; traceInd < tracesCount; traceInd++) { ReadPointer(pStackTrace, &pSymbol); if (pSymbol == 0) { break; }
GetSymbol(pSymbol, symbol, &dwOffset); if (*symbol) { dprintf("\t%s", symbol); if (dwOffset) { dprintf("+%p\n", dwOffset); } else { dprintf("\n"); } }
pStackTrace += dwPointerSize; } dprintf("\n"); }
void DisplayDpaUsage(void) { dprintf("dpa -cvsfrp - Dump pool allocations\n" " dpa -c - dump current pool allocations statistics\n" " dpa -v - dump all the current pool allocations\n" " dpa -vs - include stack traces\n" " dpa -f - dump failed allocations\n" " dpa -r - dump free pool\n" " dpa -p <ptr> - dump the allocation containing pointer 'ptr'\n"); }
BOOL GetDpaArgs( PCHAR Args, PULONG pOptions, PULONG64 pAllocPtr ) { *pOptions = 0; *pAllocPtr = 0; if (!Args) { return FALSE; }
while (*Args) { if (*Args == '-' || *Args == '/') { ++Args; switch (*Args) { case 'c': *pOptions |= DpaCurrentAllocStats; break; case 'f': *pOptions |= DpaFailedAllocs; break; case 'p': *pOptions |= DpaContainsPointer; ++Args; GetExpressionEx(Args, pAllocPtr, &Args); break; case 'r': *pOptions |= DpaFreePool; break; case 'v': if (*(Args+1) == 's') { *pOptions |= DpaIncludeStack; } else { *pOptions |= DpaAllCurrentAllocs; } break; default: dprintf("Unknown Arg %c.\n", *Args ? *Args : ' '); return FALSE; } } if (*Args) { ++Args; } }
return TRUE; }
/***************************************************************************\
* dpa - dump pool allocations * * Dump pool allocations. * * 12-27-96 CLupu Created \***************************************************************************/ BOOL DumpPoolAllocs( ULONG opts, ULONG64 param1 ) { HRESULT Hr = S_OK;
try { ULONG64 pAllocList; DWORD dwPoolFlags; DWORD dwSize = GetTypeSize("win32k!tagWin32PoolHead"); BOOL bIncludeStackTrace = FALSE;
dwPoolFlags = GetUlongValue( "win32k!gdwPoolFlags" ); if (!(dwPoolFlags & POOL_HEAVY_ALLOCS)) { dprintf("win32k.sys doesn't have pool instrumentation !\n"); return FALSE; }
if (opts & DpaIncludeStack) { if (dwPoolFlags & POOL_CAPTURE_STACK) { bIncludeStackTrace = TRUE; } else { dprintf("win32k.sys doesn't have stack traces enabled for pool allocations\n"); } }
pAllocList = GetExpression( "win32k!gAllocList" ); if (!pAllocList) { dprintf("Could not get Win32AllocStats structure win32k!gAllocList\n"); return FALSE; } InitTypeRead(pAllocList, win32k!tagWin32AllocStats); if (opts & DpaCurrentAllocStats) { dprintf("- pool instrumentation enabled for win32k.sys\n"); if (dwPoolFlags & POOL_CAPTURE_STACK) { dprintf("- stack traces enabled for pool allocations\n"); } else { dprintf("- stack traces disabled for pool allocations\n"); }
if (dwPoolFlags & POOL_KEEP_FAIL_RECORD) { dprintf("- records of failed allocations enabled\n"); } else { dprintf("- records of failed allocations disabled\n"); }
if (dwPoolFlags & POOL_KEEP_FREE_RECORD) { dprintf("- records of free pool enabled\n"); } else { dprintf("- records of free pool disabled\n"); }
dprintf("\n");
dprintf(" CrtM CrtA MaxM MaxA Head\n"); dprintf("------------|------------|------------|------------|------------|\n"); InitTypeRead(pAllocList, win32k!tagWin32AllocStats); dprintf(" 0x%08x 0x%08x 0x%08x 0x%08x 0x%I64x\n", (ULONG)ReadField(dwCrtMem), (ULONG)ReadField(dwCrtAlloc), (ULONG)ReadField(dwMaxMem), (ULONG)ReadField(dwMaxAlloc), ReadField(pHead));
return TRUE; }
InitTypeRead(pAllocList, win32k!tagWin32AllocStats); if (opts & DpaFailedAllocs) {
DWORD dwFailRecordCrtIndex, dwFailRecordTotalFailures; DWORD dwFailRecords, Ind, dwFailuresToDump; ULONG64 pFailRecord, pFailRecordOrg;
if (!(dwPoolFlags & POOL_KEEP_FAIL_RECORD)) { dprintf("win32k.sys doesn't have records of failed allocations!\n"); return TRUE; }
dwFailRecordTotalFailures = GetUlongValue( "win32k!gdwFailRecordTotalFailures");
if (dwFailRecordTotalFailures == 0) { dprintf("No allocation failure in win32k.sys!\n"); return TRUE; }
dwFailRecordCrtIndex = GetUlongValue( "win32k!gdwFailRecordCrtIndex"); dwFailRecords = GetUlongValue( "win32k!gdwFailRecords"); if (dwFailRecordTotalFailures < dwFailRecords) { dwFailuresToDump = dwFailRecordTotalFailures; } else { dwFailuresToDump = dwFailRecords; }
pFailRecord = GetPointerValue( "win32k!gparrFailRecord"); if (!pFailRecord) { dprintf("\nCouldn't get gparrFailRecord!\n"); return FALSE; }
pFailRecordOrg = pFailRecord;
dprintf("\nFailures to dump : %d\n\n", dwFailuresToDump);
for (Ind = 0; Ind < dwFailuresToDump; Ind++) { DWORD tag[2] = {0, 0};
if (dwFailRecordCrtIndex == 0) { dwFailRecordCrtIndex = dwFailRecords - 1; } else { dwFailRecordCrtIndex--; }
pFailRecord = pFailRecordOrg + dwFailRecordCrtIndex;
InitTypeRead(pFailRecord, win32k!tagPOOLRECORD);
tag[0] = (DWORD)(DWORD_PTR)ReadField(ExtraData);
dprintf("Allocation for tag '%s' size 0x%x failed\n", tag, (ULONG)ReadField(size));
PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE); if (CheckControlC()) { return FALSE; } } }
InitTypeRead(pAllocList, win32k!tagWin32AllocStats); if (opts & DpaFreePool) {
DWORD dwFreeRecordCrtIndex, dwFreeRecordTotalFrees; DWORD dwFreeRecords, Ind, dwFreesToDump; ULONG64 pFreeRecord, pFreeRecordOrg;
if (!(dwPoolFlags & POOL_KEEP_FREE_RECORD)) { dprintf("win32k.sys doesn't have records of free pool !\n"); return FALSE; }
dwFreeRecordTotalFrees = GetUlongValue( "win32k!gdwFreeRecordTotalFrees" ); if (dwFreeRecordTotalFrees == 0) { dprintf("No free pool in win32k.sys !\n"); return FALSE; }
dwFreeRecordCrtIndex = GetUlongValue( "win32k!gdwFreeRecordCrtIndex" ); dwFreeRecords = GetUlongValue( "win32k!gdwFreeRecords" ); if (dwFreeRecordTotalFrees < dwFreeRecords) { dwFreesToDump = dwFreeRecordTotalFrees; } else { dwFreesToDump = dwFreeRecords; }
pFreeRecord = GetPointerValue( "win32k!gparrFreeRecord" ); if (!pFreeRecord) { dprintf("\nCouldn't get gparrFreeRecord!\n"); return FALSE; }
pFreeRecordOrg = pFreeRecord;
dprintf("\nFrees to dump : %d\n\n", dwFreesToDump);
for (Ind = 0; Ind < dwFreesToDump; Ind++) { if (dwFreeRecordCrtIndex == 0) { dwFreeRecordCrtIndex = dwFreeRecords - 1; } else { dwFreeRecordCrtIndex--; }
pFreeRecord = pFreeRecordOrg + dwFreeRecordCrtIndex;
/*
* Dump */ InitTypeRead(pFreeRecord, win32k!tagPOOLRECORD); dprintf("Free pool for p %#p size 0x%x\n", ReadField(ExtraData), (ULONG)ReadField(size));
PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE); } }
InitTypeRead(pAllocList, win32k!tagWin32AllocStats); if (opts & DpaAllCurrentAllocs) { ULONG64 ph = ReadField(pHead);
while (ph != 0) { InitTypeRead(ph, win32k!tagWin32PoolHead); dprintf("p %#p pHead %#p size %x\n", ph + dwSize, ph, (ULONG)ReadField(size));
if (bIncludeStackTrace) { ULONG64 dwOffset; CHAR symbol[MAX_PATH]; int ind; ULONG64 trace; ULONG64 pTrace;
pTrace = ReadField(pTrace); for (ind = 0; ind < POOL_ALLOC_TRACE_SIZE; ind++) { ReadPointer(pTrace, &trace); if (trace == 0) { break; }
GetSymbol(trace, symbol, &dwOffset); if (*symbol) { dprintf("\t%s", symbol); if (dwOffset != 0) { dprintf("+0x%I64x", dwOffset); } dprintf("\n"); }
++pTrace; } dprintf("\n"); }
ph = (ULONG_PTR)ReadField(pNext); if (CheckControlC()) { return FALSE; } } return TRUE; }
InitTypeRead(pAllocList, win32k!tagWin32AllocStats); if (opts & DpaContainsPointer) { ULONG64 ph; dwSize = GetTypeSize("win32k!tagWin32PoolHead");
if (param1 == 0) { return TRUE; }
ph = ReadField(pHead); while (ph != 0) { if ((param1 - ph) >= ((ULONG)ReadField(size) + dwSize)) { dprintf("p %#p pHead %#p size %x\n", ph + 1, ph, (ULONG)ReadField(size));
PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE); return TRUE; }
ph = ReadField(pNext); } return TRUE; } } except (Hr) { dprintf("Unhandled exception %lx in DumpPoolAllocs\n", Hr); } return TRUE; }
DECLARE_API( dpa ) { ULONG opts; ULONG64 param1; INIT_API();
if (!GetDpaArgs((PCHAR)args, &opts, ¶m1)) { DisplayDpaUsage(); Status = E_FAIL; } else { DumpPoolAllocs(opts, param1); } EXIT_API(); return Status; }
|