369 lines
7.3 KiB
C++
369 lines
7.3 KiB
C++
/*++
|
||
|
||
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 )
|
||
|