2421 lines
73 KiB
C
2421 lines
73 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pool.c
|
||
|
||
Abstract:
|
||
|
||
WinDbg Extension Api
|
||
|
||
Author:
|
||
|
||
Lou Perazzoli (Loup) 5-Nov-1993
|
||
|
||
Environment:
|
||
|
||
User Mode.
|
||
|
||
Revision History:
|
||
|
||
Kshitiz K. Sharma (kksharma)
|
||
|
||
Using debugger type info.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
typedef struct _POOL_BLOCK_HEAD {
|
||
// POOL_HEADER Header;
|
||
LIST_ENTRY List;
|
||
} POOL_BLOCK_HEAD, *PPOOL_BLOCK_HEADER;
|
||
|
||
typedef struct _POOL_HACKER {
|
||
// POOL_HEADER Header;
|
||
ULONG Contents[8];
|
||
} POOL_HACKER;
|
||
|
||
|
||
#define TAG 0
|
||
#define NONPAGED_ALLOC 1
|
||
#define NONPAGED_FREE 2
|
||
#define PAGED_ALLOC 3
|
||
#define PAGED_FREE 4
|
||
#define NONPAGED_USED 5
|
||
#define PAGED_USED 6
|
||
|
||
BOOL NewPool;
|
||
ULONG SortBy;
|
||
|
||
typedef struct _FILTER {
|
||
ULONG Tag;
|
||
BOOLEAN Exclude;
|
||
} FILTER, *PFILTER;
|
||
|
||
#define MAX_FILTER 64
|
||
FILTER Filter[MAX_FILTER];
|
||
|
||
ULONG64 SpecialPoolStart;
|
||
ULONG64 SpecialPoolEnd;
|
||
ULONG64 PoolBigTableAddress;
|
||
|
||
|
||
#define DecodeLink(Pool) ( (ULONG64) (Pool & (ULONG64) ~1))
|
||
|
||
//
|
||
// Size of a pool page.
|
||
//
|
||
// This must be greater than or equal to the page size.
|
||
//
|
||
|
||
#define POOL_PAGE_SIZE PageSize
|
||
|
||
//
|
||
// The smallest pool block size must be a multiple of the page size.
|
||
//
|
||
// Define the block size as 32.
|
||
//
|
||
|
||
|
||
#define POOL_LIST_HEADS (POOL_PAGE_SIZE / (1 << POOL_BLOCK_SHIFT))
|
||
|
||
|
||
|
||
#define SPECIAL_POOL_BLOCK_SIZE(PoolHeader_Ulong1) (PoolHeader_Ulong1 & (MI_SPECIAL_POOL_VERIFIER - 1))
|
||
|
||
#ifndef _EXTFNS_H
|
||
// GetPoolTagDescription
|
||
typedef HRESULT
|
||
(WINAPI *PGET_POOL_TAG_DESCRIPTION)(
|
||
ULONG PoolTag,
|
||
PSTR *pDescription
|
||
);
|
||
#endif
|
||
|
||
ULONG64
|
||
GetSpecialPoolHeader (
|
||
IN PVOID DataPage,
|
||
IN ULONG64 RealDataPage,
|
||
OUT PULONG64 ReturnedDataStart
|
||
);
|
||
|
||
int __cdecl
|
||
ulcomp(const void *e1,const void *e2)
|
||
{
|
||
ULONG u1;
|
||
LONG64 diff;
|
||
ULONG64 ValE1, ValE2;
|
||
|
||
switch (SortBy) {
|
||
case TAG:
|
||
|
||
GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "Key", ValE1);
|
||
GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "Key", ValE2);
|
||
|
||
u1 = ((PUCHAR)&ValE1)[0] - ((PUCHAR)&ValE2)[0];
|
||
if (u1 != 0) {
|
||
return u1;
|
||
}
|
||
u1 = ((PUCHAR)&ValE1)[1] - ((PUCHAR)&ValE2)[1];
|
||
if (u1 != 0) {
|
||
return u1;
|
||
}
|
||
u1 = ((PUCHAR)&ValE1)[2] - ((PUCHAR)&ValE2)[2];
|
||
if (u1 != 0) {
|
||
return u1;
|
||
}
|
||
u1 = ((PUCHAR)&ValE1)[3] - ((PUCHAR)&ValE2)[3];
|
||
return u1;
|
||
break;
|
||
|
||
case NONPAGED_ALLOC:
|
||
GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedAllocs", ValE1);
|
||
GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedAllocs", ValE2);
|
||
diff = ValE2 - ValE1;
|
||
return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
|
||
break;
|
||
|
||
case NONPAGED_FREE:
|
||
GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedFrees", ValE1);
|
||
GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedFrees", ValE2);
|
||
diff = ValE2 - ValE1;
|
||
return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
|
||
break;
|
||
|
||
case NONPAGED_USED:
|
||
GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedBytes", ValE1);
|
||
GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedBytes", ValE2);
|
||
diff = ValE2 - ValE1;
|
||
return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
|
||
break;
|
||
|
||
case PAGED_USED:
|
||
GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "PagedBytes", ValE1);
|
||
GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "PagedBytes", ValE2);
|
||
diff = ValE2 - ValE1;
|
||
return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
|
||
break;
|
||
|
||
default:
|
||
return(0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets up generally useful pool globals.
|
||
|
||
Must be called in every DECLARE_API interface that uses pool.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
LOGICAL PoolInitialized = FALSE;
|
||
|
||
LOGICAL
|
||
PoolInitializeGlobals(
|
||
VOID
|
||
)
|
||
{
|
||
if (PoolInitialized == TRUE) {
|
||
return TRUE;
|
||
}
|
||
|
||
SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
|
||
SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
|
||
|
||
|
||
if (PageSize < 0x1000 || (PageSize & (ULONG)0xFFF)) {
|
||
dprintf ("unable to get MmPageSize (0x%x) - probably bad symbols\n", PageSize);
|
||
return FALSE;
|
||
}
|
||
|
||
PoolInitialized = TRUE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
DECLARE_API( frag )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dump pool fragmentation
|
||
|
||
Arguments:
|
||
|
||
args - Flags
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Flags;
|
||
ULONG result;
|
||
ULONG i;
|
||
ULONG count;
|
||
ULONG64 Pool;
|
||
ULONG64 PoolLoc1;
|
||
ULONG TotalFrag;
|
||
ULONG TotalCount;
|
||
ULONG Frag;
|
||
ULONG64 PoolStart;
|
||
ULONG PoolOverhead;
|
||
ULONG64 PoolLoc;
|
||
ULONG PoolTag, BlockSize, PreviousSize, PoolIndex;
|
||
ULONG TotalPages, TotalBigPages;
|
||
ULONG64 Flink, Blink;
|
||
PCHAR pc;
|
||
ULONG64 tmp;
|
||
|
||
#define PoolBlk(F,V) GetFieldValue(Pool, "nt!_POOL_BLOCK_HEAD", #F, V)
|
||
|
||
if (PoolInitializeGlobals() == FALSE) {
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
dprintf("\n NonPaged Pool Fragmentation\n\n");
|
||
Flags = 0;
|
||
PoolStart = 0;
|
||
|
||
if (GetExpressionEx(args, &tmp, &args)) {
|
||
Flags = (ULONG) tmp;
|
||
PoolStart = GetExpression (args);
|
||
}
|
||
|
||
PoolOverhead = GetTypeSize("nt!_POOL_HEADER");
|
||
if (PoolStart != 0) {
|
||
PoolStart += PoolOverhead;
|
||
|
||
Pool = DecodeLink(PoolStart);
|
||
do {
|
||
|
||
Pool = Pool - PoolOverhead;
|
||
if ( PoolBlk(Header.PoolTag, PoolTag) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", Pool );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
PoolBlk(Header.BlockSize,BlockSize);
|
||
PoolBlk(Header.PreviousSize,PreviousSize);
|
||
PoolBlk(List.Flink,Flink);
|
||
PoolBlk(List.Blink,Blink);
|
||
|
||
dprintf(" %p size: %4lx previous size: %4lx %c%c%c%c links: %8p %8p\n",
|
||
Pool,
|
||
(ULONG)BlockSize << POOL_BLOCK_SHIFT,
|
||
(ULONG)PreviousSize << POOL_BLOCK_SHIFT,
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP((PoolTag&~PROTECTED_POOL) >> 24),
|
||
#undef PP
|
||
Flink,
|
||
Blink);
|
||
|
||
if (Flags != 3) {
|
||
Pool = Flink;
|
||
} else {
|
||
Pool = Blink;
|
||
}
|
||
|
||
Pool = DecodeLink(Pool);
|
||
|
||
if (CheckControlC()) {
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
} while ( (Pool & (ULONG64) ~1) != (PoolStart & (ULONG64) ~1) );
|
||
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
PoolLoc1 = GetNtDebuggerData( NonPagedPoolDescriptor );
|
||
|
||
if (PoolLoc1 == 0) {
|
||
dprintf ("unable to get nonpaged pool head\n");
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
PoolLoc = PoolLoc1;
|
||
|
||
TotalFrag = 0;
|
||
TotalCount = 0;
|
||
|
||
for (i = 0; i < POOL_LIST_HEADS; i += 1) {
|
||
CHAR Buffer[40];
|
||
ULONG ListOffset;
|
||
|
||
sprintf(Buffer, "ListHeads[%d].Flink", i);
|
||
Frag = 0;
|
||
count = 0;
|
||
|
||
if (GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", Buffer, Pool)) {
|
||
dprintf ("%08p: Unable to get pool descriptor\n", PoolLoc1);
|
||
return E_INVALIDARG;
|
||
}
|
||
GetFieldOffset("nt!_POOL_DESCRIPTOR", Buffer, &ListOffset);
|
||
|
||
// Pool = (PUCHAR)PoolDesc.ListHeads[i].Flink;
|
||
Pool = DecodeLink(Pool);
|
||
|
||
while (Pool != (ListOffset + PoolLoc)) {
|
||
|
||
Pool = Pool - PoolOverhead;
|
||
if ( PoolBlk(Header.PoolTag, PoolTag) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", Pool );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
PoolBlk(Header.BlockSize,BlockSize);
|
||
PoolBlk(Header.PreviousSize,PreviousSize);
|
||
PoolBlk(List.Flink,Flink);
|
||
|
||
Frag += BlockSize << POOL_BLOCK_SHIFT;
|
||
count += 1;
|
||
|
||
if (Flags & 2) {
|
||
dprintf(" ListHead[%x]: %p size: %4lx previous size: %4lx %c%c%c%c\n",
|
||
i,
|
||
(ULONG)Pool,
|
||
(ULONG)BlockSize << POOL_BLOCK_SHIFT,
|
||
(ULONG)PreviousSize << POOL_BLOCK_SHIFT,
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP((PoolTag&~PROTECTED_POOL) >> 24));
|
||
#undef PP
|
||
}
|
||
Pool = Flink;
|
||
Pool = DecodeLink(Pool);
|
||
|
||
if (CheckControlC()) {
|
||
return E_INVALIDARG;
|
||
}
|
||
}
|
||
if (Flags & 1) {
|
||
dprintf("index: %2ld number of fragments: %5ld bytes: %6ld\n",
|
||
i,count,Frag);
|
||
}
|
||
TotalFrag += Frag;
|
||
TotalCount += count;
|
||
}
|
||
|
||
dprintf("\n Number of fragments: %7ld consuming %7ld bytes\n",
|
||
TotalCount,TotalFrag);
|
||
GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages",TotalPages);
|
||
GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalBigPages", TotalBigPages);
|
||
|
||
dprintf( " NonPagedPool Usage: %7ld bytes\n",(TotalPages + TotalBigPages)*PageSize);
|
||
return S_OK;
|
||
#undef PoolBlk
|
||
}
|
||
|
||
|
||
PRTL_BITMAP
|
||
GetBitmap(
|
||
ULONG64 pBitmap
|
||
)
|
||
{
|
||
PRTL_BITMAP p;
|
||
ULONG Size, Result;
|
||
ULONG64 Buffer=0;
|
||
|
||
if ( GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "Buffer", Buffer)) {
|
||
dprintf("%08p: Unable to get contents of bitmap\n", pBitmap );
|
||
return 0;
|
||
}
|
||
GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "SizeOfBitMap", Size);
|
||
|
||
p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) + (Size / 8) );
|
||
if (p) {
|
||
p->SizeOfBitMap = Size;
|
||
p->Buffer = (PULONG)(p + 1);
|
||
if ( !ReadMemory( Buffer,
|
||
p->Buffer,
|
||
Size / 8,
|
||
&Result) ) {
|
||
dprintf("%08p: Unable to get contents of bitmap buffer\n", Buffer );
|
||
HeapFree( GetProcessHeap(), 0, p );
|
||
p = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
return p;
|
||
}
|
||
|
||
VOID
|
||
DumpPool(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG64 p, pStart;
|
||
ULONG64 Size;
|
||
ULONG BusyFlag;
|
||
ULONG CurrentPage, NumberOfPages;
|
||
PRTL_BITMAP StartMap;
|
||
PRTL_BITMAP EndMap;
|
||
ULONG64 PagedPoolStart;
|
||
ULONG64 PagedPoolEnd;
|
||
ULONG Result;
|
||
UCHAR PgPool[] = "nt!_MM_PAGED_POOL_INFO";
|
||
ULONG64 PagedPoolInfoPointer;
|
||
ULONG64 PagedPoolAllocationMap=0, EndOfPagedPoolBitmap=0;
|
||
|
||
if (PoolInitializeGlobals() == FALSE) {
|
||
return;
|
||
}
|
||
|
||
PagedPoolInfoPointer = GetNtDebuggerData( MmPagedPoolInformation );
|
||
|
||
if ( GetFieldValue( PagedPoolInfoPointer,
|
||
PgPool,
|
||
"PagedPoolAllocationMap",
|
||
PagedPoolAllocationMap)) {
|
||
dprintf("%08p: Unable to get contents of paged pool information\n",
|
||
PagedPoolInfoPointer );
|
||
return;
|
||
}
|
||
|
||
GetFieldValue( PagedPoolInfoPointer, PgPool, "EndOfPagedPoolBitmap", EndOfPagedPoolBitmap);
|
||
|
||
|
||
StartMap = GetBitmap( PagedPoolAllocationMap );
|
||
EndMap = GetBitmap( EndOfPagedPoolBitmap );
|
||
|
||
PagedPoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
|
||
PagedPoolEnd = GetNtDebuggerDataPtrValue( MmPagedPoolEnd );
|
||
|
||
if (StartMap && EndMap) {
|
||
p = PagedPoolStart;
|
||
CurrentPage = 0;
|
||
dprintf( "Paged Pool: %p .. %p\n", PagedPoolStart, PagedPoolEnd );
|
||
|
||
while (p < PagedPoolEnd) {
|
||
if ( CheckControlC() ) {
|
||
return;
|
||
}
|
||
pStart = p;
|
||
BusyFlag = RtlCheckBit( StartMap, CurrentPage );
|
||
while ( ~(BusyFlag ^ RtlCheckBit( StartMap, CurrentPage )) ) {
|
||
p += PageSize;
|
||
if (RtlCheckBit( EndMap, CurrentPage )) {
|
||
CurrentPage++;
|
||
break;
|
||
}
|
||
|
||
CurrentPage++;
|
||
if (p > PagedPoolEnd) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
Size = p - pStart;
|
||
dprintf( "%p: %I64x - %s\n", pStart, Size, BusyFlag ? "busy" : "free" );
|
||
}
|
||
}
|
||
|
||
HeapFree( GetProcessHeap(), 0, StartMap );
|
||
HeapFree( GetProcessHeap(), 0, EndMap );
|
||
}
|
||
|
||
void
|
||
PrintPoolTagComponent(
|
||
ULONG PoolTag
|
||
)
|
||
{
|
||
PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
|
||
PSTR TagComponent;
|
||
#ifdef _EXTFNS_H
|
||
DEBUG_POOLTAG_DESCRIPTION Desc = {0};
|
||
Desc.SizeOfStruct = sizeof(DEBUG_POOLTAG_DESCRIPTION);
|
||
GetPoolTagDescription = NULL;
|
||
if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
|
||
!GetPoolTagDescription) {
|
||
return;
|
||
}
|
||
|
||
(*GetPoolTagDescription)(PoolTag, &Desc);
|
||
|
||
if (Desc.Description[0]) {
|
||
dprintf("\t\tPooltag %4.4s : %s", &PoolTag, Desc.Description);
|
||
if (Desc.Binary[0]) {
|
||
dprintf(", Binary : %s",Desc.Binary);
|
||
}
|
||
if (Desc.Owner[0]) {
|
||
dprintf(", Owner : %s", Desc.Owner);
|
||
}
|
||
dprintf("\n");
|
||
} else {
|
||
dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
|
||
}
|
||
|
||
#else
|
||
GetPoolTagDescription = NULL;
|
||
if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
|
||
!GetPoolTagDescription) {
|
||
return;
|
||
}
|
||
|
||
(*GetPoolTagDescription)(PoolTag, &TagComponent);
|
||
if (TagComponent && (100 < (ULONG64) TagComponent)) {
|
||
dprintf("\t\tOwning component : %s\n", TagComponent);
|
||
} else {
|
||
dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
PSTR g_PoolRegion[DbgPoolRegionMax] = {
|
||
"Unknown", // DbgPoolRegionUnknown,
|
||
"Special pool", // DbgPoolRegionSpecial,
|
||
"Paged pool", // DbgPoolRegionPaged,
|
||
"Nonpaged pool", // DbgPoolRegionNonPaged,
|
||
"Pool code", // DbgPoolRegionCode,
|
||
"Nonpaged pool expansion", // DbgPoolRegionNonPagedExpansion,
|
||
};
|
||
|
||
DEBUG_POOL_REGION
|
||
GetPoolRegion(
|
||
ULONG64 Pool
|
||
)
|
||
{
|
||
static ULONG64 PoolCodeEnd;
|
||
static ULONG64 SpecialPoolEnd;
|
||
static ULONG64 PagedPoolEnd;
|
||
static ULONG64 NonPagedPoolEnd;
|
||
static ULONG64 NonPagedPoolStart;
|
||
static ULONG64 SpecialPoolStart;
|
||
static ULONG64 PagedPoolStart;
|
||
static ULONG64 NonPagedPoolExpansionStart;
|
||
static ULONG64 PoolCodeStart;
|
||
static BOOL GotAll = FALSE;
|
||
|
||
if (!GotAll) {
|
||
PoolCodeEnd = GetPointerValue("nt!MmPoolCodeEnd");
|
||
SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
|
||
PagedPoolEnd = GetPointerValue("nt!MmPagedPoolEnd");
|
||
NonPagedPoolEnd = GetPointerValue("nt!MmNonPagedPoolEnd");
|
||
NonPagedPoolStart = GetPointerValue("nt!MmNonPagedPoolStart");
|
||
SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
|
||
PagedPoolStart = GetPointerValue("nt!MmPagedPoolStart");
|
||
NonPagedPoolExpansionStart = GetPointerValue("nt!MmNonPagedPoolExpansionStart");
|
||
PoolCodeStart = GetPointerValue("nt!MmPoolCodeStart");
|
||
GotAll = TRUE;
|
||
}
|
||
if (!(PoolCodeStart || SpecialPoolStart || SpecialPoolEnd || PoolCodeEnd ||
|
||
NonPagedPoolExpansionStart || NonPagedPoolStart || NonPagedPoolEnd ||
|
||
PagedPoolStart || PagedPoolEnd)) {
|
||
GotAll = FALSE;
|
||
return DbgPoolRegionUnknown;
|
||
}
|
||
if ( Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
|
||
return DbgPoolRegionSpecial;
|
||
} else if ( Pool >= PagedPoolStart && Pool < PagedPoolEnd) {
|
||
return DbgPoolRegionPaged;
|
||
} else if ( Pool >= NonPagedPoolStart && Pool < NonPagedPoolEnd) {
|
||
return DbgPoolRegionNonPaged;
|
||
} else if ( Pool >= PoolCodeStart && Pool < PoolCodeEnd) {
|
||
return DbgPoolRegionCode;
|
||
} else if ( Pool >= NonPagedPoolExpansionStart) {
|
||
return DbgPoolRegionNonPagedExpansion;
|
||
} else {
|
||
return DbgPoolRegionUnknown;
|
||
}
|
||
return DbgPoolRegionUnknown;
|
||
}
|
||
|
||
void
|
||
PrintPoolRegion(
|
||
ULONG64 Pool
|
||
)
|
||
{
|
||
PSTR pszRegion;
|
||
DEBUG_POOL_REGION Region;
|
||
|
||
|
||
Region = GetPoolRegion(Pool);
|
||
|
||
pszRegion = g_PoolRegion[Region];
|
||
if (pszRegion) {
|
||
dprintf(pszRegion);
|
||
dprintf("\n");
|
||
} else {
|
||
dprintf("Region unkown\n", Pool);
|
||
}
|
||
|
||
}
|
||
HRESULT
|
||
ListPoolPage(
|
||
ULONG64 PoolPageToDump,
|
||
ULONG Flags,
|
||
PDEBUG_POOL_DATA PoolData
|
||
)
|
||
{
|
||
ULONG64 PoolTableAddress;
|
||
ULONG result;
|
||
ULONG PoolTag;
|
||
ULONG Result;
|
||
ULONG64 StartPage;
|
||
ULONG64 Pool;
|
||
ULONG PoolBlockSize;
|
||
ULONG PoolHeaderSize;
|
||
ULONG64 PoolHeader;
|
||
ULONG Previous;
|
||
UCHAR c;
|
||
PUCHAR p;
|
||
ULONG64 PoolDataEnd;
|
||
UCHAR PoolBlockPattern;
|
||
UCHAR DataPage[0x5000];
|
||
PUCHAR DataStart;
|
||
ULONG64 RealDataStart;
|
||
LOGICAL Pagable;
|
||
LOGICAL FirstBlock;
|
||
ULONG BlockType;
|
||
ULONG PoolWhere;
|
||
ULONG i;
|
||
ULONG j;
|
||
ULONG ct;
|
||
ULONG start;
|
||
ULONG PoolBigPageTableSize;
|
||
ULONG SizeOfPoolHdr=GetTypeSize("nt!_POOL_HEADER");
|
||
|
||
if (!SpecialPoolStart) {
|
||
SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
|
||
SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
|
||
}
|
||
|
||
Pool = PAGE_ALIGN64 (PoolPageToDump);
|
||
StartPage = Pool;
|
||
Previous = 0;
|
||
|
||
if (PoolData) {
|
||
ZeroMemory(PoolData, sizeof(DEBUG_POOL_DATA));
|
||
}
|
||
if (!(Flags & 0x80000000)) {
|
||
dprintf("Pool page %p region is ", PoolPageToDump);
|
||
PrintPoolRegion(PoolPageToDump);
|
||
}
|
||
|
||
|
||
if ( Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
|
||
ULONG Hdr_Ulong=0;
|
||
|
||
// LWFIX: this is not ported yet.
|
||
// dprintf("reading %I64x datapage %x\n", Pool, min(PageSize, sizeof(DataPage)));
|
||
// Pre read the pool
|
||
if ( !ReadMemory( Pool,
|
||
&DataPage[0],
|
||
min(PageSize, sizeof(DataPage)),
|
||
&Result) ) {
|
||
dprintf("%08p: Unable to get contents of special pool block\n", Pool );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong)) {
|
||
dprintf("%08p: Unable to get nt!_POOL_HEADER\n", Pool );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
//
|
||
// Determine whether the data is at the start or end of the page.
|
||
// Start off by assuming the data is at the end, in this case the
|
||
// header will be at the start.
|
||
//
|
||
|
||
PoolHeader = GetSpecialPoolHeader((PVOID) &DataPage[0], Pool, &RealDataStart);
|
||
|
||
if (PoolHeader == 0) {
|
||
dprintf("Block %p is a corrupted special pool allocation\n",
|
||
PoolPageToDump);
|
||
return E_INVALIDARG;
|
||
}
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
|
||
PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(Hdr_Ulong);
|
||
|
||
if (Hdr_Ulong & MI_SPECIAL_POOL_PAGABLE) {
|
||
Pagable = TRUE;
|
||
} else {
|
||
Pagable = FALSE;
|
||
}
|
||
|
||
if (PoolData) {
|
||
PoolData->Pool = RealDataStart;
|
||
PoolData->PoolBlock = PoolPageToDump;
|
||
PoolData->SpecialPool = 1;
|
||
PoolData->Pageable = Hdr_Ulong & 0x8000 ? 1 : 0;
|
||
PoolData->Size = PoolBlockSize;
|
||
if (Flags & 0x80000000) {
|
||
// do not print anything
|
||
return S_OK;
|
||
}
|
||
}
|
||
dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
|
||
RealDataStart,
|
||
PoolBlockSize,
|
||
Hdr_Ulong & 0x8000 ? "pagable" : "non-paged",
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP(PoolTag >> 24)
|
||
);
|
||
#undef PP
|
||
PrintPoolTagComponent(PoolTag);
|
||
|
||
//
|
||
// Add code to validate whole block.
|
||
//
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
FirstBlock = TRUE;
|
||
|
||
while (PAGE_ALIGN64(Pool) == StartPage) {
|
||
ULONG BlockSize=0, PreviousSize=0, PoolType=0, AllocatorBackTraceIndex=0;
|
||
ULONG PoolTagHash=0, PoolIndex=0;
|
||
ULONG64 ProcessBilled=0;
|
||
|
||
if ( CheckControlC() ) {
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", Pool );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if (PoolPageToDump >= Pool &&
|
||
PoolPageToDump < (Pool + (BlockSize << POOL_BLOCK_SHIFT))
|
||
) {
|
||
c = '*';
|
||
} else {
|
||
c = ' ';
|
||
}
|
||
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolType", PoolType);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
|
||
|
||
BlockType = 0;
|
||
|
||
if ((BlockSize << POOL_BLOCK_SHIFT) >= POOL_PAGE_SIZE) {
|
||
BlockType = 1;
|
||
} else if (BlockSize == 0) {
|
||
BlockType = 2;
|
||
} else if (PreviousSize != Previous) {
|
||
BlockType = 3;
|
||
}
|
||
|
||
if (BlockType != 0) {
|
||
ULONG BigPageSize = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
|
||
|
||
if (!BigPageSize) {
|
||
dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
|
||
break;
|
||
}
|
||
|
||
//
|
||
// See if this is a big block allocation. Iff we have not parsed
|
||
// any other small blocks in here already.
|
||
//
|
||
|
||
if (FirstBlock == TRUE) {
|
||
|
||
if (!PoolBigTableAddress) {
|
||
PoolBigTableAddress = GetPointerValue ("PoolBigPageTable");
|
||
}
|
||
|
||
PoolTableAddress = PoolBigTableAddress;
|
||
|
||
if (PoolTableAddress) {
|
||
|
||
dprintf ("%p is not a valid small pool allocation, checking large pool...\n", Pool);
|
||
|
||
PoolBigPageTableSize = GetUlongValue ("PoolBigPageTableSize");
|
||
//
|
||
// Scan the table looking for a match.
|
||
//
|
||
|
||
i = 0;
|
||
ct = PageSize / BigPageSize;
|
||
|
||
while (i < PoolBigPageTableSize) {
|
||
ULONG64 Va=0;
|
||
ULONG Key=0, NumberOfPages=0;
|
||
|
||
if (PoolBigPageTableSize - i < ct) {
|
||
ct = PoolBigPageTableSize - i;
|
||
}
|
||
|
||
if ( GetFieldValue( PoolTableAddress,
|
||
"nt!_POOL_TRACKER_BIG_PAGES",
|
||
"Va",
|
||
Va) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
for (j = 0; j < ct; j += 1) {
|
||
|
||
if ( GetFieldValue( PoolTableAddress + BigPageSize*j,
|
||
"nt!_POOL_TRACKER_BIG_PAGES",
|
||
"Va",
|
||
Va) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if (Va == PAGE_ALIGN64(Pool)) {
|
||
|
||
//
|
||
// Match !
|
||
//
|
||
GetFieldValue( PoolTableAddress + BigPageSize*j,
|
||
"nt!_POOL_TRACKER_BIG_PAGES",
|
||
"Key",
|
||
Key);
|
||
GetFieldValue( PoolTableAddress + BigPageSize*j,
|
||
"nt!_POOL_TRACKER_BIG_PAGES",
|
||
"NumberOfPages",
|
||
NumberOfPages);
|
||
PoolTag = Key;
|
||
|
||
if (PoolData) {
|
||
PoolData->Pool = PoolPageToDump;
|
||
PoolData->Size = NumberOfPages*PageSize;
|
||
PoolData->PoolTag = PoolTag;
|
||
PoolData->LargePool = 1;
|
||
PoolData->Free = (Pool & POOL_BIG_TABLE_ENTRY_FREE) ? 1 : 0;
|
||
if (Flags & 0x80000000) {
|
||
// do not print anything
|
||
return S_OK;
|
||
}
|
||
}
|
||
dprintf("*%p :%s large page allocation, Tag is %c%c%c%c, size is 0x%x bytes\n",
|
||
(Pool & ~POOL_BIG_TABLE_ENTRY_FREE),
|
||
(Pool & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP(PoolTag >> 24),
|
||
NumberOfPages * PageSize
|
||
);
|
||
#undef PP
|
||
PrintPoolTagComponent(PoolTag);
|
||
return S_OK;
|
||
}
|
||
}
|
||
i += ct;
|
||
PoolTableAddress += (ct * BigPageSize);
|
||
}
|
||
|
||
//
|
||
// No match in small or large pool, must be
|
||
// freed or corrupt pool
|
||
//
|
||
|
||
dprintf("%p is freed (or corrupt) pool\n", Pool);
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
dprintf("unable to get pool big page table - either wrong symbols or pool tagging is disabled\n");
|
||
}
|
||
|
||
if (BlockType == 1) {
|
||
dprintf("Bad allocation size @%p, too large\n", Pool);
|
||
return E_INVALIDARG;
|
||
} else if (BlockType == 2) {
|
||
dprintf("Bad allocation size @%p, zero is invalid\n", Pool);
|
||
return E_INVALIDARG;
|
||
} else if (BlockType == 3) {
|
||
dprintf("Bad previous allocation size @%p, last size was %lx\n",
|
||
Pool, Previous);
|
||
return E_INVALIDARG;
|
||
}
|
||
}
|
||
|
||
GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
|
||
|
||
|
||
if (!(Flags & 2) || c == '*') {
|
||
if (PoolData) {
|
||
PoolData->Pool = Pool;
|
||
PoolData->PoolBlock = PoolPageToDump;
|
||
PoolData->PoolTag = PoolTag & ~PROTECTED_POOL;
|
||
PoolData->ProcessBilled = ProcessBilled;
|
||
PoolData->PreviousSize = PreviousSize << POOL_BLOCK_SHIFT;
|
||
PoolData->Size = BlockSize << POOL_BLOCK_SHIFT;
|
||
PoolData->Free = ((PoolType != 0) && (!NewPool ?
|
||
(PoolIndex & 0x80) : (PoolType & 0x04))) ? 0 : 1;
|
||
PoolData->Protected = (PoolTag&PROTECTED_POOL) ? 1 : 0;
|
||
if (Flags & 0x80000000) {
|
||
// do not print anything
|
||
return S_OK;
|
||
}
|
||
}
|
||
|
||
dprintf("%c%p size: %4lx previous size: %4lx ",
|
||
c,
|
||
Pool,
|
||
BlockSize << POOL_BLOCK_SHIFT,
|
||
PreviousSize << POOL_BLOCK_SHIFT);
|
||
|
||
if (PoolType == 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.
|
||
//
|
||
|
||
dprintf(" (Free)");
|
||
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
dprintf(" %c%c%c%c%c\n",
|
||
c,
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP((PoolTag&~PROTECTED_POOL) >> 24)
|
||
);
|
||
#undef PP
|
||
if (c=='*') {
|
||
PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
|
||
}
|
||
} else {
|
||
|
||
if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
|
||
dprintf(" (Allocated)");
|
||
} 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.
|
||
//
|
||
dprintf(" (Free )");
|
||
}
|
||
if ((PoolType & POOL_QUOTA_MASK) == 0) {
|
||
/*
|
||
ULONG Key=0;
|
||
if (AllocatorBackTraceIndex != 0 &&
|
||
AllocatorBackTraceIndex & POOL_BACKTRACEINDEX_PRESENT
|
||
) {
|
||
if ( GetFieldValue( PoolTrackTable + ( PoolTagHash&~(PROTECTED_POOL >> 16) )*GetTypeSize("nt!_POOL_TRACKER_TABLE"),
|
||
"nt!_POOL_TRACKER_TABLE",
|
||
"Key",
|
||
Key) ) {
|
||
PoolTag = 0;
|
||
} else {
|
||
PoolTag = Key;
|
||
}
|
||
|
||
if (PoolTagHash & (PROTECTED_POOL >> 16)) {
|
||
PoolTag |= PROTECTED_POOL;
|
||
}
|
||
|
||
} else {
|
||
PoolTag = PoolTag;
|
||
}*/
|
||
|
||
dprintf(" %c%c%c%c%c%s\n",
|
||
c,
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(PoolTag),
|
||
PP(PoolTag >> 8),
|
||
PP(PoolTag >> 16),
|
||
PP((PoolTag&~PROTECTED_POOL) >> 24),
|
||
(PoolTag&PROTECTED_POOL) ? " (Protected)" : ""
|
||
#undef PP
|
||
);
|
||
|
||
if (c=='*') {
|
||
PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
|
||
}
|
||
} else {
|
||
if (ProcessBilled != 0) {
|
||
dprintf(" Process: %0p\n", ProcessBilled );
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (Flags & 1) {
|
||
ULONG i, Contents[8];
|
||
|
||
// BUG if Contents have different size than 32 bits
|
||
ReadMemory(Pool + SizeOfPoolHdr,
|
||
&Contents,
|
||
sizeof(Contents),
|
||
&i);
|
||
dprintf(" %08lx %08lx %08lx %08lx %08lx\n",
|
||
Pool+SizeOfPoolHdr,
|
||
Contents[0],
|
||
Contents[1],
|
||
Contents[2],
|
||
Contents[3]);
|
||
|
||
dprintf(" %08lx %08lx %08lx %08lx %08lx\n",
|
||
Pool+SizeOfPoolHdr+16,
|
||
Contents[4],
|
||
Contents[5],
|
||
Contents[6],
|
||
Contents[7]);
|
||
dprintf("\n");
|
||
}
|
||
|
||
Previous = BlockSize;
|
||
Pool += (Previous << POOL_BLOCK_SHIFT);
|
||
FirstBlock = FALSE;
|
||
}
|
||
return S_OK;
|
||
}
|
||
|
||
DECLARE_API( pool )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dump kernel mode heap
|
||
|
||
Arguments:
|
||
|
||
args - Page Flags
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG64 PoolPageToDump;
|
||
ULONG Flags;
|
||
HRESULT Hr;
|
||
|
||
INIT_API();
|
||
if (PoolInitializeGlobals() == FALSE) {
|
||
Hr = E_INVALIDARG;
|
||
} else {
|
||
PoolPageToDump = 0;
|
||
Flags = 0;
|
||
if (GetExpressionEx(args, &PoolPageToDump, &args)) {
|
||
Flags = (ULONG) GetExpression (args);
|
||
}
|
||
|
||
if (PoolPageToDump == 0) {
|
||
DumpPool();
|
||
Hr = S_OK;;
|
||
} else {
|
||
Hr = ListPoolPage(PoolPageToDump, Flags, NULL);
|
||
}
|
||
|
||
}
|
||
EXIT_API();
|
||
|
||
return Hr;
|
||
|
||
}
|
||
|
||
|
||
|
||
DECLARE_API( poolused )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dump usage by pool tag
|
||
|
||
Arguments:
|
||
|
||
args -
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG PoolTrackTableSize;
|
||
ULONG PoolTrackTableSizeInBytes;
|
||
PULONG64 p;
|
||
PUCHAR PoolTrackTableData;
|
||
ULONG Flags;
|
||
ULONG i;
|
||
ULONG result;
|
||
ULONG ct;
|
||
ULONG TagName;
|
||
CHAR TagNameX[4] = {'*','*','*','*'};
|
||
ULONG SizeOfPoolTarker;
|
||
ULONG64 PoolTableAddress;
|
||
ULONG64 PoolTrackTable;
|
||
ULONG NonPagedAllocsTotal,NonPagedFreesTotal,PagedAllocsTotal,PagedFreesTotal;
|
||
ULONG64 NonPagedBytesTotal, PagedBytesTotal;
|
||
|
||
if (PoolInitializeGlobals() == FALSE) {
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
Flags = 0;
|
||
if (!sscanf(args,"%lx %c%c%c%c", &Flags, &TagNameX[0],
|
||
&TagNameX[1], &TagNameX[2], &TagNameX[3])) {
|
||
Flags = 0;
|
||
}
|
||
|
||
TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
|
||
|
||
PoolTrackTableSize = GetUlongValue ("PoolTrackTableSize");
|
||
|
||
if (!(SizeOfPoolTarker = GetTypeSize("nt!_POOL_TRACKER_TABLE"))) {
|
||
dprintf("Unable to get _POOL_TRACKER_TABLE : probably wrong symbols.\n");
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
|
||
|
||
if (PoolTrackTable == 0) {
|
||
dprintf ("unable to get PoolTrackTable - ");
|
||
if (GetExpression("nt!PoolTrackTable")) {
|
||
dprintf ("pool tagging is disabled, enable it to use this command\n");
|
||
dprintf ("Use gflags.exe and check the box that says \"Enable pool tagging\".\n");
|
||
} else {
|
||
dprintf ("symbols could be worng\n");
|
||
}
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
|
||
PoolTrackTableSizeInBytes = PoolTrackTableSize * SizeOfPoolTarker;
|
||
|
||
PoolTrackTableData = malloc (PoolTrackTableSizeInBytes);
|
||
if (PoolTrackTableData == NULL) {
|
||
dprintf("unable to allocate memory for tag table.\n");
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
//
|
||
// KD is going to cache the data
|
||
//
|
||
PoolTableAddress = PoolTrackTable;
|
||
if ( !ReadMemory( PoolTableAddress,
|
||
&PoolTrackTableData[0],
|
||
PoolTrackTableSizeInBytes,
|
||
&result) ) {
|
||
dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
|
||
free (PoolTrackTableData);
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if (Flags & 2) {
|
||
SortBy = NONPAGED_USED;
|
||
dprintf(" Sorting by NonPaged Pool Consumed\n");
|
||
} else if (Flags & 4) {
|
||
SortBy = PAGED_USED;
|
||
dprintf(" Sorting by Paged Pool Consumed\n");
|
||
} else {
|
||
SortBy = TAG;
|
||
dprintf(" Sorting by Tag\n");
|
||
}
|
||
|
||
dprintf("\n Pool Used:\n");
|
||
if (!(Flags & 1)) {
|
||
dprintf(" NonPaged Paged\n");
|
||
dprintf(" Tag Allocs Used Allocs Used\n");
|
||
|
||
} else {
|
||
dprintf(" NonPaged Paged\n");
|
||
dprintf(" Tag Allocs Frees Diff Used Allocs Frees Diff Used\n");
|
||
}
|
||
|
||
ct = PageSize / SizeOfPoolTarker;
|
||
i = 0;
|
||
PoolTableAddress = PoolTrackTable;
|
||
|
||
free (PoolTrackTableData);
|
||
//
|
||
// Create array of POOL_TRACKER_TABLE addresses and sort the addresses
|
||
//
|
||
PoolTrackTableData = malloc (PoolTrackTableSize * sizeof(ULONG64));
|
||
if (PoolTrackTableData == NULL) {
|
||
dprintf("unable to allocate memory for tag table.\n");
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
while (i < PoolTrackTableSize) {
|
||
|
||
if ( CheckControlC() ) {
|
||
free (PoolTrackTableData);
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
((PULONG64) PoolTrackTableData)[i] = PoolTableAddress + i * SizeOfPoolTarker;
|
||
i++;
|
||
}
|
||
|
||
qsort((void *)PoolTrackTableData,
|
||
(size_t)PoolTrackTableSize,
|
||
(size_t)sizeof(ULONG64),
|
||
ulcomp);
|
||
|
||
i = 0;
|
||
p = (PULONG64) &PoolTrackTableData[i];
|
||
|
||
NonPagedAllocsTotal = 0;
|
||
NonPagedFreesTotal = 0;
|
||
NonPagedBytesTotal = 0;
|
||
|
||
PagedAllocsTotal = 0;
|
||
PagedFreesTotal = 0;
|
||
PagedBytesTotal = 0;
|
||
|
||
for ( ; i < PoolTrackTableSize; i += 1, p += 1) {
|
||
ULONG Key,NonPagedAllocs,NonPagedFrees,PagedAllocs,PagedFrees;
|
||
ULONG64 NonPagedBytes, PagedBytes;
|
||
|
||
#define TrackFld(F) GetFieldValue(*p, "nt!_POOL_TRACKER_TABLE", #F, F)
|
||
|
||
TrackFld(Key); TrackFld(NonPagedAllocs); TrackFld(NonPagedBytes);
|
||
TrackFld(PagedBytes); TrackFld(NonPagedFrees); TrackFld(PagedAllocs);
|
||
TrackFld(PagedFrees);
|
||
|
||
#undef TrackFld
|
||
|
||
if ((Key != 0) &&
|
||
(CheckSingleFilter ((PCHAR)&Key, (PCHAR)&TagName))) {
|
||
|
||
if (!(Flags & 1)) {
|
||
|
||
if ((NonPagedBytes != 0) || (PagedBytes != 0)) {
|
||
|
||
NonPagedAllocsTotal += NonPagedAllocs;
|
||
NonPagedFreesTotal += NonPagedFrees;
|
||
NonPagedBytesTotal += NonPagedBytes;
|
||
|
||
PagedAllocsTotal += PagedAllocs;
|
||
PagedFreesTotal += PagedFrees;
|
||
PagedBytesTotal += PagedBytes;
|
||
|
||
dprintf(" %c%c%c%c %8ld %8I64ld %8ld %8I64ld\n",
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(Key),
|
||
PP(Key >> 8),
|
||
PP(Key >> 16),
|
||
PP(Key >> 24),
|
||
NonPagedAllocs - NonPagedFrees,
|
||
NonPagedBytes,
|
||
PagedAllocs - PagedFrees,
|
||
PagedBytes);
|
||
}
|
||
|
||
} else {
|
||
|
||
NonPagedAllocsTotal += NonPagedAllocs;
|
||
NonPagedFreesTotal += NonPagedFrees;
|
||
NonPagedBytesTotal += NonPagedBytes;
|
||
|
||
PagedAllocsTotal += PagedAllocs;
|
||
PagedFreesTotal += PagedFrees;
|
||
PagedBytesTotal += PagedBytes;
|
||
|
||
dprintf(" %c%c%c%c %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
|
||
PP(Key),
|
||
PP(Key >> 8),
|
||
PP(Key >> 16),
|
||
PP(Key >> 24),
|
||
NonPagedAllocs,
|
||
NonPagedFrees,
|
||
NonPagedAllocs - NonPagedFrees,
|
||
NonPagedBytes,
|
||
PagedAllocs,
|
||
PagedFrees,
|
||
PagedAllocs - PagedFrees,
|
||
PagedBytes);
|
||
#undef PP
|
||
}
|
||
}
|
||
|
||
}
|
||
if (!(Flags & 1)) {
|
||
dprintf(" TOTAL %8ld %8I64ld %8ld %8I64ld\n",
|
||
NonPagedAllocsTotal - NonPagedFreesTotal,
|
||
NonPagedBytesTotal,
|
||
PagedAllocsTotal - PagedFreesTotal,
|
||
PagedBytesTotal);
|
||
} else {
|
||
dprintf(" TOTAL %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
|
||
NonPagedAllocsTotal,
|
||
NonPagedFreesTotal,
|
||
NonPagedAllocsTotal - NonPagedFreesTotal,
|
||
NonPagedBytesTotal,
|
||
PagedAllocsTotal,
|
||
PagedFreesTotal,
|
||
PagedAllocsTotal - PagedFreesTotal,
|
||
PagedBytesTotal);
|
||
}
|
||
|
||
free (PoolTrackTableData);
|
||
return S_OK;
|
||
}
|
||
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
|
||
BOOLEAN WINAPI
|
||
CheckSingleFilterAndPrint (
|
||
PCHAR Tag,
|
||
PCHAR Filter,
|
||
ULONG Flags,
|
||
ULONG64 PoolHeader,
|
||
ULONG BlockSize,
|
||
ULONG64 Data,
|
||
PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback to check a piece of pool and print out information about it
|
||
if it matches the specified tag.
|
||
|
||
Arguments:
|
||
|
||
Tag - Supplies the tag to search for.
|
||
|
||
Filter - Supplies the filter string to match against.
|
||
|
||
Flags - Supplies 0 if a nonpaged pool search is desired.
|
||
Supplies 1 if a paged pool search is desired.
|
||
Supplies 2 if a special pool search is desired.
|
||
Supplies 4 if a pool is a large pool
|
||
|
||
PoolHeader - Supplies the pool header.
|
||
|
||
BlockSize - Supplies the size of the pool block in bytes.
|
||
|
||
Data - Supplies the address of the pool block.
|
||
|
||
Context - Unused.
|
||
|
||
Return Value:
|
||
|
||
TRUE for a match, FALSE if not.
|
||
|
||
--*/
|
||
{
|
||
ULONG UTag = *((PULONG)Tag);
|
||
ULONG HdrUlong1=0, HdrPoolSize ;
|
||
|
||
UNREFERENCED_PARAMETER (Context);
|
||
|
||
if (CheckSingleFilter (Tag, Filter) == FALSE) {
|
||
return FALSE;
|
||
}
|
||
|
||
HdrPoolSize = GetTypeSize("nt!_POOL_HEADER");
|
||
if ((BlockSize >= (PageSize-2*HdrPoolSize)) || (Flags & 0x4)) {
|
||
dprintf("*%p :%slarge page allocation, Tag %3s %c%c%c%c, size %3s 0x%x bytes\n",
|
||
(Data & ~POOL_BIG_TABLE_ENTRY_FREE),
|
||
(Data & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
|
||
(Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
|
||
PP(UTag),
|
||
PP(UTag >> 8),
|
||
PP(UTag >> 16),
|
||
PP(UTag >> 24),
|
||
(Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
|
||
BlockSize
|
||
);
|
||
} else if (Flags & 0x2) {
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
|
||
dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
|
||
Data,
|
||
BlockSize,
|
||
HdrUlong1 & MI_SPECIAL_POOL_PAGABLE ? "pagable" : "non-paged",
|
||
PP(UTag),
|
||
PP(UTag >> 8),
|
||
PP(UTag >> 16),
|
||
PP(UTag >> 24)
|
||
);
|
||
} else {
|
||
ULONG BlockSize, PreviousSize, PoolType, PoolIndex, AllocatorBackTraceIndex;
|
||
ULONG PoolTagHash, PoolTag;
|
||
ULONG64 ProcessBilled;
|
||
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", BlockSize);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
|
||
|
||
dprintf("%p size: %4lx previous size: %4lx ",
|
||
Data - HdrPoolSize,
|
||
BlockSize << POOL_BLOCK_SHIFT,
|
||
PreviousSize << POOL_BLOCK_SHIFT);
|
||
|
||
if (PoolType == 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.
|
||
//
|
||
dprintf(" (Free)");
|
||
dprintf(" %c%c%c%c\n",
|
||
PP(UTag),
|
||
PP(UTag >> 8),
|
||
PP(UTag >> 16),
|
||
PP(UTag >> 24)
|
||
);
|
||
} else {
|
||
|
||
if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
|
||
dprintf(" (Allocated)");
|
||
} 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.
|
||
//
|
||
dprintf(" (Free )");
|
||
}
|
||
if ((PoolType & POOL_QUOTA_MASK) == 0) {
|
||
|
||
UTag = PoolTag;
|
||
|
||
dprintf(" %c%c%c%c%s\n",
|
||
PP(UTag),
|
||
PP(UTag >> 8),
|
||
PP(UTag >> 16),
|
||
PP((UTag &~PROTECTED_POOL) >> 24),
|
||
(UTag & PROTECTED_POOL) ? " (Protected)" : ""
|
||
);
|
||
|
||
} else {
|
||
if (ProcessBilled != 0) {
|
||
dprintf(" Process: %08p\n", ProcessBilled );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
return TRUE;
|
||
} // CheckSingleFilterAndPrint
|
||
|
||
#undef PP
|
||
|
||
ULONG64
|
||
GetNextResidentAddress (
|
||
ULONG64 VirtualAddress,
|
||
ULONG64 MaximumVirtualAddress
|
||
)
|
||
{
|
||
ULONG64 PointerPde;
|
||
ULONG64 PointerPte;
|
||
ULONG SizeOfPte;
|
||
ULONG Valid;
|
||
|
||
//
|
||
// Note this code will need to handle one more level of indirection for
|
||
// WIN64.
|
||
//
|
||
|
||
if (!(SizeOfPte=GetTypeSize("nt!_MMPTE"))) {
|
||
dprintf("Cannot get MMPTE type.\n");
|
||
return 0;
|
||
}
|
||
|
||
top:
|
||
|
||
PointerPde = DbgGetPdeAddress (VirtualAddress);
|
||
|
||
while (GetFieldValue(PointerPde,
|
||
"nt!_MMPTE",
|
||
"u.Hard.Valid",
|
||
Valid) ||
|
||
(Valid == 0)) {
|
||
|
||
//
|
||
// Note that on 32-bit systems, the PDE should always be readable.
|
||
// If the PDE is not valid then increment to the next PDE's VA.
|
||
//
|
||
|
||
PointerPde = (PointerPde + SizeOfPte);
|
||
|
||
VirtualAddress = DbgGetVirtualAddressMappedByPte (PointerPde);
|
||
VirtualAddress = DbgGetVirtualAddressMappedByPte (VirtualAddress);
|
||
|
||
if (VirtualAddress >= MaximumVirtualAddress) {
|
||
return VirtualAddress;
|
||
}
|
||
|
||
if (CheckControlC()) {
|
||
return VirtualAddress;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
PointerPte = DbgGetPteAddress (VirtualAddress);
|
||
|
||
while (GetFieldValue(PointerPde,
|
||
"nt!_MMPTE",
|
||
"u.Hard.Valid",
|
||
Valid) ||
|
||
(Valid == 0)) {
|
||
|
||
//
|
||
// If the PTE cannot be read then increment by PAGE_SIZE.
|
||
//
|
||
|
||
VirtualAddress = (VirtualAddress + PageSize);
|
||
|
||
if (CheckControlC()) {
|
||
return VirtualAddress;
|
||
}
|
||
|
||
PointerPte = (PointerPte + SizeOfPte);
|
||
if ((PointerPte & (PageSize - 1)) == 0) {
|
||
goto top;
|
||
}
|
||
|
||
if (VirtualAddress >= MaximumVirtualAddress) {
|
||
return VirtualAddress;
|
||
}
|
||
}
|
||
|
||
return VirtualAddress;
|
||
}
|
||
|
||
|
||
VOID
|
||
SearchPool(
|
||
ULONG TagName,
|
||
ULONG Flags,
|
||
ULONG64 RestartAddr,
|
||
POOLFILTER Filter,
|
||
PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Engine to search the 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.
|
||
Supplies 2 if a special 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:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LOGICAL PhysicallyContiguous;
|
||
ULONG PoolBlockSize;
|
||
ULONG64 PoolHeader;
|
||
ULONG PoolTag;
|
||
ULONG Result;
|
||
ULONG64 PoolPage;
|
||
ULONG64 StartPage;
|
||
ULONG64 Pool;
|
||
ULONG Previous;
|
||
ULONG64 PoolStart;
|
||
ULONG64 PoolPteAddress;
|
||
ULONG64 PoolEnd;
|
||
ULONG64 ExpandedPoolStart;
|
||
ULONG64 ExpandedPoolEnd;
|
||
ULONG InitialPoolSize;
|
||
ULONG SkipSize;
|
||
BOOLEAN TwoPools;
|
||
UCHAR DataPage[0x4000]; // MAX pzger size
|
||
ULONG64 DataPageReal;
|
||
ULONG64 DataStartReal;
|
||
LOGICAL Found;
|
||
ULONG i;
|
||
ULONG j;
|
||
ULONG ct;
|
||
ULONG PoolBigPageTableSize;
|
||
ULONG64 PoolTableAddress;
|
||
UCHAR FastTag[4];
|
||
ULONG TagLength;
|
||
ULONG SizeOfBigPages;
|
||
ULONG PoolTypeFlags = Flags & 0x3;
|
||
ULONG Ulong1;
|
||
ULONG HdrSize;
|
||
|
||
if (PoolInitializeGlobals() == FALSE) {
|
||
return;
|
||
}
|
||
|
||
if (PoolTypeFlags == 2) {
|
||
|
||
if (RestartAddr && (RestartAddr >= SpecialPoolStart) && (RestartAddr <= SpecialPoolEnd)) {
|
||
Pool = RestartAddr;
|
||
} else {
|
||
Pool = SpecialPoolStart;
|
||
}
|
||
|
||
dprintf("\nSearching special pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
|
||
Pool,
|
||
SpecialPoolEnd,
|
||
TagName,
|
||
TagName >> 8,
|
||
TagName >> 16,
|
||
TagName >> 24);
|
||
|
||
Found = FALSE;
|
||
SkipSize = PageSize;
|
||
|
||
if (SpecialPoolStart && SpecialPoolEnd) {
|
||
|
||
//
|
||
// Search special pool for the tag.
|
||
//
|
||
|
||
while (Pool < SpecialPoolEnd) {
|
||
|
||
if ( CheckControlC() ) {
|
||
dprintf("\n...terminating - searched pool to %p\n",
|
||
Pool);
|
||
return;
|
||
}
|
||
|
||
DataStartReal = Pool;
|
||
DataPageReal = Pool;
|
||
if ( !ReadMemory( Pool,
|
||
&DataPage[0],
|
||
min(PageSize, sizeof(DataPage)),
|
||
&Result) ) {
|
||
ULONG64 PteLong=0, PageFileHigh;
|
||
|
||
if (SkipSize != 2 * PageSize) {
|
||
|
||
// dprintf("SP skip %x", Pool);
|
||
PoolPteAddress = DbgGetPteAddress (Pool);
|
||
|
||
if (!GetFieldValue(PoolPteAddress,
|
||
"nt!_MMPTE",
|
||
"u.Soft.PageFileHigh",
|
||
PageFileHigh) ) {
|
||
|
||
if ((PageFileHigh == 0) ||
|
||
(PageFileHigh == MI_SPECIAL_POOL_PTE_PAGABLE) ||
|
||
(PageFileHigh == MI_SPECIAL_POOL_PTE_NONPAGABLE)) {
|
||
|
||
//
|
||
// Found a NO ACCESS PTE - skip these from
|
||
// here on to speed up the search.
|
||
//
|
||
|
||
// dprintf("SP skip double %p", PoolPteAddress);
|
||
SkipSize = 2 * PageSize;
|
||
Pool += PageSize;
|
||
// dprintf("SP skip final %p", Pool);
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
Pool += SkipSize;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Determine whether this is a valid special pool block.
|
||
//
|
||
|
||
PoolHeader = GetSpecialPoolHeader (DataPage,
|
||
DataPageReal,
|
||
&DataStartReal);
|
||
|
||
if (PoolHeader != 0) {
|
||
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Ulong1);
|
||
PoolBlockSize = (ULONG) SPECIAL_POOL_BLOCK_SIZE(Ulong1);
|
||
|
||
Found = Filter( (PCHAR)&PoolTag,
|
||
(PCHAR)&TagName,
|
||
Flags,
|
||
PoolHeader,
|
||
PoolBlockSize,
|
||
DataStartReal,
|
||
Context );
|
||
} else {
|
||
dprintf( "No pool header for page: 0x%p\n", Pool );
|
||
}
|
||
Pool += SkipSize;
|
||
}
|
||
}
|
||
|
||
if (Found == FALSE) {
|
||
dprintf("The %c%c%c%c tag could not be found in special pool.\n",
|
||
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
||
PP(TagName),
|
||
PP(TagName >> 8),
|
||
PP(TagName >> 16),
|
||
PP(TagName >> 24)
|
||
);
|
||
#undef PP
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (PoolTypeFlags == 0) {
|
||
PhysicallyContiguous = TRUE;
|
||
} else {
|
||
PhysicallyContiguous = FALSE;
|
||
}
|
||
|
||
__try {
|
||
TwoPools = FALSE;
|
||
|
||
if (!PoolBigTableAddress) {
|
||
PoolBigTableAddress = GetPointerValue ("PoolBigPageTable");
|
||
}
|
||
|
||
PoolTableAddress = PoolBigTableAddress;
|
||
|
||
if (PoolTableAddress) {
|
||
|
||
ULONG VaOffset;
|
||
ULONG NumPagesOffset;
|
||
ULONG PtrSize;
|
||
ULONG KeyOffset;
|
||
|
||
PoolBigPageTableSize = GetUlongValue ("PoolBigPageTableSize");
|
||
|
||
//
|
||
// Scan the table looking for a match. We read close to a page at a time
|
||
// physical page / sizeof ( pool_tracker_big_page ) * sizeof ( pool_tracker_big_page )
|
||
// on x86 this works out to ffc
|
||
//
|
||
|
||
i = 0;
|
||
SizeOfBigPages = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
|
||
if (!SizeOfBigPages) {
|
||
dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
|
||
return;
|
||
}
|
||
ct = PageSize / SizeOfBigPages;
|
||
|
||
dprintf( "\nScanning large pool allocation table for Tag: %c%c%c%c (%p : %p)\n\n\r",
|
||
TagName,
|
||
TagName >> 8,
|
||
TagName >> 16,
|
||
TagName >> 24,
|
||
PoolBigTableAddress,
|
||
PoolBigTableAddress + PoolBigPageTableSize * SizeOfBigPages );
|
||
|
||
GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Va", &VaOffset );
|
||
GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "NumberOfPages", &NumPagesOffset );
|
||
GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Key", &KeyOffset );
|
||
PtrSize = IsPtr64() ? 8 : 4;
|
||
|
||
while (i < PoolBigPageTableSize) {
|
||
|
||
if (PoolBigPageTableSize - i < ct) {
|
||
ct = PoolBigPageTableSize - i;
|
||
}
|
||
|
||
if ( !ReadMemory( PoolTableAddress,
|
||
&DataPage[0],
|
||
ct * SizeOfBigPages,
|
||
&Result) ) {
|
||
|
||
dprintf( "%08lx: Unable to get contents of big pool block\r\n", PoolTableAddress );
|
||
break;
|
||
}
|
||
|
||
for (j = 0; j < ct; j += 1) {
|
||
ULONG64 Va = 0;
|
||
|
||
memcpy( &Va, (PCHAR)DataPage + (SizeOfBigPages * j) + VaOffset, PtrSize );
|
||
|
||
Filter( ((PCHAR)DataPage + (SizeOfBigPages * j) + KeyOffset),
|
||
(PCHAR)&TagName,
|
||
Flags | 0x4, // To assist filter routine to recognize this as large pool
|
||
PoolTableAddress + SizeOfBigPages * j,
|
||
(*((PULONG)((PCHAR)DataPage + (SizeOfBigPages * j) + NumPagesOffset))) * PageSize,
|
||
Va,
|
||
Context );
|
||
if ( CheckControlC() ) {
|
||
dprintf("\n...terminating - searched pool to %p\n",
|
||
PoolTableAddress + j * SizeOfBigPages);
|
||
return;
|
||
}
|
||
}
|
||
i += ct;
|
||
PoolTableAddress += (ct * SizeOfBigPages);
|
||
if ( CheckControlC() ) {
|
||
dprintf("\n...terminating - searched pool to %p\n",
|
||
PoolTableAddress);
|
||
return;
|
||
}
|
||
|
||
}
|
||
} else {
|
||
dprintf("unable to get large pool allocation table - either wrong symbols or pool tagging is disabled\n");
|
||
}
|
||
|
||
if (PoolTypeFlags == 0) {
|
||
PoolStart = GetNtDebuggerDataPtrValue( MmNonPagedPoolStart );
|
||
|
||
if (0 == PoolStart) {
|
||
dprintf( "Unable to get MmNonPagedPoolStart\n" );
|
||
}
|
||
|
||
PoolEnd =
|
||
PoolStart + GetNtDebuggerDataValue( MmMaximumNonPagedPoolInBytes );
|
||
|
||
ExpandedPoolEnd = GetNtDebuggerDataPtrValue( MmNonPagedPoolEnd );
|
||
|
||
if (PoolEnd != ExpandedPoolEnd) {
|
||
InitialPoolSize = (ULONG)GetUlongValue( "MmSizeOfNonPagedPoolInBytes" );
|
||
PoolEnd = PoolStart + InitialPoolSize;
|
||
|
||
ExpandedPoolStart = GetPointerValue( "MmNonPagedPoolExpansionStart" );
|
||
TwoPools = TRUE;
|
||
}
|
||
for (TagLength = 0;TagLength < 3; TagLength++) {
|
||
if ((*(((PCHAR)&TagName)+TagLength) == '?') ||
|
||
(*(((PCHAR)&TagName)+TagLength) == '*')) {
|
||
break;
|
||
}
|
||
FastTag[TagLength] = *(((PCHAR)&TagName)+TagLength);
|
||
}
|
||
|
||
} else {
|
||
PoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
|
||
PoolEnd =
|
||
PoolStart + GetNtDebuggerDataValue( MmSizeOfPagedPoolInBytes );
|
||
}
|
||
|
||
if (RestartAddr) {
|
||
PoolStart = RestartAddr;
|
||
if (TwoPools == TRUE) {
|
||
if (PoolStart > PoolEnd) {
|
||
TwoPools = FALSE;
|
||
PoolStart = RestartAddr;
|
||
PoolEnd = ExpandedPoolEnd;
|
||
}
|
||
}
|
||
}
|
||
|
||
dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
|
||
(PoolTypeFlags == 0) ? "NonPaged" : "Paged",
|
||
PoolStart,
|
||
PoolEnd,
|
||
TagName,
|
||
TagName >> 8,
|
||
TagName >> 16,
|
||
TagName >> 24);
|
||
|
||
PoolPage = PoolStart;
|
||
HdrSize = GetTypeSize("nt!_POOL_HEADER");
|
||
while (PoolPage < PoolEnd) {
|
||
|
||
//
|
||
// Optimize things by ioctl'ing over to the other side to
|
||
// do a fast search and start with that page.
|
||
//
|
||
if ((PoolTypeFlags == 0) &&
|
||
PhysicallyContiguous &&
|
||
(TagLength > 0)) {
|
||
SEARCHMEMORY Search;
|
||
|
||
Search.SearchAddress = PoolPage;
|
||
Search.SearchLength = PoolEnd-PoolPage;
|
||
Search.PatternLength = TagLength;
|
||
Search.Pattern = &FastTag;
|
||
Search.FoundAddress = 0;
|
||
if ((Ioctl(IG_SEARCH_MEMORY, &Search, sizeof(Search))) &&
|
||
(Search.FoundAddress != 0)) {
|
||
//
|
||
// Got a hit, search the whole page
|
||
//
|
||
PoolPage = PAGE_ALIGN64(Search.FoundAddress);
|
||
} else {
|
||
//
|
||
// The tag was not found at all, so we can just skip
|
||
// this chunk entirely.
|
||
//
|
||
PoolPage = PoolEnd;
|
||
goto skiprange;
|
||
}
|
||
}
|
||
|
||
Pool = PAGE_ALIGN64 (PoolPage);
|
||
StartPage = Pool;
|
||
Previous = 0;
|
||
|
||
while (PAGE_ALIGN64(Pool) == StartPage) {
|
||
|
||
ULONG HdrPoolTag, BlockSize, PreviousSize, AllocatorBackTraceIndex, PoolTagHash;
|
||
ULONG PoolType;
|
||
|
||
if ( GetFieldValue(Pool,
|
||
"nt!_POOL_HEADER",
|
||
"PoolTag",
|
||
HdrPoolTag) ) {
|
||
|
||
PoolPage = GetNextResidentAddress (Pool, PoolEnd);
|
||
|
||
//
|
||
// If we're half resident - half non-res then we'll get back
|
||
// that are starting address is the next resident page. In that
|
||
// case just go on to the next page
|
||
//
|
||
|
||
if (PoolPage == Pool) {
|
||
PoolPage = PoolPage + PageSize;
|
||
}
|
||
|
||
goto nextpage;
|
||
}
|
||
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTag",HdrPoolTag);
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","PoolType", PoolType);
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","BlockSize",BlockSize);
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTagHash",PoolTagHash);
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","PreviousSize",PreviousSize);
|
||
GetFieldValue(Pool,"nt!_POOL_HEADER","AllocatorBackTraceIndex",AllocatorBackTraceIndex);
|
||
|
||
if ((BlockSize << POOL_BLOCK_SHIFT) > POOL_PAGE_SIZE) {
|
||
//dprintf("Bad allocation size @%lx, too large\n", Pool);
|
||
break;
|
||
}
|
||
|
||
if (BlockSize == 0) {
|
||
//dprintf("Bad allocation size @%lx, zero is invalid\n", Pool);
|
||
break;
|
||
}
|
||
|
||
if (PreviousSize != Previous) {
|
||
//dprintf("Bad previous allocation size @%lx, last size was %lx\n",Pool, Previous);
|
||
break;
|
||
}
|
||
|
||
PoolTag = HdrPoolTag;
|
||
|
||
Filter((PCHAR)&PoolTag,
|
||
(PCHAR)&TagName,
|
||
Flags,
|
||
Pool,
|
||
BlockSize << POOL_BLOCK_SHIFT,
|
||
Pool + HdrSize,
|
||
Context );
|
||
|
||
Previous = BlockSize;
|
||
Pool += (Previous << POOL_BLOCK_SHIFT);
|
||
if ( CheckControlC() ) {
|
||
dprintf("\n...terminating - searched pool to %p\n",
|
||
PoolPage);
|
||
return;
|
||
}
|
||
}
|
||
PoolPage = (PoolPage + PageSize);
|
||
nextpage:
|
||
if ( CheckControlC() ) {
|
||
dprintf("\n...terminating - searched pool to %p\n",
|
||
PoolPage);
|
||
return;
|
||
}
|
||
skiprange:
|
||
if (TwoPools == TRUE) {
|
||
if (PoolPage == PoolEnd) {
|
||
TwoPools = FALSE;
|
||
PoolStart = ExpandedPoolStart;
|
||
PoolEnd = ExpandedPoolEnd;
|
||
PoolPage = PoolStart;
|
||
PhysicallyContiguous = FALSE;
|
||
|
||
dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\n\n",
|
||
"NonPaged",
|
||
PoolStart,
|
||
PoolEnd,
|
||
TagName,
|
||
TagName >> 8,
|
||
TagName >> 16,
|
||
TagName >> 24);
|
||
}
|
||
}
|
||
}
|
||
} __finally {
|
||
}
|
||
|
||
return;
|
||
} // SearchPool
|
||
|
||
|
||
|
||
DECLARE_API( poolfind )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
flags == 0 means finds a tag in nonpaged pool.
|
||
flags == 1 means finds a tag in paged pool.
|
||
flags == 2 means finds a tag in special pool.
|
||
|
||
Arguments:
|
||
|
||
args -
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Flags;
|
||
CHAR TagNameX[4] = {' ',' ',' ',' '};
|
||
ULONG TagName;
|
||
ULONG64 PoolTrackTable;
|
||
|
||
Flags = 0;
|
||
if (!sscanf(args,"%c%c%c%c %lx", &TagNameX[0],
|
||
&TagNameX[1], &TagNameX[2], &TagNameX[3], &Flags)) {
|
||
Flags = 0;
|
||
}
|
||
|
||
if (TagNameX[0] == '0' && TagNameX[1] == 'x') {
|
||
if (!sscanf( args, "%lx %lx", &TagName, &Flags )) {
|
||
TagName = 0;
|
||
}
|
||
} else {
|
||
TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
|
||
}
|
||
|
||
PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
|
||
if (PoolTrackTable == 0) {
|
||
dprintf ("unable to get PoolTrackTable - probably pool tagging disabled or wrong symbols\n");
|
||
}
|
||
|
||
|
||
SearchPool( TagName, Flags, 0, CheckSingleFilterAndPrint, NULL );
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
CheckSingleFilter (
|
||
PCHAR Tag,
|
||
PCHAR Filter
|
||
)
|
||
{
|
||
ULONG i;
|
||
UCHAR tc;
|
||
UCHAR fc;
|
||
|
||
for ( i = 0; i < 4; i++ ) {
|
||
tc = (UCHAR) *Tag++;
|
||
fc = (UCHAR) *Filter++;
|
||
if ( fc == '*' ) return TRUE;
|
||
if ( fc == '?' ) continue;
|
||
if (i == 3 && (tc & ~(PROTECTED_POOL >> 24)) == fc) continue;
|
||
if ( tc != fc ) return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
ULONG64
|
||
GetSpecialPoolHeader (
|
||
IN PVOID DataPage,
|
||
IN ULONG64 RealDataPage,
|
||
OUT PULONG64 ReturnedDataStart
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Examine a page of data to determine if it is a special pool block.
|
||
|
||
Arguments:
|
||
|
||
DataPage - Supplies a pointer to a page of data to examine.
|
||
|
||
ReturnedDataStart - Supplies a pointer to return the start of the data.
|
||
Only valid if this routine returns non-NULL.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the pool header for this special pool block or
|
||
NULL if the block is not valid special pool.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG PoolBlockSize;
|
||
ULONG PoolHeaderSize;
|
||
ULONG PoolBlockPattern;
|
||
PUCHAR p;
|
||
PUCHAR PoolDataEnd;
|
||
PUCHAR DataStart;
|
||
ULONG64 PoolHeader;
|
||
ULONG HdrUlong1;
|
||
|
||
PoolHeader = RealDataPage;
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
|
||
//
|
||
// Determine whether the data is at the start or end of the page.
|
||
// Start off by assuming the data is at the end, in this case the
|
||
// header will be at the start.
|
||
//
|
||
|
||
PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
|
||
|
||
if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
|
||
|
||
PoolHeaderSize = POOL_OVERHEAD;
|
||
if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
|
||
PoolHeaderSize += GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
|
||
}
|
||
|
||
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
|
||
|
||
DataStart = (PUCHAR)DataPage + PageSize - PoolBlockSize;
|
||
p = (PUCHAR)DataPage + PoolHeaderSize;
|
||
|
||
for ( ; p < DataStart; p += 1) {
|
||
if (*p != PoolBlockPattern) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p == DataStart || p >= (PUCHAR)DataPage + PoolHeaderSize + 0x10) {
|
||
|
||
//
|
||
// For this page, the data is at the end of the block.
|
||
// The 0x10 is just to give corrupt blocks some slack.
|
||
// All pool allocations are quadword aligned.
|
||
//
|
||
|
||
DataStart = (PUCHAR)DataPage + ((PageSize - PoolBlockSize) & ~(sizeof(QUAD)-1));
|
||
|
||
*ReturnedDataStart = RealDataPage + (ULONG64) ((PUCHAR) DataStart - (PUCHAR) DataPage);
|
||
return PoolHeader;
|
||
}
|
||
|
||
//
|
||
// The data must be at the front or the block is corrupt.
|
||
//
|
||
}
|
||
|
||
//
|
||
// Try for the data at the front. Checks are necessary as
|
||
// the page could be corrupt on both ends.
|
||
//
|
||
|
||
PoolHeader = (RealDataPage + PageSize - POOL_OVERHEAD);
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
|
||
PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
|
||
|
||
if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
|
||
PoolDataEnd = (PUCHAR)PoolHeader;
|
||
|
||
if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
|
||
PoolDataEnd -= GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
|
||
}
|
||
|
||
|
||
GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
|
||
DataStart = (PUCHAR)DataPage;
|
||
|
||
p = DataStart + PoolBlockSize;
|
||
for ( ; p < PoolDataEnd; p += 1) {
|
||
if (*p != PoolBlockPattern) {
|
||
break;
|
||
}
|
||
}
|
||
if (p == (PUCHAR)PoolDataEnd || p > (PUCHAR)DataPage + PoolBlockSize + 0x10) {
|
||
//
|
||
// For this page, the data is at the front of the block.
|
||
// The 0x10 is just to give corrupt blocks some slack.
|
||
// All pool allocations are quadword aligned.
|
||
//
|
||
|
||
*ReturnedDataStart = RealDataPage + (ULONG64)( (PUCHAR)DataStart - (PUCHAR) DataPage);
|
||
return PoolHeader;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Not valid special pool.
|
||
//
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
#define BYTE(u,n) ((u & (0xff << 8*n)) >> 8*n)
|
||
#define LOCHAR_BYTE(u,n) (tolower(BYTE(u,n)) & 0xff)
|
||
#define REVERSE_ULONGBYTES(u) (LOCHAR_BYTE(u,3) | (LOCHAR_BYTE(u,2) << 8) | (LOCHAR_BYTE(u,1) << 16) | (LOCHAR_BYTE(u,0) << 24))
|
||
|
||
|
||
PSTR
|
||
GetNextLine(
|
||
HANDLE hFile
|
||
)
|
||
// Returns next line in the file hFile
|
||
// Returns NULL if EOF is reached
|
||
{
|
||
static CHAR FileLines1[MAX_PATH] = {0}, FileLines2[MAX_PATH] = {0};
|
||
static CHAR FileLine[MAX_PATH];
|
||
PCHAR pEOL;
|
||
ULONG BytesRead;
|
||
PCHAR pEndOfBuff;
|
||
ULONG BuffLen, ReadLen;
|
||
|
||
pEOL = NULL;
|
||
if (!(pEOL = strchr(FileLines1, '\n'))) {
|
||
// We have something that was already read but it isn't enough for a whole line
|
||
// We need to read the data
|
||
|
||
BuffLen = strlen(FileLines1);
|
||
|
||
// sanity check
|
||
if (BuffLen >= sizeof(FileLines1)) {
|
||
return NULL;
|
||
}
|
||
|
||
pEndOfBuff = &FileLines1[0] + BuffLen;
|
||
ReadLen = sizeof(FileLines1) - BuffLen;
|
||
|
||
ZeroMemory(pEndOfBuff, ReadLen);
|
||
if (ReadFile(hFile, pEndOfBuff, ReadLen - 1, &BytesRead, NULL)) {
|
||
pEOL = strchr(FileLines1, '\n');
|
||
}
|
||
}
|
||
|
||
if (pEOL) {
|
||
FileLine[0] = 0;
|
||
|
||
strncat(FileLine,FileLines1, (ULONG) (pEOL - &FileLines1[0]));
|
||
strcpy(FileLines2, pEOL+1);
|
||
strcpy(FileLines1, FileLines2);
|
||
return FileLine;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
EXTENSION_API ( GetPoolRegion )(
|
||
PDEBUG_CLIENT Client,
|
||
ULONG64 Pool,
|
||
DEBUG_POOL_REGION *PoolData
|
||
)
|
||
{
|
||
INIT_API();
|
||
|
||
*PoolData = GetPoolRegion(Pool);
|
||
|
||
EXIT_API();
|
||
return S_OK;
|
||
}
|
||
|
||
EXTENSION_API ( GetPoolData )(
|
||
PDEBUG_CLIENT Client,
|
||
ULONG64 Pool,
|
||
PDEBUG_POOL_DATA PoolData
|
||
)
|
||
{
|
||
PCHAR Desc;
|
||
HRESULT Hr;
|
||
PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
|
||
|
||
INIT_API();
|
||
|
||
if (!PoolInitializeGlobals()) {
|
||
EXIT_API();
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
Hr = ListPoolPage(Pool, 0x80000002, PoolData);
|
||
|
||
if (Hr != S_OK) {
|
||
EXIT_API();
|
||
return Hr;
|
||
}
|
||
|
||
GetPoolTagDescription = NULL;
|
||
#ifndef _EXTFNS_H
|
||
if (!GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription)) {
|
||
EXIT_API();
|
||
return E_INVALIDARG;
|
||
}
|
||
(*GetPoolTagDescription)(PoolData->PoolTag, &Desc);
|
||
if (Desc) {
|
||
ULONG strsize = strlen(Desc);
|
||
if (strsize > sizeof(PoolData->PoolTagDescription)) {
|
||
strsize = sizeof(PoolData->PoolTagDescription);
|
||
}
|
||
strncpy(PoolData->PoolTagDescription, Desc, strsize);
|
||
PoolData->PoolTagDescription[strsize] = 0;
|
||
}
|
||
#endif
|
||
EXIT_API();
|
||
return Hr;
|
||
}
|