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 )
|
|||
|
|