|
|
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name:
heapfind.cxx
Abstract:
This module contains an NTSD debugger extension for dumping various bits of heap information.
Author:
Keith Moore (keithmo) 01-Nov-1997
Revision History:
--*/
#include "inetdbgp.h"
typedef struct _ENUM_CONTEXT {
ULONG SizeToDump; ULONG DumpCount; PUCHAR BlockToSearchFor; BOOLEAN ContinueEnum;
} ENUM_CONTEXT, *PENUM_CONTEXT;
/************************************************************
* Dump Heap Info ************************************************************/
BOOLEAN CALLBACK HfpEnumHeapSegmentEntriesProc( IN PVOID Param, IN PHEAP_ENTRY LocalHeapEntry, IN PHEAP_ENTRY RemoteHeapEntry )
/*++
Routine Description:
Callback invoked for each heap entry within a heap segment.
Arguments:
Param - An uninterpreted parameter passed to the enumerator.
LocalHeapEntry - Pointer to a local copy of the HEAP_ENTRY structure.
RemoteHeapEntry - The remote address of the HEAP_ENTRY structure in the debugee.
Return Value:
BOOLEAN - TRUE if the enumeration should continue, FALSE if it should be terminated.
--*/
{
PENUM_CONTEXT context = (PENUM_CONTEXT)Param; PUCHAR entryStart; ULONG entryLength; BOOLEAN dumpBlock = FALSE;
//
// allow user to break out of lengthy enumeration
//
if( CheckControlC() ) { context->ContinueEnum = FALSE; return TRUE; }
//
// Ignore free blocks.
//
if( !( LocalHeapEntry->Flags & HEAP_ENTRY_BUSY ) ) { return TRUE; }
//
// Calculate the start & length of the heap block.
//
entryStart = (PUCHAR)RemoteHeapEntry + sizeof(HEAP_ENTRY);
entryLength = ( (ULONG)LocalHeapEntry->Size << HEAP_GRANULARITY_SHIFT ) - (ULONG)LocalHeapEntry->UnusedBytes;
//
// Decide how to handle this request.
//
if( context->BlockToSearchFor != NULL ) {
//
// The user is looking for the heap block that contains a
// specific address. If the current block is a match, then
// dump it and terminate the enumeration.
//
if( context->BlockToSearchFor >= entryStart && context->BlockToSearchFor < ( entryStart + entryLength ) ) {
dumpBlock = TRUE; context->ContinueEnum = FALSE;
}
} else {
//
// The user is looking for blocks of a specific size. If the
// size matches, or the user is looking for "big" blocks and
// the current block is >= 64K, then dump it.
//
if( context->SizeToDump == entryLength || ( context->SizeToDump == 0xFFFFFFFF && entryLength >= 65536 ) ) {
dumpBlock = TRUE;
}
}
if( dumpBlock ) { context->DumpCount++; dprintf( "HeapEntry @ %08lp [%08lp], flags = %02x, length = %lx\n", RemoteHeapEntry, entryStart, (ULONG)LocalHeapEntry->Flags, entryLength ); }
return context->ContinueEnum;
} // HfpEnumHeapSegmentEntriesProc
BOOLEAN CALLBACK HfpEnumHeapSegmentsProc( IN PVOID Param, IN PHEAP_SEGMENT LocalHeapSegment, IN PHEAP_SEGMENT RemoteHeapSegment, IN ULONG HeapSegmentIndex )
/*++
Routine Description:
Callback invoked for each heap segment within a heap.
Arguments:
Param - An uninterpreted parameter passed to the enumerator.
LocalHeapSegment - Pointer to a local copy of the HEAP_SEGMENT structure.
RemoteHeapSegment - The remote address of the HEAP_SEGMENT structure in the debugee.
Return Value:
BOOLEAN - TRUE if the enumeration should continue, FALSE if it should be terminated.
--*/
{
PENUM_CONTEXT context = (PENUM_CONTEXT)Param;
//
// Enumerate the entries for the specified segment.
//
if( !EnumHeapSegmentEntries( LocalHeapSegment, RemoteHeapSegment, HfpEnumHeapSegmentEntriesProc, (PVOID)context ) ) { dprintf( "error retrieving heap segment entries\n" ); return FALSE; }
return context->ContinueEnum;
} // HfpEnumHeapSegmentsProc
BOOLEAN CALLBACK HfpEnumHeapsProc( IN PVOID Param, IN PHEAP LocalHeap, IN PHEAP RemoteHeap, IN ULONG HeapIndex )
/*++
Routine Description:
Callback invoked for each heap within a process.
Arguments:
Param - An uninterpreted parameter passed to the enumerator.
LocalHeap - Pointer to a local copy of the HEAP structure.
RemoteHeap - The remote address of the HEAP structure in the debugee.
Return Value:
BOOLEAN - TRUE if the enumeration should continue, FALSE if it should be terminated.
--*/
{
PENUM_CONTEXT context = (PENUM_CONTEXT)Param;
//
// Enumerate the segments for the specified heap.
//
if( !EnumHeapSegments( LocalHeap, RemoteHeap, HfpEnumHeapSegmentsProc, (PVOID)context ) ) { dprintf( "error retrieving heap segments\n" ); return FALSE; }
return context->ContinueEnum;
} // HfpEnumHeapsProc
DECLARE_API( heapfind )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump heap information.
Arguments:
hCurrentProcess - Supplies a handle to the current process (at the time the extension was called).
hCurrentThread - Supplies a handle to the current thread (at the time the extension was called).
CurrentPc - Supplies the current pc at the time the extension is called.
lpExtensionApis - Supplies the address of the functions callable by this extension.
lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped.
Return Value:
None.
--*/
{
ENUM_CONTEXT context;
INIT_API();
//
// Setup.
//
RtlZeroMemory( &context, sizeof(context) );
context.ContinueEnum = TRUE;
//
// Skip leading blanks.
//
while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; }
if( *lpArgumentString == '\0' || *lpArgumentString != '-' ) { PrintUsage( "heapfind" ); return; }
lpArgumentString++;
//
// Interpret the command-line switch.
//
switch( *lpArgumentString ) { case 'a' : case 'A' : lpArgumentString++; context.BlockToSearchFor = (PUCHAR)strtoul( lpArgumentString, NULL, 16 ); break;
case 's' : case 'S' : lpArgumentString++; context.SizeToDump = (ULONG)strtoul( lpArgumentString, NULL, 16 ); break;
default : PrintUsage( "heapfind" ); return; }
//
// Enumerate the heaps, which will enumerate the segments, which
// will enumerate the entries, which will search for the specified
// address or specified size.
//
if( !EnumProcessHeaps( HfpEnumHeapsProc, (PVOID)&context ) ) { dprintf( "error retrieving process heaps\n" ); } else { if (context.DumpCount > 0) { dprintf( "Total count: %08lx\n", context.DumpCount); } }
} // DECLARE_API( heapfind )
|