Windows2000/private/ntos/dll/query.c
2020-09-30 17:12:32 +02:00

869 lines
33 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
*/
#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);
NtTerminateThread(NtCurrentThread(), 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;
PTEB Teb;
PVOID StackDeallocationBase;
ULONG Size;
SIZE_T BigSize;
RtlpChangeQueryDebugBufferTarget(Buffer, NULL, NULL);
Status = STATUS_SUCCESS;
if (Buffer->TargetThreadHandle != NULL) {
StackDeallocationBase = NULL;
Status = NtQueryInformationThread(Buffer->TargetThreadHandle, ThreadBasicInformation, &BasicInformation, sizeof(BasicInformation), NULL);
if (NT_SUCCESS(Status)) {
if (Teb = BasicInformation.TebBaseAddress) {
NtReadVirtualMemory(Buffer->TargetProcessHandle, &Teb->DeallocationStack, &StackDeallocationBase, sizeof(StackDeallocationBase), &Size);
}
}
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;
}
}
BigSize = 0;
NtFreeVirtualMemory(Buffer->TargetProcessHandle, &StackDeallocationBase, &BigSize, MEM_RELEASE);
}
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;
HANDLE ProcessHandle, ThreadHandle;
THREAD_BASIC_INFORMATION BasicInformation;
PTEB Teb;
PVOID StackDeallocationBase;
ULONG Size;
SIZE_T BigSize;
Buffer->Flags = Flags;
if (Buffer->OffsetFree != 0) {
RtlZeroMemory((Buffer + 1), Buffer->OffsetFree - (SIZE_T)sizeof(*Buffer));
}
Buffer->OffsetFree = sizeof(*Buffer);
if (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) {
// Not querying current process, so do it remotely
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;
}
StackDeallocationBase = NULL;
Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &BasicInformation, sizeof(BasicInformation), NULL);
if (NT_SUCCESS(Status)) {
if (Teb = BasicInformation.TebBaseAddress) {
NtReadVirtualMemory(ProcessHandle, &Teb->DeallocationStack, &StackDeallocationBase, sizeof(StackDeallocationBase), &Size);
}
}
Status = NtWaitForSingleObject(ThreadHandle, TRUE, NULL);
if (NT_SUCCESS(Status)) {
Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &BasicInformation, sizeof(BasicInformation), NULL);
if (NT_SUCCESS(Status)) {
Status = BasicInformation.ExitStatus;
}
}
BigSize = 0;
NtFreeVirtualMemory(ProcessHandle, &StackDeallocationBase, &BigSize, MEM_RELEASE);
NtClose(ThreadHandle);
}
NtClose(ProcessHandle);
}
}
else {
if (Flags & RTL_QUERY_PROCESS_MODULES) {
Status = RtlQueryProcessModuleInformation(Buffer);
if (Status != STATUS_SUCCESS) {
return Status;
}
}
if (Flags & RTL_QUERY_PROCESS_BACKTRACES) {
Status = RtlQueryProcessBackTraceInformation(Buffer);
if (Status != STATUS_SUCCESS) {
return Status;
}
}
if (Flags & RTL_QUERY_PROCESS_LOCKS) {
Status = RtlQueryProcessLockInformation(Buffer);
if (Status != STATUS_SUCCESS) {
return Status;
}
}
if (Flags & (RTL_QUERY_PROCESS_HEAP_SUMMARY | RTL_QUERY_PROCESS_HEAP_TAGS | RTL_QUERY_PROCESS_HEAP_ENTRIES)) {
Status = RtlQueryProcessHeapInformation(Buffer);
if (Status != STATUS_SUCCESS) {
return Status;
}
}
}
return Status;
}
NTSTATUS NTAPI RtlQueryProcessModuleInformation(IN OUT PRTL_DEBUG_INFORMATION Buffer)
{
NTSTATUS Status;
ULONG RequiredLength;
PRTL_PROCESS_MODULES Modules;
Status = LdrQueryProcessModuleInformation(NULL, 0, &RequiredLength);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
Modules = RtlpCommitQueryDebugInfo(Buffer, RequiredLength);
if (Modules != NULL) {
Status = LdrQueryProcessModuleInformation(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;
}