Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2447 lines
72 KiB

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <memory.h>
#include <ntos.h>
#include <nturtl.h>
#include <windows.h>
#include <imagehlp.h>
#include <symhelp.h>
BOOLEAN fVerbose;
BOOLEAN fDumpModules;
BOOLEAN fDumpBackTraces;
BOOLEAN fIgnoreBackTraces;
BOOLEAN fDumpHeapSummaries;
BOOLEAN fDumpHeapTags;
BOOLEAN fDumpHeapEntries;
BOOLEAN fDumpHeapHogs;
BOOLEAN fDumpLocks;
BOOLEAN fDumpSystemObjects;
BOOLEAN fDumpSystemProcesses;
BOOLEAN fDumpKernelModeInformation;
DWORD ProcessId;
HANDLE OutputFile;
CHAR DumpLine[512];
char OutputFileName[ MAX_PATH ];
PRTL_DEBUG_INFORMATION
RtlQuerySystemDebugInformation(
ULONG Flags
);
BOOLEAN
ComputeSymbolicBackTraces(
PRTL_PROCESS_BACKTRACES BackTraces1
);
BOOLEAN
LoadSymbolsForModules(
PRTL_PROCESS_MODULES Modules
);
VOID
DumpModules(
PRTL_PROCESS_MODULES Modules
);
VOID
DumpBackTraces( VOID );
VOID
DumpHeaps(
PRTL_PROCESS_HEAPS Heaps,
BOOLEAN fDumpSummary,
BOOLEAN fDumpHogs,
BOOLEAN fDumpTags,
BOOLEAN fDumpEntries
);
VOID
DumpLocks(
PRTL_PROCESS_LOCKS Locks
);
VOID
DumpSystemProcesses( VOID );
VOID
DumpObjects( VOID );
VOID
DumpHandles( VOID );
VOID
DumpOutputString( VOID )
{
DWORD d;
if (OutputFile == NULL) {
return;
}
if (!WriteFile(OutputFile,DumpLine,strlen(DumpLine),&d,NULL)) {
CloseHandle( OutputFile );
OutputFile = NULL;
}
}
VOID
Usage( VOID )
{
fprintf( stderr, "Usage: DH [-l] [-m] [-s] [-g] [-h] [-t] [-p -1 | 0 [-o] | n] [-f fileName]\n" );
fprintf( stderr, "where: -l - displays information about locks.\n" );
fprintf( stderr, " -m - displays information about module table.\n" );
fprintf( stderr, " -s - displays summary information about heaps.\n" );
fprintf( stderr, " -g - displays information about memory hogs.\n" );
fprintf( stderr, " -h - displays information about heap entries for each heap.\n" );
fprintf( stderr, " -t - displays information about heap tags for each heap.\n" );
fprintf( stderr, " -b - displays information about stack back trace database.\n" );
fprintf( stderr, " -i - ignore information about stack back trace database.\n" );
fprintf( stderr, " -p 0 - displays information about kernel memory and objects in DH_SYS.DMP.\n" );
fprintf( stderr, " -o - displays information about object handles (only valid with -p 0).\n" );
fprintf( stderr, " -k - displays information about processes and threads (only valid with -p 0).\n" );
fprintf( stderr, " -p -1 - displays information about Win32 Subsystem process in DH_WIN32.DMP.\n" );
fprintf( stderr, " -p n - displays information about process with ClientId of n\n" );
fprintf( stderr, " -f fileName - specifies the name of the file to write the dump to.\n" );
fprintf( stderr, " Default file name is DH_nnnn.DMP where nnnn is the process id.\n" );
fprintf( stderr, " -- specifies the dump output should be written to stdout.\n" );
fprintf( stderr, "\n" );
fprintf( stderr, " Default flags are: -p -1 -m -l -s -g -h\n" );
exit( 1 );
}
VOID
InitializeSymbolPathEnvVar( VOID )
{
DWORD n;
char Buffer[ MAX_PATH ];
n = GetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer, sizeof( Buffer ) );
if (n == 0) {
n = GetEnvironmentVariable( "SystemRoot", Buffer, sizeof( Buffer ) );
if (n != 0) {
strcat( Buffer, "\\Symbols" );
SetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer );
fprintf( stderr, "DH: Default _NT_SYMBOL_PATH to %s\n", Buffer );
}
}
return;
}
int _CRTAPI1
main(
int argc,
char *argv[],
char *envp[]
)
{
char FileNameBuffer[ 32 ];
char *FilePart;
char *s;
NTSTATUS Status;
PRTL_DEBUG_INFORMATION p;
ULONG QueryDebugProcessFlags;
ULONG HeapNumber;
PRTL_HEAP_INFORMATION HeapInfo;
InitializeSymbolPathEnvVar();
ProcessId = 0xFFFFFFFF;
OutputFile = NULL;
OutputFileName[ 0 ] = '\0';
while (--argc) {
s = *++argv;
if (*s == '/' || *s == '-') {
while (*++s) {
switch (tolower(*s)) {
case 'v':
case 'V':
fVerbose = TRUE;
break;
case 'i':
case 'I':
fIgnoreBackTraces = TRUE;
break;
case 'b':
case 'B':
fDumpBackTraces = TRUE;
break;
case 'g':
case 'G':
fDumpHeapHogs = TRUE;
break;
case 'h':
case 'H':
fDumpHeapEntries = TRUE;
break;
case 't':
case 'T':
fDumpHeapTags = TRUE;
break;
case 'l':
case 'L':
fDumpLocks = TRUE;
break;
case 'm':
case 'M':
fDumpModules = TRUE;
break;
case 'o':
case 'O':
fDumpSystemObjects = TRUE;
break;
case 'k':
case 'K':
fDumpSystemProcesses = TRUE;
break;
case 's':
case 'S':
fDumpHeapSummaries = TRUE;
break;
case 'p':
case 'P':
if (--argc) {
ProcessId = atoi( *++argv );
if (ProcessId == 0) {
fDumpKernelModeInformation = TRUE;
}
}
else {
Usage();
}
break;
case '-':
OutputFile = GetStdHandle( STD_OUTPUT_HANDLE );
break;
case 'f':
case 'F':
if (--argc) {
strcpy( OutputFileName, *++argv );
}
else {
Usage();
}
break;
default:
Usage();
}
}
}
else {
Usage();
}
}
if (!fDumpModules && !fDumpHeapSummaries &&
!fDumpHeapTags && !fDumpHeapHogs && !fDumpLocks
) {
fDumpModules = TRUE;
fDumpHeapSummaries = TRUE;
fDumpHeapTags = TRUE;
fDumpHeapHogs = TRUE;
if (fDumpKernelModeInformation) {
if (!fDumpSystemObjects &&
!fDumpSystemProcesses
) {
fDumpSystemObjects = TRUE;
fDumpSystemProcesses = TRUE;
}
}
else {
fDumpLocks = TRUE;
}
}
if ((fDumpSystemObjects || fDumpSystemProcesses) && !fDumpKernelModeInformation) {
Usage();
}
if (OutputFile == NULL) {
if (OutputFileName[ 0 ] == '\0') {
if ( ProcessId == -1 ) {
sprintf( FileNameBuffer, "DH_win32.dmp" );
}
else
if ( ProcessId == 0 ) {
sprintf( FileNameBuffer, "DH_sys.dmp" );
}
else {
sprintf( FileNameBuffer, "DH_%u.dmp", (USHORT)ProcessId );
}
GetFullPathName( FileNameBuffer,
sizeof( OutputFileName ),
OutputFileName,
&FilePart
);
}
}
else {
strcpy( OutputFileName, "(stdout)" );
}
if (ProcessId == -1) {
HANDLE Process;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
PROCESS_BASIC_INFORMATION BasicInfo;
RtlInitUnicodeString( &UnicodeString, L"\\WindowsSS" );
InitializeObjectAttributes( &ObjectAttributes,
&UnicodeString,
0,
NULL,
NULL
);
Status = NtOpenProcess( &Process,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
NULL
);
if (NT_SUCCESS(Status)) {
Status = NtQueryInformationProcess( Process,
ProcessBasicInformation,
(PVOID)&BasicInfo,
sizeof(BasicInfo),
NULL
);
}
NtClose( Process );
if (!NT_SUCCESS(Status)) {
printf( "Unable to access Win32 server process - %08x", Status );
exit( 1 );
}
ProcessId = BasicInfo.UniqueProcessId;
}
fprintf( stderr, "DH: Writing dump output to %s", OutputFileName );
if (OutputFile == NULL) {
OutputFile = CreateFile( OutputFileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
0,
NULL
);
if ( OutputFile == INVALID_HANDLE_VALUE ) {
fprintf( stderr, " - unable to open, error == %u\n", GetLastError() );
return 1;
}
}
fprintf( stderr, "\n" );
if (fDumpKernelModeInformation) {
p = RtlQuerySystemDebugInformation( RTL_QUERY_PROCESS_MODULES |
RTL_QUERY_PROCESS_BACKTRACES |
RTL_QUERY_PROCESS_HEAP_SUMMARY |
RTL_QUERY_PROCESS_HEAP_TAGS |
RTL_QUERY_PROCESS_HEAP_ENTRIES |
RTL_QUERY_PROCESS_LOCKS
);
if (p == NULL) {
fprintf( stderr, "DH: Unable to query kernel mode information.\n" );
exit( 1 );
}
Status = STATUS_SUCCESS;
}
else {
p = RtlCreateQueryDebugBuffer( 0, FALSE );
Status = RtlQueryProcessDebugInformation( (HANDLE)ProcessId,
RTL_QUERY_PROCESS_MODULES |
RTL_QUERY_PROCESS_BACKTRACES |
RTL_QUERY_PROCESS_HEAP_SUMMARY |
RTL_QUERY_PROCESS_HEAP_TAGS |
RTL_QUERY_PROCESS_HEAP_ENTRIES |
RTL_QUERY_PROCESS_LOCKS,
p
);
if (NT_SUCCESS( Status )) {
if ((fDumpBackTraces || fDumpHeapHogs) && p->BackTraces == NULL) {
fprintf( stderr, "DH: Unable to query stack back trace information\n" );
fprintf( stderr, " Be sure target process was launched with the\n" );
fprintf( stderr, " 'Create user mode stack trace DB' enabled\n" );
fprintf( stderr, " Use the GFLAGS application to do this.\n" );
}
if (fDumpHeapTags) {
HeapInfo = &p->Heaps->Heaps[ 0 ];
for (HeapNumber = 0; HeapNumber < p->Heaps->NumberOfHeaps; HeapNumber++) {
if (HeapInfo->Tags != NULL && HeapInfo->NumberOfTags != 0) {
break;
}
}
if (HeapNumber == p->Heaps->NumberOfHeaps) {
fprintf( stderr, "DH: Unable to query heap tag information\n" );
fprintf( stderr, " Be sure target process was launched with the\n" );
fprintf( stderr, " 'Enable heap tagging' option enabled.\n" );
fprintf( stderr, " Use the GFLAGS application to do this.\n" );
}
}
}
}
if (NT_SUCCESS( Status )) {
if (!fIgnoreBackTraces &&
p->Modules != NULL &&
LoadSymbolsForModules( p->Modules ) &&
p->BackTraces != NULL
) {
ComputeSymbolicBackTraces( p->BackTraces );
}
if (fDumpModules) {
DumpModules( p->Modules );
}
if (!fIgnoreBackTraces && fDumpBackTraces) {
DumpBackTraces();
}
DumpHeaps( p->Heaps, fDumpHeapSummaries, fDumpHeapHogs, fDumpHeapTags, fDumpHeapEntries );
if (fDumpLocks) {
DumpLocks( p->Locks );
}
if (fDumpSystemObjects) {
DumpObjects();
DumpHandles();
}
if (fDumpSystemProcesses) {
DumpSystemProcesses();
}
}
RtlDestroyQueryDebugBuffer( p );
return 0;
}
PRTL_PROCESS_MODULES Modules;
PRTL_PROCESS_BACKTRACES BackTraces;
PUCHAR SymbolicInfoBase;
PUCHAR SymbolicInfoCurrent;
PUCHAR SymbolicInfoCommitNext;
typedef struct _PROCESS_INFO {
LIST_ENTRY Entry;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo[ 1 ];
} PROCESS_INFO, *PPROCESS_INFO;
LIST_ENTRY ProcessListHead;
PSYSTEM_OBJECTTYPE_INFORMATION ObjectInformation;
PSYSTEM_HANDLE_INFORMATION HandleInformation;
PSYSTEM_PROCESS_INFORMATION ProcessInformation;
#define MAX_TYPE_NAMES 128
PUNICODE_STRING *TypeNames;
UNICODE_STRING UnknownTypeIndex;
BOOL
LoadSymbolsFilter(
HANDLE UniqueProcess,
LPSTR ImageFilePath,
DWORD ImageBase,
DWORD ImageSize,
LOAD_SYMBOLS_FILTER_REASON Reason
)
{
switch( Reason ) {
case LoadSymbolsPathNotFound:
fprintf( stderr,
"DH: Unable to fimd symbols for %s\n",
ImageFilePath
);
break;
case LoadSymbolsDeferredLoad:
if (fVerbose) {
fprintf( stderr,
"DH: Remembering %s based at [%08x..%08x) in CID: %x\n",
ImageFilePath,
ImageBase,
ImageBase + ImageSize,
UniqueProcess
);
}
break;
case LoadSymbolsLoad:
fprintf( stderr,
"DH: Loading symbols for %s based at %08x in CID: %x\n",
ImageFilePath,
ImageBase,
UniqueProcess
);
break;
case LoadSymbolsUnload:
if (fVerbose) {
fprintf( stderr,
"DH: Unloading symbols for %s based at %08x in CID: %x\n",
ImageFilePath,
ImageBase,
UniqueProcess
);
}
break;
case LoadSymbolsUnableToLoad:
fprintf( stderr,
"DH: Unable to load symbols for %s\n",
ImageFilePath
);
break;
}
fflush( stderr );
return TRUE;
}
BOOLEAN
LoadSymbolsForModules(
PRTL_PROCESS_MODULES Modules1
)
{
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
LPSTR ImageFilePath;
ULONG ModuleNumber;
Modules = Modules1;
if (!InitializeImageDebugInformation( LoadSymbolsFilter, NULL, FALSE, fDumpKernelModeInformation )) {
return FALSE;
}
ModuleInfo = &Modules->Modules[ 0 ];
for (ModuleNumber=0; ModuleNumber<Modules->NumberOfModules; ModuleNumber++) {
if (ModuleInfo->MappedBase == NULL) {
if (ImageFilePath = strchr( ModuleInfo->FullPathName, ':')) {
ImageFilePath -= 1;
}
else {
ImageFilePath = ModuleInfo->FullPathName;
}
AddImageDebugInformation( (HANDLE)ProcessId,
ImageFilePath,
(DWORD)ModuleInfo->ImageBase,
ModuleInfo->ImageSize
);
}
ModuleInfo += 1;
}
return TRUE;
}
static char DllNameBuffer[ MAX_PATH ];
PCHAR
FindDllHandleName(
PVOID DllHandle
)
{
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
LPSTR DllName;
ULONG ModuleNumber;
ModuleInfo = &Modules->Modules[ 0 ];
for (ModuleNumber=0; ModuleNumber<Modules->NumberOfModules; ModuleNumber++) {
if (ModuleInfo->ImageBase == DllHandle) {
strcpy( DllNameBuffer, &ModuleInfo->FullPathName[ ModuleInfo->OffsetToFileName ] );
if ((DllName = strchr( DllNameBuffer, '.' )) != NULL) {
*DllName = '\0';
}
return DllNameBuffer;
}
ModuleInfo += 1;
}
return "UNKNOWN";
}
PUCHAR
SaveSymbolicBackTrace(
IN ULONG Depth,
IN PVOID BackTrace[]
)
{
NTSTATUS Status;
ULONG i, FileNameLength, SymbolOffset;
PCHAR s, SymbolicBackTrace;
if (Depth == 0) {
return NULL;
}
if (SymbolicInfoBase == NULL) {
SymbolicInfoBase = (PUCHAR)VirtualAlloc( NULL,
4096 * 4096,
MEM_RESERVE,
PAGE_READWRITE
);
if (SymbolicInfoBase == NULL) {
return NULL;
}
SymbolicInfoCurrent = SymbolicInfoBase;
SymbolicInfoCommitNext = SymbolicInfoBase;
}
i = 4096;
if ((SymbolicInfoCurrent + i - 1) > SymbolicInfoCommitNext) {
if (!VirtualAlloc( SymbolicInfoCommitNext,
i,
MEM_COMMIT,
PAGE_READWRITE
)
) {
fprintf( stderr, "DH: Exceeded 16MB of space for symbolic stack back traces.\n" );
return NULL;
}
SymbolicInfoCommitNext += i;
}
s = SymbolicInfoCurrent;
SymbolicBackTrace = s;
for (i=0; i<Depth; i++) {
if (BackTrace[ i ] == 0) {
break;
}
s += GetSymbolicNameForAddress( (HANDLE)ProcessId, (ULONG)BackTrace[ i ], s, MAX_PATH );
*s++ = '\0';
}
*s++ = '\0';
SymbolicInfoCurrent = s;
return SymbolicBackTrace;
}
BOOLEAN
ComputeSymbolicBackTraces(
PRTL_PROCESS_BACKTRACES BackTraces1
)
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
ULONG BackTraceIndex, NumberOfBackTraces;
BackTraces = BackTraces1;
NumberOfBackTraces = BackTraces->NumberOfBackTraces;
BackTraceInfo = &BackTraces->BackTraces[ 0 ];
BackTraceIndex = 0;
while (NumberOfBackTraces--) {
printf( "Getting symbols for Stack Back Trace %05u\r", BackTraceIndex++ );
BackTraceInfo->SymbolicBackTrace = SaveSymbolicBackTrace( BackTraceInfo->Depth,
&BackTraceInfo->BackTrace[ 0 ]
);
BackTraceInfo += 1;
}
return TRUE;
}
PRTL_PROCESS_BACKTRACE_INFORMATION
FindBackTrace(
IN ULONG BackTraceIndex
)
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
if (!BackTraceIndex ||
BackTraces == NULL ||
BackTraceIndex >= BackTraces->NumberOfBackTraces
) {
return( NULL );
}
return &BackTraces->BackTraces[ BackTraceIndex-1 ];
}
VOID
FormatHeapHeader(
PRTL_HEAP_INFORMATION HeapInfo,
PCHAR Title
)
{
CHAR TempBuffer[ 64 ];
PCHAR s;
if (HeapInfo->BaseAddress == (PVOID)SystemPagedPoolInformation) {
s = "Paged Pool";
}
else
if (HeapInfo->BaseAddress == (PVOID)SystemNonPagedPoolInformation) {
s = "NonPaged Pool";
}
else {
sprintf( TempBuffer, "Heap %08x", HeapInfo->BaseAddress );
s = TempBuffer;
}
sprintf( DumpLine, "\n\n*********** %s %s ********************\n\n", s, Title );
DumpOutputString();
}
VOID
DumpModules(
PRTL_PROCESS_MODULES Modules
)
{
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
ULONG ModuleNumber;
if (fVerbose) {
fprintf( stderr, "DH: Dumping module information.\n" );
}
ModuleInfo = &Modules->Modules[ 0 ];
sprintf( DumpLine, "\n\n*********** Module Information ********************\n\n" );
DumpOutputString();
sprintf( DumpLine, "Number of loaded modules: %u\n", Modules->NumberOfModules );
DumpOutputString();
ModuleNumber = 0;
while (ModuleNumber++ < Modules->NumberOfModules) {
sprintf( DumpLine, "Module%02u (%02u,%02u,%02u): [%08x .. %08x] %s\n",
ModuleNumber,
(ULONG)ModuleInfo->LoadOrderIndex,
(ULONG)ModuleInfo->InitOrderIndex,
(ULONG)ModuleInfo->LoadCount,
ModuleInfo->ImageBase,
(ULONG)ModuleInfo->ImageBase + ModuleInfo->ImageSize - 1,
ModuleInfo->FullPathName
);
DumpOutputString();
ModuleInfo++;
}
return;
}
VOID
DumpBackTraces( VOID )
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
ULONG BackTraceIndex;
char *s;
if (BackTraces == NULL) {
return;
}
if (fVerbose) {
fprintf( stderr, "DH: Dumping back trace information.\n" );
}
sprintf( DumpLine, "\n\n*********** BackTrace Information ********************\n\n" );
DumpOutputString();
sprintf( DumpLine, "Number of back traces: %u Looked Up Count: %u\n",
BackTraces->NumberOfBackTraces - 1,
BackTraces->NumberOfBackTraceLookups
);
DumpOutputString();
sprintf( DumpLine, "Reserved Memory: %08x Committed Memory: %08x\n",
BackTraces->ReservedMemory,
BackTraces->CommittedMemory
);
DumpOutputString();
BackTraceInfo = BackTraces->BackTraces;
for (BackTraceIndex=0; BackTraceIndex<BackTraces->NumberOfBackTraces; BackTraceIndex++) {
sprintf( DumpLine, "BackTrace%05lu\n", BackTraceInfo->Index );
DumpOutputString();
if (BackTraceInfo->SymbolicBackTrace == NULL) {
BackTraceInfo->SymbolicBackTrace = SaveSymbolicBackTrace( BackTraceInfo->Depth,
&BackTraceInfo->BackTrace[ 0 ]
);
}
if (s = BackTraceInfo->SymbolicBackTrace) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
BackTraceInfo += 1;
}
}
VOID
DumpHeapSummary(
PRTL_HEAP_INFORMATION HeapInfo
)
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
PUCHAR s;
sprintf( DumpLine, " Flags: %08x\n", HeapInfo->Flags );
DumpOutputString();
sprintf( DumpLine, " Number Of Entries: %u\n", HeapInfo->NumberOfEntries );
DumpOutputString();
sprintf( DumpLine, " Number Of Tags: %u\n", HeapInfo->NumberOfTags );
DumpOutputString();
sprintf( DumpLine, " Bytes Allocated: %08x\n", HeapInfo->BytesAllocated );
DumpOutputString();
sprintf( DumpLine, " Bytes Committed: %08x\n", HeapInfo->BytesCommitted );
DumpOutputString();
sprintf( DumpLine, " Total FreeSpace: %08x\n", HeapInfo->BytesCommitted -
HeapInfo->BytesAllocated );
DumpOutputString();
sprintf( DumpLine, " Entry Overhead: %u\n", HeapInfo->EntryOverhead );
DumpOutputString();
sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", HeapInfo->CreatorBackTraceIndex );
DumpOutputString();
BackTraceInfo = FindBackTrace( HeapInfo->CreatorBackTraceIndex );
if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
return;
}
int
_CRTAPI1
CmpTagsRoutine(
const void *Element1,
const void *Element2
)
{
return( (*(PRTL_HEAP_TAG *)Element2)->BytesAllocated -
(*(PRTL_HEAP_TAG *)Element1)->BytesAllocated
);
}
PRTL_HEAP_TAG
FindTagEntry(
PRTL_HEAP_INFORMATION HeapInfo,
ULONG TagIndex
)
{
if (TagIndex == 0 || (TagIndex & ~HEAP_PSEUDO_TAG_FLAG) >= HeapInfo->NumberOfTags) {
return NULL;
}
else {
if (TagIndex & HEAP_PSEUDO_TAG_FLAG) {
return HeapInfo->Tags + (TagIndex & ~HEAP_PSEUDO_TAG_FLAG);
}
else {
return HeapInfo->Tags + HeapInfo->NumberOfPseudoTags + TagIndex;
}
}
}
VOID
DumpHeapTags(
PRTL_HEAP_INFORMATION HeapInfo
)
{
PRTL_HEAP_TAG *TagEntries, TagEntry;
ULONG TagIndex;
PUCHAR s;
UCHAR HeapName[ 64 ];
if (HeapInfo->Tags == NULL || HeapInfo->NumberOfTags == 0) {
return;
}
TagEntries = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
HeapInfo->NumberOfTags * sizeof( PRTL_HEAP_TAG )
);
if (TagEntries == NULL) {
return;
}
for (TagIndex=1; TagIndex<HeapInfo->NumberOfTags; TagIndex++) {
TagEntries[ TagIndex-1 ] = &HeapInfo->Tags[ TagIndex ];
}
qsort( (void *)TagEntries,
HeapInfo->NumberOfTags - 1,
sizeof( PRTL_HEAP_TAG ),
CmpTagsRoutine
);
TagEntry = &HeapInfo->Tags[ HeapInfo->NumberOfPseudoTags ];
if (HeapInfo->NumberOfTags > HeapInfo->NumberOfPseudoTags &&
TagEntry->TagName[ 0 ] != UNICODE_NULL
) {
sprintf( HeapName, "Tags for %ws heap", TagEntry->TagName );
}
else {
sprintf( HeapName, "Tags" );
}
FormatHeapHeader( HeapInfo, HeapName );
sprintf( DumpLine, " Allocs Frees Diff Bytes Tag\n" );
DumpOutputString();
for (TagIndex=1; TagIndex<(HeapInfo->NumberOfTags-1); TagIndex++) {
TagEntry = TagEntries[ TagIndex ];
if (TagEntry->BytesAllocated != 0) {
sprintf( DumpLine, " %08x %08x %08x %08x %ws\n",
TagEntry->NumberOfAllocations,
TagEntry->NumberOfFrees,
TagEntry->NumberOfAllocations - TagEntry->NumberOfFrees,
TagEntry->BytesAllocated,
TagEntry->TagName
);
DumpOutputString();
}
}
RtlFreeHeap( RtlProcessHeap(), 0, TagEntries );
return;
}
typedef struct _HEAP_CALLER {
ULONG TotalAllocated;
USHORT NumberOfAllocations;
USHORT CallerBackTraceIndex;
PRTL_HEAP_TAG TagEntry;
} HEAP_CALLER, *PHEAP_CALLER;
int
_CRTAPI1
CmpCallerRoutine(
const void *Element1,
const void *Element2
)
{
return( ((PHEAP_CALLER)Element2)->TotalAllocated -
((PHEAP_CALLER)Element1)->TotalAllocated
);
}
VOID
DumpHeapHogs(
PRTL_HEAP_INFORMATION HeapInfo
)
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
PUCHAR s;
ULONG BackTraceNumber, HeapEntryNumber;
USHORT TagIndex;
PRTL_HEAP_ENTRY p;
PHEAP_CALLER HogList;
if (BackTraces == NULL) {
return;
}
HogList = (PHEAP_CALLER)VirtualAlloc( NULL,
BackTraces->NumberOfBackTraces *
sizeof( HEAP_CALLER ),
MEM_COMMIT,
PAGE_READWRITE
);
if (HogList == NULL) {
return;
}
p = HeapInfo->Entries;
if (p == NULL) {
return;
}
for (HeapEntryNumber=0; HeapEntryNumber<HeapInfo->NumberOfEntries; HeapEntryNumber++) {
if (p->Flags & RTL_HEAP_BUSY) {
if (p->AllocatorBackTraceIndex >= BackTraces->NumberOfBackTraces) {
p->AllocatorBackTraceIndex = 0;
}
HogList[ p->AllocatorBackTraceIndex ].NumberOfAllocations++;
HogList[ p->AllocatorBackTraceIndex ].TotalAllocated += p->Size;
if (p->u.s1.Tag != 0) {
HogList[ p->AllocatorBackTraceIndex ].TagEntry = FindTagEntry( HeapInfo, p->u.s1.Tag );
}
else
if (HeapInfo->NumberOfPseudoTags != 0) {
TagIndex = HEAP_PSEUDO_TAG_FLAG;
if (p->Size < (HeapInfo->NumberOfPseudoTags * HeapInfo->PseudoTagGranularity)) {
TagIndex |= (p->Size / HeapInfo->PseudoTagGranularity);
}
HogList[ p->AllocatorBackTraceIndex ].TagEntry = FindTagEntry( HeapInfo, TagIndex );
}
}
p++;
}
for (BackTraceNumber = 1;
BackTraceNumber < BackTraces->NumberOfBackTraces;
BackTraceNumber++
) {
HogList[ BackTraceNumber ].CallerBackTraceIndex = (USHORT)BackTraceNumber;
}
qsort( (void *)HogList,
BackTraces->NumberOfBackTraces,
sizeof( HEAP_CALLER ),
CmpCallerRoutine
);
FormatHeapHeader( HeapInfo, "Hogs" );
for (BackTraceNumber=0;
BackTraceNumber<BackTraces->NumberOfBackTraces;
BackTraceNumber++
) {
if (HogList[ BackTraceNumber ].TotalAllocated != 0) {
BackTraceInfo = FindBackTrace( HogList[ BackTraceNumber ].CallerBackTraceIndex );
sprintf( DumpLine, "%08x bytes",
HogList[ BackTraceNumber ].TotalAllocated
);
DumpOutputString();
if (HogList[ BackTraceNumber ].NumberOfAllocations > 1) {
sprintf( DumpLine, " in %04lx allocations (@ %04lx)",
HogList[ BackTraceNumber ].NumberOfAllocations,
HogList[ BackTraceNumber ].TotalAllocated /
HogList[ BackTraceNumber ].NumberOfAllocations
);
DumpOutputString();
}
sprintf( DumpLine, " by: BackTrace%05lu",
BackTraceInfo ? BackTraceInfo->Index : 99999
);
DumpOutputString();
if (HogList[ BackTraceNumber ].TagEntry != NULL) {
sprintf( DumpLine, " (%ws)\n", HogList[ BackTraceNumber ].TagEntry->TagName );
}
else {
sprintf( DumpLine, "\n" );
}
DumpOutputString();
if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
sprintf( DumpLine, " \n" );
DumpOutputString();
}
}
VirtualFree( HogList, 0, MEM_RELEASE );
}
VOID
DumpHeapEntries(
PRTL_HEAP_INFORMATION HeapInfo
)
{
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
PUCHAR s;
PRTL_HEAP_ENTRY p;
PRTL_HEAP_TAG TagEntry;
PCHAR HeapEntryAddress;
ULONG HeapEntrySize, HeapEntryNumber;
p = HeapInfo->Entries;
if (p == NULL || HeapInfo->NumberOfEntries == 0) {
return;
}
FormatHeapHeader( HeapInfo, "Entries" );
HeapEntryAddress = NULL;
for (HeapEntryNumber=0; HeapEntryNumber<HeapInfo->NumberOfEntries; HeapEntryNumber++) {
if (p->Flags != 0xFF && p->Flags & RTL_HEAP_SEGMENT) {
HeapEntryAddress = (PCHAR)p->u.s2.FirstBlock;
sprintf( DumpLine, "\n[%lx : %lx]\n",
(ULONG)HeapEntryAddress & ~(4096-1),
p->u.s2.CommittedSize
);
DumpOutputString();
}
else {
HeapEntrySize = p->Size;
if (p->Flags == RTL_HEAP_UNCOMMITTED_RANGE) {
sprintf( DumpLine, "%08lx: %08lx - UNCOMMITTED\n",
HeapEntryAddress,
HeapEntrySize
);
DumpOutputString();
}
else
if (p->Flags & RTL_HEAP_BUSY) {
s = DumpLine;
s += sprintf( s, "%08lx: %08lx - BUSY [%02x]",
HeapEntryAddress,
HeapEntrySize,
p->Flags
);
TagEntry = FindTagEntry( HeapInfo, p->u.s1.Tag );
if (TagEntry != NULL) {
s += sprintf( s, "(%ws)", TagEntry->TagName );
}
if (BackTraces != NULL) {
s += sprintf( s, " (BackTrace%05lu)",
p->AllocatorBackTraceIndex
);
}
if (p->Flags & RTL_HEAP_SETTABLE_VALUE &&
p->Flags & RTL_HEAP_SETTABLE_FLAG1
) {
s += sprintf( s, " (Handle: %x)", p->u.s1.Settable );
}
if (p->Flags & RTL_HEAP_SETTABLE_FLAG2) {
s += sprintf( s, " (DDESHARE)" );
}
if (p->Flags & RTL_HEAP_PROTECTED_ENTRY) {
s += sprintf( s, " (Protected)" );
}
sprintf( s, "\n" );
DumpOutputString();
}
else {
sprintf( DumpLine, "%08lx: %08lx - FREE\n",
HeapEntryAddress,
HeapEntrySize
);
DumpOutputString();
}
sprintf( DumpLine, "\n" );
DumpOutputString();
HeapEntryAddress += HeapEntrySize;
}
p++;
}
return;
}
VOID
DumpHeaps(
PRTL_PROCESS_HEAPS Heaps,
BOOLEAN fDumpSummary,
BOOLEAN fDumpHogs,
BOOLEAN fDumpTags,
BOOLEAN fDumpEntries
)
{
ULONG HeapNumber;
PRTL_HEAP_INFORMATION HeapInfo;
if (fVerbose) {
fprintf( stderr, "DH: Dumping heap information.\n" );
}
HeapInfo = &Heaps->Heaps[ 0 ];
for (HeapNumber = 0; HeapNumber < Heaps->NumberOfHeaps; HeapNumber++) {
FormatHeapHeader( HeapInfo, "Information" );
if (fDumpSummary) {
DumpHeapSummary( HeapInfo );
}
if (fDumpTags) {
DumpHeapTags( HeapInfo );
}
if (fDumpHogs) {
DumpHeapHogs( HeapInfo );
}
if (fDumpEntries) {
DumpHeapEntries( HeapInfo );
}
HeapInfo += 1;
}
return;
}
VOID
DumpLocks(
PRTL_PROCESS_LOCKS Locks
)
{
PRTL_PROCESS_LOCK_INFORMATION LockInfo;
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
ULONG LockNumber;
PUCHAR s;
if (fVerbose) {
fprintf( stderr, "DH: Dumping lock information.\n" );
}
sprintf( DumpLine, "\n\n*********** Lock Information ********************\n\n" );
DumpOutputString();
if (Locks == NULL) {
return;
}
sprintf( DumpLine, "NumberOfLocks == %u\n", Locks->NumberOfLocks );
DumpOutputString();
LockInfo = &Locks->Locks[ 0 ];
LockNumber = 0;
while (LockNumber++ < Locks->NumberOfLocks) {
sprintf( DumpLine, "Lock%u at %08x (%s)\n",
LockNumber,
LockInfo->Address,
LockInfo->Type == RTL_CRITSECT_TYPE ? "CriticalSection" : "Resource"
);
DumpOutputString();
sprintf( DumpLine, " Contention: %u\n", LockInfo->ContentionCount );
DumpOutputString();
sprintf( DumpLine, " Usage: %u\n", LockInfo->EntryCount );
DumpOutputString();
if (LockInfo->CreatorBackTraceIndex != 0) {
sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", LockInfo->CreatorBackTraceIndex );
DumpOutputString();
BackTraceInfo = FindBackTrace( LockInfo->CreatorBackTraceIndex );
if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
}
if (LockInfo->OwningThread) {
sprintf( DumpLine, " Owner: (ThreadID == %x)\n", LockInfo->OwningThread );
DumpOutputString();
}
sprintf( DumpLine, "\n" );
DumpOutputString();
LockInfo++;
}
}
#define RTL_NEW( p ) RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *p ) )
BOOLEAN
LoadSystemModules(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemBackTraces(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemPools(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemTags(
PRTL_HEAP_INFORMATION PagedPoolInfo,
PRTL_HEAP_INFORMATION NonPagedPoolInfo
);
BOOLEAN
LoadSystemPool(
PRTL_HEAP_INFORMATION HeapInfo,
SYSTEM_INFORMATION_CLASS SystemInformationClass
);
BOOLEAN
LoadSystemLocks(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemObjects(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemHandles(
PRTL_DEBUG_INFORMATION Buffer
);
BOOLEAN
LoadSystemProcesses(
PRTL_DEBUG_INFORMATION Buffer
);
PSYSTEM_PROCESS_INFORMATION
FindProcessInfoForCid(
IN HANDLE UniqueProcessId
);
PRTL_DEBUG_INFORMATION
RtlQuerySystemDebugInformation(
ULONG Flags
)
{
PRTL_DEBUG_INFORMATION Buffer;
Buffer = RTL_NEW( Buffer );
if (Buffer == NULL) {
return NULL;
}
if (!LoadSystemModules( Buffer )) {
fprintf( stderr, "DH: Unable to query system module list.\n" );
}
if (!LoadSystemBackTraces( Buffer )) {
fprintf( stderr, "DH: Unable to query system back trace information.\n" );
fprintf( stderr, " Be sure the system was booted with the\n" );
fprintf( stderr, " 'Create kernel mode stack trace DB' enabled\n" );
fprintf( stderr, " Use the GFLAGS application to do this.\n" );
}
if (!LoadSystemPools( Buffer )) {
fprintf( stderr, "DH: Unable to query system pool information.\n" );
}
if (!LoadSystemLocks( Buffer )) {
fprintf( stderr, "DH: Unable to query system lock information.\n" );
}
if (!LoadSystemObjects( Buffer )) {
fprintf( stderr, "DH: Unable to query system object information.\n" );
}
if (!LoadSystemHandles( Buffer )) {
fprintf( stderr, "DH: Unable to query system handle information.\n" );
}
if (!LoadSystemProcesses( Buffer )) {
fprintf( stderr, "DH: Unable to query system process information.\n" );
}
return Buffer;
}
PVOID
BufferAlloc(
IN OUT PULONG Length
);
PVOID
BufferAlloc(
IN OUT PULONG Length
)
{
PVOID Buffer;
MEMORY_BASIC_INFORMATION MemoryInformation;
Buffer = VirtualAlloc( NULL,
*Length,
MEM_COMMIT,
PAGE_READWRITE
);
if (Buffer != NULL &&
VirtualQuery( Buffer, &MemoryInformation, sizeof( MemoryInformation ) )
) {
*Length = MemoryInformation.RegionSize;
}
return Buffer;
}
BOOLEAN
LoadSystemModules(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
PVOID BufferToFree;
RTL_PROCESS_MODULES ModulesBuffer;
PRTL_PROCESS_MODULES Modules;
ULONG RequiredLength;
Modules = &ModulesBuffer;
RequiredLength = sizeof( ModulesBuffer );
BufferToFree = NULL;
while (TRUE) {
Status = NtQuerySystemInformation( SystemModuleInformation,
Modules,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (Modules != &ModulesBuffer) {
break;
}
Modules = BufferAlloc( &RequiredLength );
if (Modules == NULL) {
break;
}
BufferToFree = Modules;
}
else
if (NT_SUCCESS( Status )) {
Buffer->Modules = Modules;
return TRUE;
}
else {
break;
}
}
if (Modules != &ModulesBuffer) {
VirtualFree( Modules, 0, MEM_RELEASE );
}
return FALSE;
}
BOOLEAN
LoadSystemBackTraces(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
RTL_PROCESS_BACKTRACES BackTracesBuffer;
ULONG RequiredLength;
BackTraces = &BackTracesBuffer;
RequiredLength = sizeof( BackTracesBuffer );
while (TRUE) {
Status = NtQuerySystemInformation( SystemStackTraceInformation,
BackTraces,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (BackTraces != &BackTracesBuffer) {
break;
}
RequiredLength += 4096; // slop, since we may trigger more allocs.
BackTraces = BufferAlloc( &RequiredLength );
if (BackTraces == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
break;
}
else {
Buffer->BackTraces = BackTraces;
return TRUE;
}
}
if (BackTraces != &BackTracesBuffer) {
VirtualFree( BackTraces, 0, MEM_RELEASE );
}
return FALSE;
}
BOOLEAN
LoadSystemPools(
PRTL_DEBUG_INFORMATION Buffer
)
{
PRTL_PROCESS_HEAPS Heaps;
Heaps = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
FIELD_OFFSET( RTL_PROCESS_HEAPS, Heaps ) +
2 * sizeof( RTL_HEAP_INFORMATION )
);
if (Heaps == NULL) {
return FALSE;
}
Buffer->Heaps = Heaps;
if (LoadSystemTags( &Heaps->Heaps[ 0 ], &Heaps->Heaps[ 1 ] )) {
if (LoadSystemPool( &Heaps->Heaps[ 0 ], SystemPagedPoolInformation )) {
Heaps->NumberOfHeaps = 1;
if (LoadSystemPool( &Heaps->Heaps[ 1 ], SystemNonPagedPoolInformation )) {
Heaps->NumberOfHeaps = 2;
return TRUE;
}
}
}
return FALSE;
}
BOOLEAN
LoadSystemTags(
PRTL_HEAP_INFORMATION PagedPoolInfo,
PRTL_HEAP_INFORMATION NonPagedPoolInfo
)
{
NTSTATUS Status;
ULONG RequiredLength;
SYSTEM_POOLTAG_INFORMATION TagsBuffer;
PSYSTEM_POOLTAG_INFORMATION Tags;
PSYSTEM_POOLTAG TagInfo;
PRTL_HEAP_TAG pPagedPoolTag, pNonPagedPoolTag;
ULONG n, TagIndex;
PagedPoolInfo->NumberOfTags = 0;
PagedPoolInfo->Tags = NULL;
NonPagedPoolInfo->NumberOfTags = 0;
NonPagedPoolInfo->Tags = NULL;
Tags = &TagsBuffer;
RequiredLength = sizeof( TagsBuffer );
while (TRUE) {
Status = NtQuerySystemInformation( SystemPoolTagInformation,
Tags,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (Tags != &TagsBuffer) {
break;
}
RequiredLength += 4096; // slop, since we may trigger more allocs.
Tags = BufferAlloc( &RequiredLength );
if (Tags == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
break;
}
else {
PagedPoolInfo->NumberOfTags = Tags->Count + 1;
NonPagedPoolInfo->NumberOfTags = Tags->Count + 1;
n = (Tags->Count + 1) * sizeof( RTL_HEAP_TAG );
PagedPoolInfo->Tags = RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, n );
NonPagedPoolInfo->Tags = RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, n );
TagInfo = &Tags->TagInfo[ 0 ];
pPagedPoolTag = PagedPoolInfo->Tags + 1;
pNonPagedPoolTag = NonPagedPoolInfo->Tags + 1;
for (TagIndex=1; TagIndex<=Tags->Count; TagIndex++) {
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
pPagedPoolTag->TagIndex = (USHORT)TagIndex;
pPagedPoolTag->NumberOfAllocations = TagInfo->PagedAllocs;
pPagedPoolTag->NumberOfFrees = TagInfo->PagedFrees;
pPagedPoolTag->BytesAllocated = TagInfo->PagedUsed;
UnicodeString.Buffer = pPagedPoolTag->TagName;
UnicodeString.MaximumLength = sizeof( pPagedPoolTag->TagName );
AnsiString.Buffer = TagInfo->Tag;
AnsiString.Length = sizeof( TagInfo->Tag );
AnsiString.MaximumLength = AnsiString.Length;
RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
pNonPagedPoolTag->TagIndex = (USHORT)TagIndex;
pNonPagedPoolTag->NumberOfAllocations = TagInfo->NonPagedAllocs;
pNonPagedPoolTag->NumberOfFrees = TagInfo->NonPagedFrees;
pNonPagedPoolTag->BytesAllocated = TagInfo->NonPagedUsed;
wcscpy( pNonPagedPoolTag->TagName, pPagedPoolTag->TagName );
pPagedPoolTag += 1;
pNonPagedPoolTag += 1;
TagInfo += 1;
}
break;
}
}
if (Tags != &TagsBuffer) {
VirtualFree( Tags, 0, MEM_RELEASE );
}
return TRUE;
}
USHORT
FindPoolTagIndex(
PRTL_HEAP_TAG Tags,
ULONG NumberOfTags,
PCHAR Tag
)
{
ULONG i;
UCHAR AnsiTagName[ 5 ];
WCHAR UnicodeTagName[ 5 ];
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
strncpy( AnsiTagName, Tag, 4 );
UnicodeString.Buffer = UnicodeTagName;
UnicodeString.MaximumLength = sizeof( UnicodeTagName );
AnsiString.Buffer = AnsiTagName;
AnsiString.Length = strlen( AnsiTagName );
AnsiString.MaximumLength = AnsiString.Length;
RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
Tags += 1;
for (i=1; i<NumberOfTags; i++) {
if (!_wcsicmp( UnicodeTagName, Tags->TagName )) {
return (USHORT)i;
}
Tags += 1;
}
return 0;
}
BOOLEAN
LoadSystemPool(
PRTL_HEAP_INFORMATION HeapInfo,
SYSTEM_INFORMATION_CLASS SystemInformationClass
)
{
NTSTATUS Status;
ULONG RequiredLength;
SYSTEM_POOL_INFORMATION PoolInfoBuffer;
PSYSTEM_POOL_INFORMATION PoolInfo;
PSYSTEM_POOL_ENTRY PoolEntry;
PRTL_HEAP_ENTRY p;
ULONG n;
BOOLEAN Result;
HeapInfo->BaseAddress = (PVOID)SystemInformationClass;
PoolInfo = &PoolInfoBuffer;
RequiredLength = sizeof( PoolInfoBuffer );
Result = FALSE;
while (TRUE) {
Status = NtQuerySystemInformation( SystemInformationClass,
PoolInfo,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (PoolInfo != &PoolInfoBuffer) {
break;
}
RequiredLength += 4096; // slop, since we may trigger more allocs.
PoolInfo = BufferAlloc( &RequiredLength );
if (PoolInfo == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
break;
}
else {
n = PoolInfo->NumberOfEntries;
HeapInfo->NumberOfEntries = n + 1;
HeapInfo->EntryOverhead = PoolInfo->EntryOverhead;
HeapInfo->Entries = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
HeapInfo->NumberOfEntries * sizeof( RTL_HEAP_ENTRY )
);
p = HeapInfo->Entries;
p->Flags = RTL_HEAP_SEGMENT;
p->u.s2.CommittedSize = PoolInfo->TotalSize;
p->u.s2.FirstBlock = PoolInfo->FirstEntry;
p += 1;
PoolEntry = &PoolInfo->Entries[ 0 ];
while (n--) {
p->Size = PoolEntry->Size;
if (PoolEntry->TagUlong & PROTECTED_POOL) {
p->Flags |= RTL_HEAP_PROTECTED_ENTRY;
PoolEntry->TagUlong &= ~PROTECTED_POOL;
}
p->u.s1.Tag = FindPoolTagIndex( HeapInfo->Tags,
HeapInfo->NumberOfTags,
PoolEntry->Tag
);
HeapInfo->BytesCommitted += p->Size;
if (PoolEntry->Allocated) {
p->Flags |= RTL_HEAP_BUSY;
p->AllocatorBackTraceIndex = PoolEntry->AllocatorBackTraceIndex;
HeapInfo->BytesAllocated += p->Size;
}
p += 1;
PoolEntry += 1;
}
Result = TRUE;
break;
}
}
if (PoolInfo != &PoolInfoBuffer) {
VirtualFree( PoolInfo, 0, MEM_RELEASE );
}
return Result;
}
BOOLEAN
LoadSystemLocks(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
RTL_PROCESS_LOCKS LocksBuffer;
PRTL_PROCESS_LOCKS Locks;
ULONG RequiredLength;
Locks = &LocksBuffer;
RequiredLength = sizeof( LocksBuffer );
while (TRUE) {
Status = NtQuerySystemInformation( SystemLocksInformation,
Locks,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (Locks != &LocksBuffer) {
break;
}
Locks = BufferAlloc( &RequiredLength );
if (Locks == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
break;
}
else {
Buffer->Locks = Locks;
return TRUE;
}
}
if (Locks != &LocksBuffer) {
VirtualFree( Locks, 0, MEM_RELEASE );
}
return FALSE;
}
BOOLEAN
LoadSystemObjects(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
SYSTEM_OBJECTTYPE_INFORMATION ObjectInfoBuffer;
ULONG RequiredLength, i;
PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
ObjectInformation = &ObjectInfoBuffer;
RequiredLength = sizeof( *ObjectInformation );
while (TRUE) {
Status = NtQuerySystemInformation( SystemObjectInformation,
ObjectInformation,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (ObjectInformation != &ObjectInfoBuffer) {
return FALSE;
}
RequiredLength += 4096; // slop, since we may trigger more object creations.
ObjectInformation = BufferAlloc( &RequiredLength );
if (ObjectInformation == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
return FALSE;
}
else {
break;
}
}
TypeNames = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( PUNICODE_STRING ) * (MAX_TYPE_NAMES+1)
);
if (TypeNames == NULL) {
return FALSE;
}
TypeInfo = ObjectInformation;
while (TRUE) {
if (TypeInfo->TypeIndex < MAX_TYPE_NAMES) {
TypeNames[ TypeInfo->TypeIndex ] = &TypeInfo->TypeName;
}
if (TypeInfo->NextEntryOffset == 0) {
break;
}
TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
}
RtlInitUnicodeString( &UnknownTypeIndex, L"Unknown Type Index" );
for (i=0; i<=MAX_TYPE_NAMES; i++) {
if (TypeNames[ i ] == NULL) {
TypeNames[ i ] = &UnknownTypeIndex;
}
}
return TRUE;
}
BOOLEAN
LoadSystemHandles(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
SYSTEM_HANDLE_INFORMATION HandleInfoBuffer;
ULONG RequiredLength;
PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
PSYSTEM_OBJECT_INFORMATION ObjectInfo;
HandleInformation = &HandleInfoBuffer;
RequiredLength = sizeof( *HandleInformation );
while (TRUE) {
Status = NtQuerySystemInformation( SystemHandleInformation,
HandleInformation,
RequiredLength,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
if (HandleInformation != &HandleInfoBuffer) {
return FALSE;
}
RequiredLength += 4096; // slop, since we may trigger more handle creations.
HandleInformation = (PSYSTEM_HANDLE_INFORMATION)BufferAlloc( &RequiredLength );
if (HandleInformation == NULL) {
return FALSE;
}
}
else
if (!NT_SUCCESS( Status )) {
return FALSE;
}
else {
break;
}
}
TypeInfo = ObjectInformation;
while (TRUE) {
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)TypeInfo->TypeName.Buffer + TypeInfo->TypeName.MaximumLength);
while (TRUE) {
if (ObjectInfo->HandleCount != 0) {
PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntry;
ULONG HandleNumber;
HandleEntry = &HandleInformation->Handles[ 0 ];
HandleNumber = 0;
while (HandleNumber++ < HandleInformation->NumberOfHandles) {
if (!(HandleEntry->HandleAttributes & 0x80) &&
HandleEntry->Object == ObjectInfo->Object
) {
HandleEntry->Object = ObjectInfo;
HandleEntry->HandleAttributes |= 0x80;
}
HandleEntry++;
}
}
if (ObjectInfo->NextEntryOffset == 0) {
break;
}
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)ObjectInformation + ObjectInfo->NextEntryOffset);
}
if (TypeInfo->NextEntryOffset == 0) {
break;
}
TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
}
return TRUE;
}
BOOLEAN
LoadSystemProcesses(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
ULONG RequiredLength, i, TotalOffset;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo;
PPROCESS_INFO ProcessEntry;
UCHAR NameBuffer[ MAX_PATH ];
ANSI_STRING AnsiString;
RequiredLength = 64 * 1024;
ProcessInformation = BufferAlloc( &RequiredLength );
if (ProcessInformation == NULL) {
return FALSE;
}
Status = NtQuerySystemInformation( SystemProcessInformation,
ProcessInformation,
RequiredLength,
&RequiredLength
);
if (!NT_SUCCESS( Status )) {
return FALSE;
}
InitializeListHead( &ProcessListHead );
ProcessInfo = ProcessInformation;
TotalOffset = 0;
while (TRUE) {
if (ProcessInfo->ImageName.Buffer == NULL) {
sprintf( NameBuffer, "System Process (%04lx)", ProcessInfo->UniqueProcessId );
}
else {
sprintf( NameBuffer, "%wZ (%04lx)",
&ProcessInfo->ImageName,
ProcessInfo->UniqueProcessId
);
}
RtlInitAnsiString( &AnsiString, NameBuffer );
RtlAnsiStringToUnicodeString( &ProcessInfo->ImageName, &AnsiString, TRUE );
ProcessEntry = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *ProcessEntry ) +
(sizeof( ThreadInfo ) * ProcessInfo->NumberOfThreads)
);
if (ProcessEntry == NULL) {
return FALSE;
}
InitializeListHead( &ProcessEntry->Entry );
ProcessEntry->ProcessInfo = ProcessInfo;
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
for (i = 0; i < ProcessInfo->NumberOfThreads; i++) {
ProcessEntry->ThreadInfo[ i ] = ThreadInfo++;
}
InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
if (ProcessInfo->NextEntryOffset == 0) {
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
((PCHAR)ProcessInformation + TotalOffset);
}
return TRUE;
}
PSYSTEM_PROCESS_INFORMATION
FindProcessInfoForCid(
IN HANDLE UniqueProcessId
)
{
PLIST_ENTRY Next, Head;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PPROCESS_INFO ProcessEntry;
UCHAR NameBuffer[ 64 ];
ANSI_STRING AnsiString;
Head = &ProcessListHead;
Next = Head->Flink;
while (Next != Head) {
ProcessEntry = CONTAINING_RECORD( Next,
PROCESS_INFO,
Entry
);
ProcessInfo = ProcessEntry->ProcessInfo;
if (ProcessInfo->UniqueProcessId == UniqueProcessId) {
return ProcessInfo;
}
Next = Next->Flink;
}
ProcessEntry = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *ProcessEntry ) +
sizeof( *ProcessInfo )
);
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessEntry+1);
ProcessEntry->ProcessInfo = ProcessInfo;
sprintf( NameBuffer, "Unknown Process (%04lx)", UniqueProcessId );
RtlInitAnsiString( &AnsiString, NameBuffer );
RtlAnsiStringToUnicodeString( (PUNICODE_STRING)&ProcessInfo->ImageName, &AnsiString, TRUE );
ProcessInfo->UniqueProcessId = UniqueProcessId;
InitializeListHead( &ProcessEntry->Entry );
InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
return ProcessInfo;
}
VOID
DumpSystemThread(
PSYSTEM_THREAD_INFORMATION ThreadInfo
)
{
UCHAR Buffer[ MAX_PATH ];
Buffer[ 0 ] = '\0';
GetSymbolicNameForAddress( NULL, (ULONG)ThreadInfo->StartAddress, Buffer, sizeof( Buffer ) );
sprintf( DumpLine, " Thread Id: %x Start Address: %x (%s)\n",
ThreadInfo->ClientId.UniqueThread,
ThreadInfo->StartAddress,
Buffer
);
DumpOutputString();
return;
}
VOID
DumpSystemProcess(
PPROCESS_INFO ProcessEntry
)
{
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
ULONG ThreadNumber;
ProcessInfo = ProcessEntry->ProcessInfo;
sprintf( DumpLine, "\n\n*********** %x (%wZ) Information ********************\n\n",
ProcessInfo->UniqueProcessId,
&ProcessInfo->ImageName
);
DumpOutputString();
if (ProcessInfo->InheritedFromUniqueProcessId) {
sprintf( DumpLine, " Parent Process: %x (%wZ)\n",
ProcessInfo->InheritedFromUniqueProcessId,
&(FindProcessInfoForCid( ProcessInfo->InheritedFromUniqueProcessId )->ImageName)
);
DumpOutputString();
}
sprintf( DumpLine, " BasePriority: %u\n",
ProcessInfo->BasePriority
);
DumpOutputString();
sprintf( DumpLine, " VirtualSize: %08x\n",
ProcessInfo->VirtualSize
);
DumpOutputString();
sprintf( DumpLine, " PeakVirtualSize: %08x\n",
ProcessInfo->PeakVirtualSize
);
DumpOutputString();
sprintf( DumpLine, " WorkingSetSize: %08x\n",
ProcessInfo->WorkingSetSize
);
DumpOutputString();
sprintf( DumpLine, " PeakWorkingSetSize: %08x\n",
ProcessInfo->PeakWorkingSetSize
);
DumpOutputString();
sprintf( DumpLine, " PagefileUsage: %08x\n",
ProcessInfo->PagefileUsage
);
DumpOutputString();
sprintf( DumpLine, " PeakPagefileUsage: %08x\n",
ProcessInfo->PeakPagefileUsage
);
DumpOutputString();
sprintf( DumpLine, " PageFaultCount: %08x\n",
ProcessInfo->PageFaultCount
);
DumpOutputString();
sprintf( DumpLine, " PrivatePageCount: %08x\n",
ProcessInfo->PrivatePageCount
);
DumpOutputString();
sprintf( DumpLine, " Number of Threads: %u\n",
ProcessInfo->NumberOfThreads
);
DumpOutputString();
for (ThreadNumber=0; ThreadNumber<ProcessInfo->NumberOfThreads; ThreadNumber++) {
DumpSystemThread( ProcessEntry->ThreadInfo[ ThreadNumber ] );
}
return;
}
VOID
DumpSystemProcesses( VOID )
{
PLIST_ENTRY Next, Head;
PPROCESS_INFO ProcessEntry;
if (fVerbose) {
fprintf( stderr, "DH: Dumping object information.\n" );
}
sprintf( DumpLine, "\n\n*********** Process Information ********************\n\n" );
DumpOutputString();
Head = &ProcessListHead;
Next = Head->Flink;
while (Next != Head) {
ProcessEntry = CONTAINING_RECORD( Next,
PROCESS_INFO,
Entry
);
DumpSystemProcess( ProcessEntry );
Next = Next->Flink;
}
return;
}
VOID
DumpObjectNameForObject(
IN PVOID Object
)
{
return;
}
VOID
DumpObjects( VOID )
{
PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
PSYSTEM_OBJECT_INFORMATION ObjectInfo;
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
UNICODE_STRING ObjectName;
PUCHAR s;
if (fVerbose) {
fprintf( stderr, "DH: Dumping object information.\n" );
}
sprintf( DumpLine, "\n\n*********** Object Information ********************\n\n" );
DumpOutputString();
TypeInfo = ObjectInformation;
while (TRUE) {
sprintf( DumpLine, "\n\n*********** %wZ Object Type ********************\n\n",
&TypeInfo->TypeName
);
DumpOutputString();
sprintf( DumpLine, " NumberOfObjects: %u\n", TypeInfo->NumberOfObjects );
DumpOutputString();
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)TypeInfo->TypeName.Buffer + TypeInfo->TypeName.MaximumLength);
while (TRUE) {
ObjectName = ObjectInfo->NameInfo.Name;
try {
if (ObjectName.Length != 0 && *ObjectName.Buffer == UNICODE_NULL) {
ObjectName.Length = 0;
}
sprintf( DumpLine, " Object: %08lx Name: %wZ Creator: %wZ (Backtrace%05lu)\n",
ObjectInfo->Object,
&ObjectName,
&(FindProcessInfoForCid( ObjectInfo->CreatorUniqueProcess )->ImageName),
ObjectInfo->CreatorBackTraceIndex
);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
sprintf( DumpLine, " Object: %08lx Name: [%04x, %04x, %08x]\n",
ObjectInfo->Object,
ObjectName.MaximumLength,
ObjectName.Length,
ObjectName.Buffer
);
}
DumpOutputString();
BackTraceInfo = FindBackTrace( ObjectInfo->CreatorBackTraceIndex );
if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
s = DumpLine;
s += sprintf( s, "\n PointerCount: %u HandleCount: %u",
ObjectInfo->PointerCount,
ObjectInfo->HandleCount
);
if (ObjectInfo->SecurityDescriptor != NULL) {
s += sprintf( s, " Security: %08x", ObjectInfo->SecurityDescriptor );
}
if (ObjectInfo->ExclusiveProcessId) {
s += sprintf( s, " Exclusive by Process: %04x", ObjectInfo->ExclusiveProcessId );
}
s += sprintf( s, " Flags: %02x", ObjectInfo->Flags );
if (ObjectInfo->Flags & OB_FLAG_NEW_OBJECT) {
s += sprintf( s, " New" );
}
if (ObjectInfo->Flags & OB_FLAG_KERNEL_OBJECT) {
s += sprintf( s, " KernelMode" );
}
if (ObjectInfo->Flags & OB_FLAG_PERMANENT_OBJECT) {
s += sprintf( s, " Permanent" );
}
if (ObjectInfo->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA) {
s += sprintf( s, " DefaultSecurityQuota" );
}
if (ObjectInfo->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
s += sprintf( s, " Single Handle Entry" );
}
s += sprintf( s, "\n" );
DumpOutputString();
if (ObjectInfo->HandleCount != 0) {
PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntry;
ULONG HandleNumber;
HandleEntry = &HandleInformation->Handles[ 0 ];
HandleNumber = 0;
while (HandleNumber++ < HandleInformation->NumberOfHandles) {
if (((HandleEntry->HandleAttributes & 0x80) && HandleEntry->Object == ObjectInfo) ||
(!(HandleEntry->HandleAttributes & 0x80) && HandleEntry->Object == ObjectInfo->Object)
) {
sprintf( DumpLine, " Handle: %08lx Access:%08lx Process: %wZ\n",
HandleEntry->HandleValue,
HandleEntry->GrantedAccess,
&(FindProcessInfoForCid( (HANDLE)HandleEntry->UniqueProcessId )->ImageName)
);
DumpOutputString();
}
HandleEntry++;
}
}
sprintf( DumpLine, "\n" );
DumpOutputString();
if (ObjectInfo->NextEntryOffset == 0) {
break;
}
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)ObjectInformation + ObjectInfo->NextEntryOffset);
}
if (TypeInfo->NextEntryOffset == 0) {
break;
}
TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
}
return;
}
VOID
DumpHandles( VOID )
{
PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntry;
HANDLE PreviousUniqueProcessId;
ULONG HandleNumber;
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
PSYSTEM_OBJECT_INFORMATION ObjectInfo;
PVOID Object;
PUCHAR s;
if (fVerbose) {
fprintf( stderr, "DH: Dumping handle information.\n" );
}
sprintf( DumpLine, "\n\n*********** Object Handle Information ********************\n\n" );
DumpOutputString();
sprintf( DumpLine, "Number of handles: %u\n", HandleInformation->NumberOfHandles );
DumpOutputString();
HandleEntry = &HandleInformation->Handles[ 0 ];
HandleNumber = 0;
PreviousUniqueProcessId = INVALID_HANDLE_VALUE;
while (HandleNumber++ < HandleInformation->NumberOfHandles) {
if (PreviousUniqueProcessId != (HANDLE)HandleEntry->UniqueProcessId) {
PreviousUniqueProcessId = (HANDLE)HandleEntry->UniqueProcessId;
sprintf( DumpLine, "\n\n*********** Handles for %wZ ********************\n\n",
&(FindProcessInfoForCid( PreviousUniqueProcessId )->ImageName)
);
DumpOutputString();
}
if (HandleEntry->HandleAttributes & 0x80) {
ObjectInfo = HandleEntry->Object;
Object = ObjectInfo->Object;
}
else {
ObjectInfo = NULL;
Object = HandleEntry->Object;
}
sprintf( DumpLine, " Handle: %08lx%c Type: %wZ Object: %08lx Access: %08lx\n",
HandleEntry->HandleValue,
HandleEntry->HandleAttributes & OBJ_INHERIT ? 'i' : ' ',
TypeNames[ HandleEntry->ObjectTypeIndex < MAX_TYPE_NAMES ? HandleEntry->ObjectTypeIndex : MAX_TYPE_NAMES ],
Object,
HandleEntry->GrantedAccess
);
DumpOutputString();
if (ObjectInfo != NULL) {
UNICODE_STRING ObjectName;
ObjectName = ObjectInfo->NameInfo.Name;
try {
if (ObjectName.Length != 0 && *ObjectName.Buffer == UNICODE_NULL) {
ObjectName.Length = 0;
}
sprintf( DumpLine, " Name: %wZ\n",
&ObjectName
);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
sprintf( DumpLine, " Name: [%04x, %04x, %08x]\n",
ObjectName.MaximumLength,
ObjectName.Length,
ObjectName.Buffer
);
}
DumpOutputString();
}
if (HandleEntry->CreatorBackTraceIndex != 0) {
sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", HandleEntry->CreatorBackTraceIndex );
DumpOutputString();
BackTraceInfo = FindBackTrace( HandleEntry->CreatorBackTraceIndex );
if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
while (*s) {
sprintf( DumpLine, " %s\n", s );
DumpOutputString();
while (*s++) {
}
}
}
}
sprintf( DumpLine, " \n" );
DumpOutputString();
HandleEntry++;
}
return;
}