windows-nt/Source/XPSP1/NT/base/ntdll/query.c
2020-09-26 16:20:57 +08:00

1149 lines
40 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
query.c
Abstract:
This module contains the RtlQueryProcessInformation function
Author:
Steve Wood (stevewo) 01-Apr-1994
Revision History:
--*/
#include <ntos.h>
#include "ldrp.h"
#include <stktrace.h>
#include <heap.h>
#include <stdio.h>
#define AdjustPointer( t, p, d ) (p); if ((p) != NULL) (p) = (t)((ULONG_PTR)(p) + (d))
NTSYSAPI
NTSTATUS
NTAPI
RtlpQueryProcessDebugInformationRemote(
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
ULONG i;
ULONG_PTR Delta;
PRTL_PROCESS_HEAPS Heaps;
PRTL_HEAP_INFORMATION HeapInfo;
if (Buffer->EventPairTarget != NULL) {
Status = NtWaitLowEventPair( Buffer->EventPairTarget );
}
else {
Status = STATUS_SUCCESS;
}
while (NT_SUCCESS( Status )) {
Status = RtlQueryProcessDebugInformation( NtCurrentTeb()->ClientId.UniqueProcess,
Buffer->Flags,
Buffer
);
if (NT_SUCCESS( Status )) {
if (Delta = Buffer->ViewBaseDelta) {
//
// Need to relocate buffer pointers back to client addresses
//
AdjustPointer( PRTL_PROCESS_MODULES, Buffer->Modules, Delta );
AdjustPointer( PRTL_PROCESS_BACKTRACES, Buffer->BackTraces, Delta );
Heaps = AdjustPointer( PRTL_PROCESS_HEAPS, Buffer->Heaps, Delta );
if (Heaps != NULL) {
for (i=0; i<Heaps->NumberOfHeaps; i++) {
HeapInfo = &Heaps->Heaps[ i ];
AdjustPointer( PRTL_HEAP_TAG, HeapInfo->Tags, Delta );
AdjustPointer( PRTL_HEAP_ENTRY, HeapInfo->Entries, Delta );
}
}
AdjustPointer( PRTL_PROCESS_LOCKS, Buffer->Locks, Delta );
}
}
if (Buffer->EventPairTarget == NULL) {
//
// If no event pair handle, then exit loop and terminate
//
break;
}
Status = NtSetHighWaitLowEventPair( Buffer->EventPairTarget );
if (Buffer->EventPairTarget == NULL) {
break;
}
}
//
// All done with buffer, remove from our address space
// then terminate ourselves so client wakes up.
//
NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
RtlExitUserThread (Status);
return Status;
}
NTSTATUS
RtlpChangeQueryDebugBufferTarget(
IN PRTL_DEBUG_INFORMATION Buffer,
IN HANDLE TargetProcessId,
OUT PHANDLE ReturnedTargetProcessHandle
)
{
NTSTATUS Status;
CLIENT_ID OldTargetClientId, NewTargetClientId;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE OldTargetProcess, NewTargetProcess, NewHandle;
PHANDLE pOldHandle;
ULONG DuplicateHandleFlags;
if (Buffer->EventPairClient != NULL &&
Buffer->TargetProcessId == TargetProcessId
) {
return STATUS_SUCCESS;
}
InitializeObjectAttributes( &ObjectAttributes,
NULL,
0,
NULL,
NULL
);
DuplicateHandleFlags = DUPLICATE_CLOSE_SOURCE |
DUPLICATE_SAME_ACCESS |
DUPLICATE_SAME_ATTRIBUTES;
if (Buffer->EventPairClient != NULL) {
pOldHandle = &Buffer->EventPairTarget;
}
else {
pOldHandle = NULL;
}
if (Buffer->TargetProcessId != NULL) {
OldTargetClientId.UniqueProcess = Buffer->TargetProcessId;
OldTargetClientId.UniqueThread = 0;
Status = NtOpenProcess( &OldTargetProcess,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
&OldTargetClientId
);
if (!NT_SUCCESS( Status )) {
return Status;
}
}
else {
OldTargetProcess = NtCurrentProcess();
DuplicateHandleFlags &= ~DUPLICATE_CLOSE_SOURCE;
if (pOldHandle != NULL) {
pOldHandle = &Buffer->EventPairClient;
}
}
if (ARGUMENT_PRESENT( TargetProcessId )) {
NewTargetClientId.UniqueProcess = TargetProcessId;
NewTargetClientId.UniqueThread = 0;
Status = NtOpenProcess( &NewTargetProcess,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
&NewTargetClientId
);
if (!NT_SUCCESS( Status )) {
if (OldTargetProcess != NtCurrentProcess()) {
NtClose( OldTargetProcess );
}
return Status;
}
}
else {
NewTargetProcess = NULL;
}
NewHandle = NULL;
if (pOldHandle != NULL) {
Status = NtDuplicateObject( OldTargetProcess,
*pOldHandle,
NewTargetProcess,
&NewHandle,
0,
0,
DuplicateHandleFlags
);
if (!NT_SUCCESS( Status )) {
if (OldTargetProcess != NtCurrentProcess()) {
NtClose( OldTargetProcess );
}
if (NewTargetProcess != NULL) {
NtClose( NewTargetProcess );
}
return Status;
}
}
if (OldTargetProcess != NtCurrentProcess()) {
NtUnmapViewOfSection( OldTargetProcess, Buffer->ViewBaseTarget );
}
else {
Buffer->ViewBaseTarget = Buffer->ViewBaseClient;
}
if (NewTargetProcess != NULL) {
Status = NtMapViewOfSection( Buffer->SectionHandleClient,
NewTargetProcess,
&Buffer->ViewBaseTarget,
0,
0,
NULL,
&Buffer->ViewSize,
ViewUnmap,
0,
PAGE_READWRITE
);
if (Status == STATUS_CONFLICTING_ADDRESSES) {
Buffer->ViewBaseTarget = NULL;
Status = NtMapViewOfSection( Buffer->SectionHandleClient,
NewTargetProcess,
&Buffer->ViewBaseTarget,
0,
0,
NULL,
&Buffer->ViewSize,
ViewUnmap,
0,
PAGE_READWRITE
);
}
if (!NT_SUCCESS( Status )) {
if (NewHandle != NULL) {
NtDuplicateObject( NewTargetProcess,
&NewHandle,
NULL,
NULL,
0,
0,
DUPLICATE_CLOSE_SOURCE
);
}
return Status;
}
if (ARGUMENT_PRESENT( ReturnedTargetProcessHandle )) {
*ReturnedTargetProcessHandle = NewTargetProcess;
}
else {
NtClose( NewTargetProcess );
}
}
Buffer->EventPairTarget = NewHandle;
Buffer->ViewBaseDelta = (ULONG_PTR)Buffer->ViewBaseClient - (ULONG_PTR)Buffer->ViewBaseTarget;
return STATUS_SUCCESS;
}
PVOID
RtlpCommitQueryDebugInfo(
IN PRTL_DEBUG_INFORMATION Buffer,
IN ULONG Size
)
{
NTSTATUS Status;
PVOID Result;
PVOID CommitBase;
SIZE_T CommitSize;
SIZE_T NeededSize;
Size = (Size + 3) & ~3;
NeededSize = Buffer->OffsetFree + Size;
if (NeededSize > Buffer->CommitSize) {
if (NeededSize >= Buffer->ViewSize) {
return NULL;
}
CommitBase = (PCHAR)Buffer + Buffer->CommitSize;
CommitSize = NeededSize - Buffer->CommitSize;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&CommitBase,
0,
&CommitSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
return NULL;
}
Buffer->CommitSize += CommitSize;
}
Result = (PCHAR)Buffer + Buffer->OffsetFree;
Buffer->OffsetFree = NeededSize;
return Result;
}
VOID
RtlpDeCommitQueryDebugInfo(
IN PRTL_DEBUG_INFORMATION Buffer,
IN PVOID p,
IN ULONG Size
)
{
Size = (Size + 3) & ~3;
if (p == (PVOID)(Buffer->OffsetFree - Size)) {
Buffer->OffsetFree -= Size;
}
}
NTSYSAPI
PRTL_DEBUG_INFORMATION
NTAPI
RtlCreateQueryDebugBuffer(
IN ULONG MaximumCommit OPTIONAL,
IN BOOLEAN UseEventPair
)
{
NTSTATUS Status;
HANDLE Section;
PRTL_DEBUG_INFORMATION Buffer;
LARGE_INTEGER MaximumSize;
ULONG_PTR ViewSize, CommitSize;
if (!ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)MaximumCommit )) { // Sundown Note: ULONG zero-extended.
MaximumCommit = 4 * 1024 * 1024;
}
MaximumSize.QuadPart = MaximumCommit;
Status = NtCreateSection( &Section,
SECTION_ALL_ACCESS,
NULL,
&MaximumSize,
PAGE_READWRITE,
SEC_RESERVE,
NULL
);
if (!NT_SUCCESS( Status )) {
return NULL;
}
Buffer = NULL;
ViewSize = MaximumCommit;
Status = NtMapViewOfSection( Section,
NtCurrentProcess(),
&Buffer,
0,
0,
NULL,
&ViewSize,
ViewUnmap,
0,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
NtClose( Section );
return NULL;
}
CommitSize = 1;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&Buffer,
0,
&CommitSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
NtClose( Section );
return NULL;
}
if (UseEventPair) {
Status = NtCreateEventPair( &Buffer->EventPairClient,
EVENT_PAIR_ALL_ACCESS,
NULL
);
if (!NT_SUCCESS( Status )) {
NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
NtClose( Section );
return NULL;
}
}
Buffer->SectionHandleClient = Section;
Buffer->ViewBaseClient = Buffer;
Buffer->OffsetFree = 0;
Buffer->CommitSize = CommitSize;
Buffer->ViewSize = ViewSize;
return Buffer;
}
NTSYSAPI
NTSTATUS
NTAPI
RtlDestroyQueryDebugBuffer(
IN PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
HANDLE ProcessHandle, ThreadHandle;
THREAD_BASIC_INFORMATION BasicInformation;
SIZE_T BigSize;
RtlpChangeQueryDebugBufferTarget( Buffer, NULL, NULL );
Status = STATUS_SUCCESS;
if (Buffer->TargetThreadHandle != NULL) {
Buffer->EventPairTarget = NULL;
NtSetLowEventPair( Buffer->EventPairClient );
NtClose( Buffer->EventPairClient );
Status = NtWaitForSingleObject( Buffer->TargetThreadHandle,
TRUE,
NULL
);
if (NT_SUCCESS( Status )) {
Status = NtQueryInformationThread( Buffer->TargetThreadHandle,
ThreadBasicInformation,
&BasicInformation,
sizeof( BasicInformation ),
NULL
);
if (NT_SUCCESS( Status )) {
Status = BasicInformation.ExitStatus;
}
}
}
NtClose( Buffer->SectionHandleClient );
NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
return Status;
}
NTSYSAPI
NTSTATUS
NTAPI
RtlQueryProcessDebugInformation(
IN HANDLE UniqueProcessId,
IN ULONG Flags,
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status = STATUS_SUCCESS;
HANDLE ProcessHandle, ThreadHandle;
THREAD_BASIC_INFORMATION BasicInformation;
HANDLE hNiProcess = NULL;
Buffer->Flags = Flags;
if (Buffer->OffsetFree != 0) {
RtlZeroMemory( (Buffer+1), Buffer->OffsetFree - (SIZE_T)sizeof(*Buffer) );
}
Buffer->OffsetFree = sizeof( *Buffer );
//
// Get process handle for noninvasive query if required
//
if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
(Flags & RTL_QUERY_PROCESS_NONINVASIVE) &&
(Flags & ( RTL_QUERY_PROCESS_MODULES |
RTL_QUERY_PROCESS_MODULES32
)
) &&
!(Flags & ~( RTL_QUERY_PROCESS_MODULES |
RTL_QUERY_PROCESS_MODULES32 |
RTL_QUERY_PROCESS_NONINVASIVE
)
)
) {
OBJECT_ATTRIBUTES ObjectAttributes;
CLIENT_ID NiProcessId;
InitializeObjectAttributes( &ObjectAttributes,
NULL,
0,
NULL,
NULL
);
NiProcessId.UniqueProcess = UniqueProcessId;
NiProcessId.UniqueThread = 0;
if (!NT_SUCCESS( NtOpenProcess( &hNiProcess,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
&NiProcessId
)
)
) {
hNiProcess = NULL;
}
}
if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
!hNiProcess
) {
//
// Perform remote query
//
ProcessHandle = NULL;
Status = RtlpChangeQueryDebugBufferTarget( Buffer, UniqueProcessId, &ProcessHandle );
if (!NT_SUCCESS( Status )) {
return Status;
}
if (ProcessHandle == NULL) {
waitForDump:
Status = NtSetLowWaitHighEventPair( Buffer->EventPairClient );
} else {
//
// don't let the debugger see this remote thread !
// This is a very ugly but effective way to prevent
// the debugger deadlocking with the target process when calling
// this function.
//
Status = RtlCreateUserThread( ProcessHandle,
NULL,
TRUE,
0,
0,
0,
RtlpQueryProcessDebugInformationRemote,
Buffer->ViewBaseTarget,
&ThreadHandle,
NULL
);
if (NT_SUCCESS( Status )) {
Status = NtSetInformationThread( ThreadHandle,
ThreadHideFromDebugger,
NULL,
0
);
if ( !NT_SUCCESS(Status) ) {
NtTerminateThread(ThreadHandle,Status);
NtClose(ThreadHandle);
NtClose(ProcessHandle);
return Status;
}
NtResumeThread(ThreadHandle,NULL);
if (Buffer->EventPairClient != NULL) {
Buffer->TargetThreadHandle = ThreadHandle;
Buffer->TargetProcessHandle = ProcessHandle;
goto waitForDump;
}
Status = NtWaitForSingleObject( ThreadHandle,
TRUE,
NULL
);
if (NT_SUCCESS( Status )) {
Status = NtQueryInformationThread( ThreadHandle,
ThreadBasicInformation,
&BasicInformation,
sizeof( BasicInformation ),
NULL
);
if (NT_SUCCESS( Status )) {
Status = BasicInformation.ExitStatus;
}
if (NT_SUCCESS (Status) &&
(Flags&(RTL_QUERY_PROCESS_MODULES|RTL_QUERY_PROCESS_MODULES32)) != 0 &&
Buffer->Modules == NULL) {
Status = STATUS_PROCESS_IS_TERMINATING;
}
}
NtClose( ThreadHandle );
}
NtClose( ProcessHandle );
}
} else {
if (Flags & (RTL_QUERY_PROCESS_MODULES | RTL_QUERY_PROCESS_MODULES32)) {
Status = RtlQueryProcessModuleInformation( hNiProcess, Flags, Buffer );
if (Status != STATUS_SUCCESS) {
goto closeNiProcessAndBreak;
}
}
if (Flags & RTL_QUERY_PROCESS_BACKTRACES) {
Status = RtlQueryProcessBackTraceInformation( Buffer );
if (Status != STATUS_SUCCESS) {
goto closeNiProcessAndBreak;
}
}
if (Flags & RTL_QUERY_PROCESS_LOCKS) {
Status = RtlQueryProcessLockInformation( Buffer );
if (Status != STATUS_SUCCESS) {
goto closeNiProcessAndBreak;
}
}
if (Flags & (RTL_QUERY_PROCESS_HEAP_SUMMARY |
RTL_QUERY_PROCESS_HEAP_TAGS |
RTL_QUERY_PROCESS_HEAP_ENTRIES
)
) {
Status = RtlQueryProcessHeapInformation( Buffer );
if (Status != STATUS_SUCCESS) {
goto closeNiProcessAndBreak;
}
}
closeNiProcessAndBreak:
if ( hNiProcess ) {
NtClose( hNiProcess );
}
}
return Status;
}
NTSTATUS
LdrQueryProcessModuleInformationEx(
IN HANDLE hProcess OPTIONAL,
IN ULONG_PTR Flags OPTIONAL,
OUT PRTL_PROCESS_MODULES ModuleInformation,
IN ULONG ModuleInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
NTSTATUS
NTAPI
RtlQueryProcessModuleInformation
(
IN HANDLE hProcess OPTIONAL,
IN ULONG Flags,
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
ULONG RequiredLength;
PRTL_PROCESS_MODULES Modules;
ULONG LdrFlags = (Flags & RTL_QUERY_PROCESS_MODULES32) != 0;
Status = LdrQueryProcessModuleInformationEx( hProcess,
LdrFlags,
NULL,
0,
&RequiredLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
Modules = RtlpCommitQueryDebugInfo( Buffer, RequiredLength );
if (Modules != NULL) {
Status = LdrQueryProcessModuleInformationEx( hProcess,
LdrFlags,
Modules,
RequiredLength,
&RequiredLength
);
if (NT_SUCCESS( Status )) {
Buffer->Modules = Modules;
return STATUS_SUCCESS;
}
}
}
return STATUS_NO_MEMORY;
}
NTSTATUS
RtlQueryProcessBackTraceInformation(
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
#if i386
NTSTATUS Status;
OUT PRTL_PROCESS_BACKTRACES BackTraces;
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
PSTACK_TRACE_DATABASE DataBase;
PRTL_STACK_TRACE_ENTRY p, *pp;
ULONG n;
DataBase = RtlpAcquireStackTraceDataBase();
if (DataBase == NULL) {
return STATUS_SUCCESS;
}
BackTraces = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_BACKTRACES, BackTraces ) );
if (BackTraces == NULL) {
return STATUS_NO_MEMORY;
}
DataBase->DumpInProgress = TRUE;
RtlpReleaseStackTraceDataBase();
try {
BackTraces->CommittedMemory = (ULONG)DataBase->CurrentUpperCommitLimit -
(ULONG)DataBase->CommitBase;
BackTraces->ReservedMemory = (ULONG)DataBase->EntryIndexArray -
(ULONG)DataBase->CommitBase;
BackTraces->NumberOfBackTraceLookups = DataBase->NumberOfEntriesLookedUp;
BackTraces->NumberOfBackTraces = DataBase->NumberOfEntriesAdded;
BackTraceInfo = RtlpCommitQueryDebugInfo( Buffer, (sizeof( *BackTraceInfo ) * BackTraces->NumberOfBackTraces) );
if (BackTraceInfo == NULL) {
Status = STATUS_NO_MEMORY;
}
else {
Status = STATUS_SUCCESS;
n = DataBase->NumberOfEntriesAdded;
pp = DataBase->EntryIndexArray;
while (n--) {
p = *--pp;
BackTraceInfo->SymbolicBackTrace = NULL;
BackTraceInfo->TraceCount = p->TraceCount;
BackTraceInfo->Index = p->Index;
BackTraceInfo->Depth = p->Depth;
RtlMoveMemory( BackTraceInfo->BackTrace,
p->BackTrace,
p->Depth * sizeof( PVOID )
);
BackTraceInfo++;
}
}
}
finally {
DataBase->DumpInProgress = FALSE;
}
if (NT_SUCCESS( Status )) {
Buffer->BackTraces = BackTraces;
}
return Status;
#else
return STATUS_SUCCESS;
#endif // i386
}
NTSTATUS
RtlpQueryProcessEnumHeapsRoutine(
PVOID HeapHandle,
PVOID Parameter
)
{
PRTL_DEBUG_INFORMATION Buffer = (PRTL_DEBUG_INFORMATION)Parameter;
PRTL_PROCESS_HEAPS Heaps = Buffer->Heaps;
PHEAP Heap = (PHEAP)HeapHandle;
PRTL_HEAP_INFORMATION HeapInfo;
PHEAP_SEGMENT Segment;
UCHAR SegmentIndex;
HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
if (HeapInfo == NULL) {
return STATUS_NO_MEMORY;
}
HeapInfo->BaseAddress = Heap;
HeapInfo->Flags = Heap->Flags;
HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
HeapInfo->CreatorBackTraceIndex = Heap->AllocatorBackTraceIndex;
SegmentIndex = HEAP_MAXIMUM_SEGMENTS;
while (SegmentIndex--) {
Segment = Heap->Segments[ SegmentIndex ];
if (Segment) {
HeapInfo->BytesCommitted += (Segment->NumberOfPages -
Segment->NumberOfUnCommittedPages
) * PAGE_SIZE;
}
}
HeapInfo->BytesAllocated = HeapInfo->BytesCommitted -
(Heap->TotalFreeSize << HEAP_GRANULARITY_SHIFT);
Heaps->NumberOfHeaps += 1;
return STATUS_SUCCESS;
}
NTSYSAPI
NTSTATUS
NTAPI
RtlQueryProcessHeapInformation(
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
PHEAP Heap;
BOOLEAN LockAcquired;
PRTL_PROCESS_HEAPS Heaps;
PRTL_HEAP_INFORMATION HeapInfo;
ULONG NumberOfHeaps;
PVOID *ProcessHeaps;
UCHAR SegmentIndex;
ULONG i, n, TagIndex;
PHEAP_SEGMENT Segment;
PRTL_HEAP_TAG Tags;
PHEAP_PSEUDO_TAG_ENTRY PseudoTags;
PRTL_HEAP_ENTRY Entries;
PHEAP_ENTRY CurrentBlock;
PHEAP_ENTRY_EXTRA ExtraStuff;
PRTL_HEAP_ENTRY p;
PLIST_ENTRY Head, Next;
PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
ULONG Size;
PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
Heaps = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_HEAPS, Heaps ) );
if (Heaps == NULL) {
return STATUS_NO_MEMORY;
}
Buffer->Heaps = Heaps;
Status = RtlEnumProcessHeaps( RtlpQueryProcessEnumHeapsRoutine, Buffer );
if (NT_SUCCESS( Status )) {
if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_TAGS) {
Heap = RtlpGlobalTagHeap;
if (Heap->TagEntries != NULL) {
HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
if (HeapInfo == NULL) {
return STATUS_NO_MEMORY;
}
HeapInfo->BaseAddress = Heap;
HeapInfo->Flags = Heap->Flags;
HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
Heaps->NumberOfHeaps += 1;
}
for (i=0; i<Heaps->NumberOfHeaps; i++) {
HeapInfo = &Heaps->Heaps[ i ];
if (Buffer->SpecificHeap == NULL ||
Buffer->SpecificHeap == HeapInfo->BaseAddress
) {
Heap = HeapInfo->BaseAddress;
HeapInfo->NumberOfTags = Heap->NextAvailableTagIndex;
n = HeapInfo->NumberOfTags * sizeof( RTL_HEAP_TAG );
if (Heap->PseudoTagEntries != NULL) {
HeapInfo->NumberOfTags += HEAP_MAXIMUM_FREELISTS + 1;
n += (HEAP_MAXIMUM_FREELISTS + 1) * sizeof( RTL_HEAP_TAG );
}
Tags = RtlpCommitQueryDebugInfo( Buffer, n );
if (Tags == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
HeapInfo->Tags = Tags;
if ((PseudoTags = Heap->PseudoTagEntries) != NULL) {
HeapInfo->NumberOfPseudoTags = HEAP_NUMBER_OF_PSEUDO_TAG;
HeapInfo->PseudoTagGranularity = HEAP_GRANULARITY;
for (TagIndex=0; TagIndex<=HEAP_MAXIMUM_FREELISTS; TagIndex++) {
Tags->NumberOfAllocations = PseudoTags->Allocs;
Tags->NumberOfFrees = PseudoTags->Frees;
Tags->BytesAllocated = PseudoTags->Size << HEAP_GRANULARITY_SHIFT;
Tags->TagIndex = (USHORT)(TagIndex | HEAP_PSEUDO_TAG_FLAG);
if (TagIndex == 0) {
swprintf( Tags->TagName, L"Objects>%4u",
HEAP_MAXIMUM_FREELISTS << HEAP_GRANULARITY_SHIFT
);
}
else
if (TagIndex < HEAP_MAXIMUM_FREELISTS) {
swprintf( Tags->TagName, L"Objects=%4u",
TagIndex << HEAP_GRANULARITY_SHIFT
);
}
else {
swprintf( Tags->TagName, L"VirtualAlloc",
TagIndex << HEAP_GRANULARITY_SHIFT
);
}
Tags += 1;
PseudoTags += 1;
}
}
RtlMoveMemory( Tags,
Heap->TagEntries,
Heap->NextAvailableTagIndex * sizeof( RTL_HEAP_TAG )
);
for (TagIndex=0; TagIndex<Heap->NextAvailableTagIndex; TagIndex++) {
Tags->BytesAllocated <<= HEAP_GRANULARITY_SHIFT;
Tags += 1;
}
}
}
}
}
else {
Buffer->Heaps = NULL;
}
if (NT_SUCCESS( Status )) {
if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_ENTRIES) {
for (i=0; i<Heaps->NumberOfHeaps; i++) {
HeapInfo = &Heaps->Heaps[ i ];
Heap = HeapInfo->BaseAddress;
if (Buffer->SpecificHeap == NULL ||
Buffer->SpecificHeap == Heap
) {
if (!(Heap->Flags & HEAP_NO_SERIALIZE)) {
RtlEnterCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
LockAcquired = TRUE;
}
else {
LockAcquired = FALSE;
}
try {
for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
Segment = Heap->Segments[ SegmentIndex ];
if (!Segment) {
continue;
}
Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
if (Entries == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
else
if (HeapInfo->Entries == NULL) {
HeapInfo->Entries = Entries;
}
Entries->Flags = RTL_HEAP_SEGMENT;
Entries->AllocatorBackTraceIndex = Segment->AllocatorBackTraceIndex;
Entries->Size = Segment->NumberOfPages * PAGE_SIZE;
Entries->u.s2.CommittedSize = (Segment->NumberOfPages -
Segment->NumberOfUnCommittedPages
) * PAGE_SIZE;
Entries->u.s2.FirstBlock = Segment->FirstEntry;
HeapInfo->NumberOfEntries++;
UnCommittedRange = Segment->UnCommittedRanges;
CurrentBlock = Segment->FirstEntry;
while (CurrentBlock < Segment->LastValidEntry) {
Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
if (Entries == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
Size = CurrentBlock->Size << HEAP_GRANULARITY_SHIFT;
Entries->Size = Size;
HeapInfo->NumberOfEntries++;
if (CurrentBlock->Flags & HEAP_ENTRY_BUSY) {
if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
ExtraStuff = (PHEAP_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size - 1);
#if i386
Entries->AllocatorBackTraceIndex = ExtraStuff->AllocatorBackTraceIndex;
#endif // i386
Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
Entries->u.s1.Settable = ExtraStuff->Settable;
Entries->u.s1.Tag = ExtraStuff->TagIndex;
}
else {
Entries->u.s1.Tag = CurrentBlock->SmallTagIndex;
}
Entries->Flags |= RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
}
else
if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
PHEAP_FREE_ENTRY_EXTRA FreeExtra;
FreeExtra = (PHEAP_FREE_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size) - 1;
Entries->u.s1.Tag = FreeExtra->TagIndex;
Entries->AllocatorBackTraceIndex = FreeExtra->FreeBackTraceIndex;
}
if (CurrentBlock->Flags & HEAP_ENTRY_LAST_ENTRY) {
CurrentBlock += CurrentBlock->Size;
if (UnCommittedRange == NULL) {
CurrentBlock = Segment->LastValidEntry;
}
else {
Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
if (Entries == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
Entries->Flags = RTL_HEAP_UNCOMMITTED_RANGE;
Entries->Size = UnCommittedRange->Size;
HeapInfo->NumberOfEntries++;
CurrentBlock = (PHEAP_ENTRY)
((PCHAR)UnCommittedRange->Address + UnCommittedRange->Size);
UnCommittedRange = UnCommittedRange->Next;
}
}
else {
CurrentBlock += CurrentBlock->Size;
}
}
}
Head = &Heap->VirtualAllocdBlocks;
Next = Head->Flink;
while (Head != Next) {
VirtualAllocBlock = CONTAINING_RECORD( Next, HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
CurrentBlock = &VirtualAllocBlock->BusyBlock;
Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
if (Entries == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
else
if (HeapInfo->Entries == NULL) {
HeapInfo->Entries = Entries;
}
Entries->Flags = RTL_HEAP_SEGMENT;
Entries->Size = VirtualAllocBlock->ReserveSize;
Entries->u.s2.CommittedSize = VirtualAllocBlock->CommitSize;
Entries->u.s2.FirstBlock = CurrentBlock;
HeapInfo->NumberOfEntries++;
Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
if (Entries == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
Entries->Size = VirtualAllocBlock->CommitSize;
Entries->Flags = RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
#if i386
Entries->AllocatorBackTraceIndex = VirtualAllocBlock->ExtraStuff.AllocatorBackTraceIndex;
#endif // i386
Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
Entries->u.s1.Settable = VirtualAllocBlock->ExtraStuff.Settable;
Entries->u.s1.Tag = VirtualAllocBlock->ExtraStuff.TagIndex;
HeapInfo->NumberOfEntries++;
Next = Next->Flink;
}
}
finally {
//
// Unlock the heap
//
if (LockAcquired) {
RtlLeaveCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
}
}
}
if (!NT_SUCCESS( Status )) {
break;
}
}
}
}
return Status;
}
NTSYSAPI
NTSTATUS
NTAPI
RtlQueryProcessLockInformation(
IN OUT PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
PLIST_ENTRY Head, Next;
PRTL_PROCESS_LOCKS Locks;
PRTL_PROCESS_LOCK_INFORMATION LockInfo;
PRTL_CRITICAL_SECTION CriticalSection;
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
PRTL_RESOURCE Resource;
PRTL_RESOURCE_DEBUG ResourceDebugInfo;
Locks = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_LOCKS, Locks ) );
if (Locks == NULL) {
return STATUS_NO_MEMORY;
}
RtlEnterCriticalSection( &RtlCriticalSectionLock );
Head = &RtlCriticalSectionList;
Next = Head->Flink;
Status = STATUS_SUCCESS;
while (Next != Head) {
DebugInfo = CONTAINING_RECORD( Next,
RTL_CRITICAL_SECTION_DEBUG,
ProcessLocksList
);
LockInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
if (LockInfo == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
CriticalSection = DebugInfo->CriticalSection;
try {
LockInfo->Address = CriticalSection;
LockInfo->Type = DebugInfo->Type;
LockInfo->CreatorBackTraceIndex = DebugInfo->CreatorBackTraceIndex;
if (LockInfo->Type == RTL_CRITSECT_TYPE) {
LockInfo->OwningThread = CriticalSection->OwningThread;
LockInfo->LockCount = CriticalSection->LockCount;
LockInfo->RecursionCount = CriticalSection->RecursionCount;
LockInfo->ContentionCount = DebugInfo->ContentionCount;
LockInfo->EntryCount = DebugInfo->EntryCount;
}
else {
Resource = (PRTL_RESOURCE)CriticalSection;
ResourceDebugInfo = Resource->DebugInfo;
LockInfo->ContentionCount = ResourceDebugInfo->ContentionCount;
LockInfo->OwningThread = Resource->ExclusiveOwnerThread;
LockInfo->LockCount = Resource->NumberOfActive;
LockInfo->NumberOfWaitingShared = Resource->NumberOfWaitingShared;
LockInfo->NumberOfWaitingExclusive = Resource->NumberOfWaitingExclusive;
}
Locks->NumberOfLocks++;
}
except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("NTDLL: Lost critical section %08lX\n", CriticalSection);
RtlpDeCommitQueryDebugInfo( Buffer, LockInfo, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
}
if (Next == Next->Flink) {
//
// Bail if list is circular
//
break;
}
else {
Next = Next->Flink;
}
}
RtlLeaveCriticalSection( &RtlCriticalSectionLock );
if (NT_SUCCESS( Status )) {
Buffer->Locks = Locks;
}
return Status;
}