Source code of Windows XP (NT5)
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.

1148 lines
40 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. This module contains the RtlQueryProcessInformation function
  7. Author:
  8. Steve Wood (stevewo) 01-Apr-1994
  9. Revision History:
  10. --*/
  11. #include <ntos.h>
  12. #include "ldrp.h"
  13. #include <stktrace.h>
  14. #include <heap.h>
  15. #include <stdio.h>
  16. #define AdjustPointer( t, p, d ) (p); if ((p) != NULL) (p) = (t)((ULONG_PTR)(p) + (d))
  17. NTSYSAPI
  18. NTSTATUS
  19. NTAPI
  20. RtlpQueryProcessDebugInformationRemote(
  21. IN OUT PRTL_DEBUG_INFORMATION Buffer
  22. )
  23. {
  24. NTSTATUS Status;
  25. ULONG i;
  26. ULONG_PTR Delta;
  27. PRTL_PROCESS_HEAPS Heaps;
  28. PRTL_HEAP_INFORMATION HeapInfo;
  29. if (Buffer->EventPairTarget != NULL) {
  30. Status = NtWaitLowEventPair( Buffer->EventPairTarget );
  31. }
  32. else {
  33. Status = STATUS_SUCCESS;
  34. }
  35. while (NT_SUCCESS( Status )) {
  36. Status = RtlQueryProcessDebugInformation( NtCurrentTeb()->ClientId.UniqueProcess,
  37. Buffer->Flags,
  38. Buffer
  39. );
  40. if (NT_SUCCESS( Status )) {
  41. if (Delta = Buffer->ViewBaseDelta) {
  42. //
  43. // Need to relocate buffer pointers back to client addresses
  44. //
  45. AdjustPointer( PRTL_PROCESS_MODULES, Buffer->Modules, Delta );
  46. AdjustPointer( PRTL_PROCESS_BACKTRACES, Buffer->BackTraces, Delta );
  47. Heaps = AdjustPointer( PRTL_PROCESS_HEAPS, Buffer->Heaps, Delta );
  48. if (Heaps != NULL) {
  49. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  50. HeapInfo = &Heaps->Heaps[ i ];
  51. AdjustPointer( PRTL_HEAP_TAG, HeapInfo->Tags, Delta );
  52. AdjustPointer( PRTL_HEAP_ENTRY, HeapInfo->Entries, Delta );
  53. }
  54. }
  55. AdjustPointer( PRTL_PROCESS_LOCKS, Buffer->Locks, Delta );
  56. }
  57. }
  58. if (Buffer->EventPairTarget == NULL) {
  59. //
  60. // If no event pair handle, then exit loop and terminate
  61. //
  62. break;
  63. }
  64. Status = NtSetHighWaitLowEventPair( Buffer->EventPairTarget );
  65. if (Buffer->EventPairTarget == NULL) {
  66. break;
  67. }
  68. }
  69. //
  70. // All done with buffer, remove from our address space
  71. // then terminate ourselves so client wakes up.
  72. //
  73. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  74. RtlExitUserThread (Status);
  75. return Status;
  76. }
  77. NTSTATUS
  78. RtlpChangeQueryDebugBufferTarget(
  79. IN PRTL_DEBUG_INFORMATION Buffer,
  80. IN HANDLE TargetProcessId,
  81. OUT PHANDLE ReturnedTargetProcessHandle
  82. )
  83. {
  84. NTSTATUS Status;
  85. CLIENT_ID OldTargetClientId, NewTargetClientId;
  86. OBJECT_ATTRIBUTES ObjectAttributes;
  87. HANDLE OldTargetProcess, NewTargetProcess, NewHandle;
  88. PHANDLE pOldHandle;
  89. ULONG DuplicateHandleFlags;
  90. if (Buffer->EventPairClient != NULL &&
  91. Buffer->TargetProcessId == TargetProcessId
  92. ) {
  93. return STATUS_SUCCESS;
  94. }
  95. InitializeObjectAttributes( &ObjectAttributes,
  96. NULL,
  97. 0,
  98. NULL,
  99. NULL
  100. );
  101. DuplicateHandleFlags = DUPLICATE_CLOSE_SOURCE |
  102. DUPLICATE_SAME_ACCESS |
  103. DUPLICATE_SAME_ATTRIBUTES;
  104. if (Buffer->EventPairClient != NULL) {
  105. pOldHandle = &Buffer->EventPairTarget;
  106. }
  107. else {
  108. pOldHandle = NULL;
  109. }
  110. if (Buffer->TargetProcessId != NULL) {
  111. OldTargetClientId.UniqueProcess = Buffer->TargetProcessId;
  112. OldTargetClientId.UniqueThread = 0;
  113. Status = NtOpenProcess( &OldTargetProcess,
  114. PROCESS_ALL_ACCESS,
  115. &ObjectAttributes,
  116. &OldTargetClientId
  117. );
  118. if (!NT_SUCCESS( Status )) {
  119. return Status;
  120. }
  121. }
  122. else {
  123. OldTargetProcess = NtCurrentProcess();
  124. DuplicateHandleFlags &= ~DUPLICATE_CLOSE_SOURCE;
  125. if (pOldHandle != NULL) {
  126. pOldHandle = &Buffer->EventPairClient;
  127. }
  128. }
  129. if (ARGUMENT_PRESENT( TargetProcessId )) {
  130. NewTargetClientId.UniqueProcess = TargetProcessId;
  131. NewTargetClientId.UniqueThread = 0;
  132. Status = NtOpenProcess( &NewTargetProcess,
  133. PROCESS_ALL_ACCESS,
  134. &ObjectAttributes,
  135. &NewTargetClientId
  136. );
  137. if (!NT_SUCCESS( Status )) {
  138. if (OldTargetProcess != NtCurrentProcess()) {
  139. NtClose( OldTargetProcess );
  140. }
  141. return Status;
  142. }
  143. }
  144. else {
  145. NewTargetProcess = NULL;
  146. }
  147. NewHandle = NULL;
  148. if (pOldHandle != NULL) {
  149. Status = NtDuplicateObject( OldTargetProcess,
  150. *pOldHandle,
  151. NewTargetProcess,
  152. &NewHandle,
  153. 0,
  154. 0,
  155. DuplicateHandleFlags
  156. );
  157. if (!NT_SUCCESS( Status )) {
  158. if (OldTargetProcess != NtCurrentProcess()) {
  159. NtClose( OldTargetProcess );
  160. }
  161. if (NewTargetProcess != NULL) {
  162. NtClose( NewTargetProcess );
  163. }
  164. return Status;
  165. }
  166. }
  167. if (OldTargetProcess != NtCurrentProcess()) {
  168. NtUnmapViewOfSection( OldTargetProcess, Buffer->ViewBaseTarget );
  169. }
  170. else {
  171. Buffer->ViewBaseTarget = Buffer->ViewBaseClient;
  172. }
  173. if (NewTargetProcess != NULL) {
  174. Status = NtMapViewOfSection( Buffer->SectionHandleClient,
  175. NewTargetProcess,
  176. &Buffer->ViewBaseTarget,
  177. 0,
  178. 0,
  179. NULL,
  180. &Buffer->ViewSize,
  181. ViewUnmap,
  182. 0,
  183. PAGE_READWRITE
  184. );
  185. if (Status == STATUS_CONFLICTING_ADDRESSES) {
  186. Buffer->ViewBaseTarget = NULL;
  187. Status = NtMapViewOfSection( Buffer->SectionHandleClient,
  188. NewTargetProcess,
  189. &Buffer->ViewBaseTarget,
  190. 0,
  191. 0,
  192. NULL,
  193. &Buffer->ViewSize,
  194. ViewUnmap,
  195. 0,
  196. PAGE_READWRITE
  197. );
  198. }
  199. if (!NT_SUCCESS( Status )) {
  200. if (NewHandle != NULL) {
  201. NtDuplicateObject( NewTargetProcess,
  202. &NewHandle,
  203. NULL,
  204. NULL,
  205. 0,
  206. 0,
  207. DUPLICATE_CLOSE_SOURCE
  208. );
  209. }
  210. return Status;
  211. }
  212. if (ARGUMENT_PRESENT( ReturnedTargetProcessHandle )) {
  213. *ReturnedTargetProcessHandle = NewTargetProcess;
  214. }
  215. else {
  216. NtClose( NewTargetProcess );
  217. }
  218. }
  219. Buffer->EventPairTarget = NewHandle;
  220. Buffer->ViewBaseDelta = (ULONG_PTR)Buffer->ViewBaseClient - (ULONG_PTR)Buffer->ViewBaseTarget;
  221. return STATUS_SUCCESS;
  222. }
  223. PVOID
  224. RtlpCommitQueryDebugInfo(
  225. IN PRTL_DEBUG_INFORMATION Buffer,
  226. IN ULONG Size
  227. )
  228. {
  229. NTSTATUS Status;
  230. PVOID Result;
  231. PVOID CommitBase;
  232. SIZE_T CommitSize;
  233. SIZE_T NeededSize;
  234. Size = (Size + 3) & ~3;
  235. NeededSize = Buffer->OffsetFree + Size;
  236. if (NeededSize > Buffer->CommitSize) {
  237. if (NeededSize >= Buffer->ViewSize) {
  238. return NULL;
  239. }
  240. CommitBase = (PCHAR)Buffer + Buffer->CommitSize;
  241. CommitSize = NeededSize - Buffer->CommitSize;
  242. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  243. &CommitBase,
  244. 0,
  245. &CommitSize,
  246. MEM_COMMIT,
  247. PAGE_READWRITE
  248. );
  249. if (!NT_SUCCESS( Status )) {
  250. return NULL;
  251. }
  252. Buffer->CommitSize += CommitSize;
  253. }
  254. Result = (PCHAR)Buffer + Buffer->OffsetFree;
  255. Buffer->OffsetFree = NeededSize;
  256. return Result;
  257. }
  258. VOID
  259. RtlpDeCommitQueryDebugInfo(
  260. IN PRTL_DEBUG_INFORMATION Buffer,
  261. IN PVOID p,
  262. IN ULONG Size
  263. )
  264. {
  265. Size = (Size + 3) & ~3;
  266. if (p == (PVOID)(Buffer->OffsetFree - Size)) {
  267. Buffer->OffsetFree -= Size;
  268. }
  269. }
  270. NTSYSAPI
  271. PRTL_DEBUG_INFORMATION
  272. NTAPI
  273. RtlCreateQueryDebugBuffer(
  274. IN ULONG MaximumCommit OPTIONAL,
  275. IN BOOLEAN UseEventPair
  276. )
  277. {
  278. NTSTATUS Status;
  279. HANDLE Section;
  280. PRTL_DEBUG_INFORMATION Buffer;
  281. LARGE_INTEGER MaximumSize;
  282. ULONG_PTR ViewSize, CommitSize;
  283. if (!ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)MaximumCommit )) { // Sundown Note: ULONG zero-extended.
  284. MaximumCommit = 4 * 1024 * 1024;
  285. }
  286. MaximumSize.QuadPart = MaximumCommit;
  287. Status = NtCreateSection( &Section,
  288. SECTION_ALL_ACCESS,
  289. NULL,
  290. &MaximumSize,
  291. PAGE_READWRITE,
  292. SEC_RESERVE,
  293. NULL
  294. );
  295. if (!NT_SUCCESS( Status )) {
  296. return NULL;
  297. }
  298. Buffer = NULL;
  299. ViewSize = MaximumCommit;
  300. Status = NtMapViewOfSection( Section,
  301. NtCurrentProcess(),
  302. &Buffer,
  303. 0,
  304. 0,
  305. NULL,
  306. &ViewSize,
  307. ViewUnmap,
  308. 0,
  309. PAGE_READWRITE
  310. );
  311. if (!NT_SUCCESS( Status )) {
  312. NtClose( Section );
  313. return NULL;
  314. }
  315. CommitSize = 1;
  316. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  317. &Buffer,
  318. 0,
  319. &CommitSize,
  320. MEM_COMMIT,
  321. PAGE_READWRITE
  322. );
  323. if (!NT_SUCCESS( Status )) {
  324. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  325. NtClose( Section );
  326. return NULL;
  327. }
  328. if (UseEventPair) {
  329. Status = NtCreateEventPair( &Buffer->EventPairClient,
  330. EVENT_PAIR_ALL_ACCESS,
  331. NULL
  332. );
  333. if (!NT_SUCCESS( Status )) {
  334. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  335. NtClose( Section );
  336. return NULL;
  337. }
  338. }
  339. Buffer->SectionHandleClient = Section;
  340. Buffer->ViewBaseClient = Buffer;
  341. Buffer->OffsetFree = 0;
  342. Buffer->CommitSize = CommitSize;
  343. Buffer->ViewSize = ViewSize;
  344. return Buffer;
  345. }
  346. NTSYSAPI
  347. NTSTATUS
  348. NTAPI
  349. RtlDestroyQueryDebugBuffer(
  350. IN PRTL_DEBUG_INFORMATION Buffer
  351. )
  352. {
  353. NTSTATUS Status;
  354. HANDLE ProcessHandle, ThreadHandle;
  355. THREAD_BASIC_INFORMATION BasicInformation;
  356. SIZE_T BigSize;
  357. RtlpChangeQueryDebugBufferTarget( Buffer, NULL, NULL );
  358. Status = STATUS_SUCCESS;
  359. if (Buffer->TargetThreadHandle != NULL) {
  360. Buffer->EventPairTarget = NULL;
  361. NtSetLowEventPair( Buffer->EventPairClient );
  362. NtClose( Buffer->EventPairClient );
  363. Status = NtWaitForSingleObject( Buffer->TargetThreadHandle,
  364. TRUE,
  365. NULL
  366. );
  367. if (NT_SUCCESS( Status )) {
  368. Status = NtQueryInformationThread( Buffer->TargetThreadHandle,
  369. ThreadBasicInformation,
  370. &BasicInformation,
  371. sizeof( BasicInformation ),
  372. NULL
  373. );
  374. if (NT_SUCCESS( Status )) {
  375. Status = BasicInformation.ExitStatus;
  376. }
  377. }
  378. }
  379. NtClose( Buffer->SectionHandleClient );
  380. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  381. return Status;
  382. }
  383. NTSYSAPI
  384. NTSTATUS
  385. NTAPI
  386. RtlQueryProcessDebugInformation(
  387. IN HANDLE UniqueProcessId,
  388. IN ULONG Flags,
  389. IN OUT PRTL_DEBUG_INFORMATION Buffer
  390. )
  391. {
  392. NTSTATUS Status = STATUS_SUCCESS;
  393. HANDLE ProcessHandle, ThreadHandle;
  394. THREAD_BASIC_INFORMATION BasicInformation;
  395. HANDLE hNiProcess = NULL;
  396. Buffer->Flags = Flags;
  397. if (Buffer->OffsetFree != 0) {
  398. RtlZeroMemory( (Buffer+1), Buffer->OffsetFree - (SIZE_T)sizeof(*Buffer) );
  399. }
  400. Buffer->OffsetFree = sizeof( *Buffer );
  401. //
  402. // Get process handle for noninvasive query if required
  403. //
  404. if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
  405. (Flags & RTL_QUERY_PROCESS_NONINVASIVE) &&
  406. (Flags & ( RTL_QUERY_PROCESS_MODULES |
  407. RTL_QUERY_PROCESS_MODULES32
  408. )
  409. ) &&
  410. !(Flags & ~( RTL_QUERY_PROCESS_MODULES |
  411. RTL_QUERY_PROCESS_MODULES32 |
  412. RTL_QUERY_PROCESS_NONINVASIVE
  413. )
  414. )
  415. ) {
  416. OBJECT_ATTRIBUTES ObjectAttributes;
  417. CLIENT_ID NiProcessId;
  418. InitializeObjectAttributes( &ObjectAttributes,
  419. NULL,
  420. 0,
  421. NULL,
  422. NULL
  423. );
  424. NiProcessId.UniqueProcess = UniqueProcessId;
  425. NiProcessId.UniqueThread = 0;
  426. if (!NT_SUCCESS( NtOpenProcess( &hNiProcess,
  427. PROCESS_ALL_ACCESS,
  428. &ObjectAttributes,
  429. &NiProcessId
  430. )
  431. )
  432. ) {
  433. hNiProcess = NULL;
  434. }
  435. }
  436. if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
  437. !hNiProcess
  438. ) {
  439. //
  440. // Perform remote query
  441. //
  442. ProcessHandle = NULL;
  443. Status = RtlpChangeQueryDebugBufferTarget( Buffer, UniqueProcessId, &ProcessHandle );
  444. if (!NT_SUCCESS( Status )) {
  445. return Status;
  446. }
  447. if (ProcessHandle == NULL) {
  448. waitForDump:
  449. Status = NtSetLowWaitHighEventPair( Buffer->EventPairClient );
  450. } else {
  451. //
  452. // don't let the debugger see this remote thread !
  453. // This is a very ugly but effective way to prevent
  454. // the debugger deadlocking with the target process when calling
  455. // this function.
  456. //
  457. Status = RtlCreateUserThread( ProcessHandle,
  458. NULL,
  459. TRUE,
  460. 0,
  461. 0,
  462. 0,
  463. RtlpQueryProcessDebugInformationRemote,
  464. Buffer->ViewBaseTarget,
  465. &ThreadHandle,
  466. NULL
  467. );
  468. if (NT_SUCCESS( Status )) {
  469. Status = NtSetInformationThread( ThreadHandle,
  470. ThreadHideFromDebugger,
  471. NULL,
  472. 0
  473. );
  474. if ( !NT_SUCCESS(Status) ) {
  475. NtTerminateThread(ThreadHandle,Status);
  476. NtClose(ThreadHandle);
  477. NtClose(ProcessHandle);
  478. return Status;
  479. }
  480. NtResumeThread(ThreadHandle,NULL);
  481. if (Buffer->EventPairClient != NULL) {
  482. Buffer->TargetThreadHandle = ThreadHandle;
  483. Buffer->TargetProcessHandle = ProcessHandle;
  484. goto waitForDump;
  485. }
  486. Status = NtWaitForSingleObject( ThreadHandle,
  487. TRUE,
  488. NULL
  489. );
  490. if (NT_SUCCESS( Status )) {
  491. Status = NtQueryInformationThread( ThreadHandle,
  492. ThreadBasicInformation,
  493. &BasicInformation,
  494. sizeof( BasicInformation ),
  495. NULL
  496. );
  497. if (NT_SUCCESS( Status )) {
  498. Status = BasicInformation.ExitStatus;
  499. }
  500. if (NT_SUCCESS (Status) &&
  501. (Flags&(RTL_QUERY_PROCESS_MODULES|RTL_QUERY_PROCESS_MODULES32)) != 0 &&
  502. Buffer->Modules == NULL) {
  503. Status = STATUS_PROCESS_IS_TERMINATING;
  504. }
  505. }
  506. NtClose( ThreadHandle );
  507. }
  508. NtClose( ProcessHandle );
  509. }
  510. } else {
  511. if (Flags & (RTL_QUERY_PROCESS_MODULES | RTL_QUERY_PROCESS_MODULES32)) {
  512. Status = RtlQueryProcessModuleInformation( hNiProcess, Flags, Buffer );
  513. if (Status != STATUS_SUCCESS) {
  514. goto closeNiProcessAndBreak;
  515. }
  516. }
  517. if (Flags & RTL_QUERY_PROCESS_BACKTRACES) {
  518. Status = RtlQueryProcessBackTraceInformation( Buffer );
  519. if (Status != STATUS_SUCCESS) {
  520. goto closeNiProcessAndBreak;
  521. }
  522. }
  523. if (Flags & RTL_QUERY_PROCESS_LOCKS) {
  524. Status = RtlQueryProcessLockInformation( Buffer );
  525. if (Status != STATUS_SUCCESS) {
  526. goto closeNiProcessAndBreak;
  527. }
  528. }
  529. if (Flags & (RTL_QUERY_PROCESS_HEAP_SUMMARY |
  530. RTL_QUERY_PROCESS_HEAP_TAGS |
  531. RTL_QUERY_PROCESS_HEAP_ENTRIES
  532. )
  533. ) {
  534. Status = RtlQueryProcessHeapInformation( Buffer );
  535. if (Status != STATUS_SUCCESS) {
  536. goto closeNiProcessAndBreak;
  537. }
  538. }
  539. closeNiProcessAndBreak:
  540. if ( hNiProcess ) {
  541. NtClose( hNiProcess );
  542. }
  543. }
  544. return Status;
  545. }
  546. NTSTATUS
  547. LdrQueryProcessModuleInformationEx(
  548. IN HANDLE hProcess OPTIONAL,
  549. IN ULONG_PTR Flags OPTIONAL,
  550. OUT PRTL_PROCESS_MODULES ModuleInformation,
  551. IN ULONG ModuleInformationLength,
  552. OUT PULONG ReturnLength OPTIONAL
  553. );
  554. NTSTATUS
  555. NTAPI
  556. RtlQueryProcessModuleInformation
  557. (
  558. IN HANDLE hProcess OPTIONAL,
  559. IN ULONG Flags,
  560. IN OUT PRTL_DEBUG_INFORMATION Buffer
  561. )
  562. {
  563. NTSTATUS Status;
  564. ULONG RequiredLength;
  565. PRTL_PROCESS_MODULES Modules;
  566. ULONG LdrFlags = (Flags & RTL_QUERY_PROCESS_MODULES32) != 0;
  567. Status = LdrQueryProcessModuleInformationEx( hProcess,
  568. LdrFlags,
  569. NULL,
  570. 0,
  571. &RequiredLength
  572. );
  573. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  574. Modules = RtlpCommitQueryDebugInfo( Buffer, RequiredLength );
  575. if (Modules != NULL) {
  576. Status = LdrQueryProcessModuleInformationEx( hProcess,
  577. LdrFlags,
  578. Modules,
  579. RequiredLength,
  580. &RequiredLength
  581. );
  582. if (NT_SUCCESS( Status )) {
  583. Buffer->Modules = Modules;
  584. return STATUS_SUCCESS;
  585. }
  586. }
  587. }
  588. return STATUS_NO_MEMORY;
  589. }
  590. NTSTATUS
  591. RtlQueryProcessBackTraceInformation(
  592. IN OUT PRTL_DEBUG_INFORMATION Buffer
  593. )
  594. {
  595. #if i386
  596. NTSTATUS Status;
  597. OUT PRTL_PROCESS_BACKTRACES BackTraces;
  598. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  599. PSTACK_TRACE_DATABASE DataBase;
  600. PRTL_STACK_TRACE_ENTRY p, *pp;
  601. ULONG n;
  602. DataBase = RtlpAcquireStackTraceDataBase();
  603. if (DataBase == NULL) {
  604. return STATUS_SUCCESS;
  605. }
  606. BackTraces = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_BACKTRACES, BackTraces ) );
  607. if (BackTraces == NULL) {
  608. return STATUS_NO_MEMORY;
  609. }
  610. DataBase->DumpInProgress = TRUE;
  611. RtlpReleaseStackTraceDataBase();
  612. try {
  613. BackTraces->CommittedMemory = (ULONG)DataBase->CurrentUpperCommitLimit -
  614. (ULONG)DataBase->CommitBase;
  615. BackTraces->ReservedMemory = (ULONG)DataBase->EntryIndexArray -
  616. (ULONG)DataBase->CommitBase;
  617. BackTraces->NumberOfBackTraceLookups = DataBase->NumberOfEntriesLookedUp;
  618. BackTraces->NumberOfBackTraces = DataBase->NumberOfEntriesAdded;
  619. BackTraceInfo = RtlpCommitQueryDebugInfo( Buffer, (sizeof( *BackTraceInfo ) * BackTraces->NumberOfBackTraces) );
  620. if (BackTraceInfo == NULL) {
  621. Status = STATUS_NO_MEMORY;
  622. }
  623. else {
  624. Status = STATUS_SUCCESS;
  625. n = DataBase->NumberOfEntriesAdded;
  626. pp = DataBase->EntryIndexArray;
  627. while (n--) {
  628. p = *--pp;
  629. BackTraceInfo->SymbolicBackTrace = NULL;
  630. BackTraceInfo->TraceCount = p->TraceCount;
  631. BackTraceInfo->Index = p->Index;
  632. BackTraceInfo->Depth = p->Depth;
  633. RtlMoveMemory( BackTraceInfo->BackTrace,
  634. p->BackTrace,
  635. p->Depth * sizeof( PVOID )
  636. );
  637. BackTraceInfo++;
  638. }
  639. }
  640. }
  641. finally {
  642. DataBase->DumpInProgress = FALSE;
  643. }
  644. if (NT_SUCCESS( Status )) {
  645. Buffer->BackTraces = BackTraces;
  646. }
  647. return Status;
  648. #else
  649. return STATUS_SUCCESS;
  650. #endif // i386
  651. }
  652. NTSTATUS
  653. RtlpQueryProcessEnumHeapsRoutine(
  654. PVOID HeapHandle,
  655. PVOID Parameter
  656. )
  657. {
  658. PRTL_DEBUG_INFORMATION Buffer = (PRTL_DEBUG_INFORMATION)Parameter;
  659. PRTL_PROCESS_HEAPS Heaps = Buffer->Heaps;
  660. PHEAP Heap = (PHEAP)HeapHandle;
  661. PRTL_HEAP_INFORMATION HeapInfo;
  662. PHEAP_SEGMENT Segment;
  663. UCHAR SegmentIndex;
  664. HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
  665. if (HeapInfo == NULL) {
  666. return STATUS_NO_MEMORY;
  667. }
  668. HeapInfo->BaseAddress = Heap;
  669. HeapInfo->Flags = Heap->Flags;
  670. HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
  671. HeapInfo->CreatorBackTraceIndex = Heap->AllocatorBackTraceIndex;
  672. SegmentIndex = HEAP_MAXIMUM_SEGMENTS;
  673. while (SegmentIndex--) {
  674. Segment = Heap->Segments[ SegmentIndex ];
  675. if (Segment) {
  676. HeapInfo->BytesCommitted += (Segment->NumberOfPages -
  677. Segment->NumberOfUnCommittedPages
  678. ) * PAGE_SIZE;
  679. }
  680. }
  681. HeapInfo->BytesAllocated = HeapInfo->BytesCommitted -
  682. (Heap->TotalFreeSize << HEAP_GRANULARITY_SHIFT);
  683. Heaps->NumberOfHeaps += 1;
  684. return STATUS_SUCCESS;
  685. }
  686. NTSYSAPI
  687. NTSTATUS
  688. NTAPI
  689. RtlQueryProcessHeapInformation(
  690. IN OUT PRTL_DEBUG_INFORMATION Buffer
  691. )
  692. {
  693. NTSTATUS Status;
  694. PHEAP Heap;
  695. BOOLEAN LockAcquired;
  696. PRTL_PROCESS_HEAPS Heaps;
  697. PRTL_HEAP_INFORMATION HeapInfo;
  698. ULONG NumberOfHeaps;
  699. PVOID *ProcessHeaps;
  700. UCHAR SegmentIndex;
  701. ULONG i, n, TagIndex;
  702. PHEAP_SEGMENT Segment;
  703. PRTL_HEAP_TAG Tags;
  704. PHEAP_PSEUDO_TAG_ENTRY PseudoTags;
  705. PRTL_HEAP_ENTRY Entries;
  706. PHEAP_ENTRY CurrentBlock;
  707. PHEAP_ENTRY_EXTRA ExtraStuff;
  708. PRTL_HEAP_ENTRY p;
  709. PLIST_ENTRY Head, Next;
  710. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  711. ULONG Size;
  712. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
  713. Heaps = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_HEAPS, Heaps ) );
  714. if (Heaps == NULL) {
  715. return STATUS_NO_MEMORY;
  716. }
  717. Buffer->Heaps = Heaps;
  718. Status = RtlEnumProcessHeaps( RtlpQueryProcessEnumHeapsRoutine, Buffer );
  719. if (NT_SUCCESS( Status )) {
  720. if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_TAGS) {
  721. Heap = RtlpGlobalTagHeap;
  722. if (Heap->TagEntries != NULL) {
  723. HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
  724. if (HeapInfo == NULL) {
  725. return STATUS_NO_MEMORY;
  726. }
  727. HeapInfo->BaseAddress = Heap;
  728. HeapInfo->Flags = Heap->Flags;
  729. HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
  730. Heaps->NumberOfHeaps += 1;
  731. }
  732. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  733. HeapInfo = &Heaps->Heaps[ i ];
  734. if (Buffer->SpecificHeap == NULL ||
  735. Buffer->SpecificHeap == HeapInfo->BaseAddress
  736. ) {
  737. Heap = HeapInfo->BaseAddress;
  738. HeapInfo->NumberOfTags = Heap->NextAvailableTagIndex;
  739. n = HeapInfo->NumberOfTags * sizeof( RTL_HEAP_TAG );
  740. if (Heap->PseudoTagEntries != NULL) {
  741. HeapInfo->NumberOfTags += HEAP_MAXIMUM_FREELISTS + 1;
  742. n += (HEAP_MAXIMUM_FREELISTS + 1) * sizeof( RTL_HEAP_TAG );
  743. }
  744. Tags = RtlpCommitQueryDebugInfo( Buffer, n );
  745. if (Tags == NULL) {
  746. Status = STATUS_NO_MEMORY;
  747. break;
  748. }
  749. HeapInfo->Tags = Tags;
  750. if ((PseudoTags = Heap->PseudoTagEntries) != NULL) {
  751. HeapInfo->NumberOfPseudoTags = HEAP_NUMBER_OF_PSEUDO_TAG;
  752. HeapInfo->PseudoTagGranularity = HEAP_GRANULARITY;
  753. for (TagIndex=0; TagIndex<=HEAP_MAXIMUM_FREELISTS; TagIndex++) {
  754. Tags->NumberOfAllocations = PseudoTags->Allocs;
  755. Tags->NumberOfFrees = PseudoTags->Frees;
  756. Tags->BytesAllocated = PseudoTags->Size << HEAP_GRANULARITY_SHIFT;
  757. Tags->TagIndex = (USHORT)(TagIndex | HEAP_PSEUDO_TAG_FLAG);
  758. if (TagIndex == 0) {
  759. swprintf( Tags->TagName, L"Objects>%4u",
  760. HEAP_MAXIMUM_FREELISTS << HEAP_GRANULARITY_SHIFT
  761. );
  762. }
  763. else
  764. if (TagIndex < HEAP_MAXIMUM_FREELISTS) {
  765. swprintf( Tags->TagName, L"Objects=%4u",
  766. TagIndex << HEAP_GRANULARITY_SHIFT
  767. );
  768. }
  769. else {
  770. swprintf( Tags->TagName, L"VirtualAlloc",
  771. TagIndex << HEAP_GRANULARITY_SHIFT
  772. );
  773. }
  774. Tags += 1;
  775. PseudoTags += 1;
  776. }
  777. }
  778. RtlMoveMemory( Tags,
  779. Heap->TagEntries,
  780. Heap->NextAvailableTagIndex * sizeof( RTL_HEAP_TAG )
  781. );
  782. for (TagIndex=0; TagIndex<Heap->NextAvailableTagIndex; TagIndex++) {
  783. Tags->BytesAllocated <<= HEAP_GRANULARITY_SHIFT;
  784. Tags += 1;
  785. }
  786. }
  787. }
  788. }
  789. }
  790. else {
  791. Buffer->Heaps = NULL;
  792. }
  793. if (NT_SUCCESS( Status )) {
  794. if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_ENTRIES) {
  795. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  796. HeapInfo = &Heaps->Heaps[ i ];
  797. Heap = HeapInfo->BaseAddress;
  798. if (Buffer->SpecificHeap == NULL ||
  799. Buffer->SpecificHeap == Heap
  800. ) {
  801. if (!(Heap->Flags & HEAP_NO_SERIALIZE)) {
  802. RtlEnterCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
  803. LockAcquired = TRUE;
  804. }
  805. else {
  806. LockAcquired = FALSE;
  807. }
  808. try {
  809. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  810. Segment = Heap->Segments[ SegmentIndex ];
  811. if (!Segment) {
  812. continue;
  813. }
  814. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  815. if (Entries == NULL) {
  816. Status = STATUS_NO_MEMORY;
  817. break;
  818. }
  819. else
  820. if (HeapInfo->Entries == NULL) {
  821. HeapInfo->Entries = Entries;
  822. }
  823. Entries->Flags = RTL_HEAP_SEGMENT;
  824. Entries->AllocatorBackTraceIndex = Segment->AllocatorBackTraceIndex;
  825. Entries->Size = Segment->NumberOfPages * PAGE_SIZE;
  826. Entries->u.s2.CommittedSize = (Segment->NumberOfPages -
  827. Segment->NumberOfUnCommittedPages
  828. ) * PAGE_SIZE;
  829. Entries->u.s2.FirstBlock = Segment->FirstEntry;
  830. HeapInfo->NumberOfEntries++;
  831. UnCommittedRange = Segment->UnCommittedRanges;
  832. CurrentBlock = Segment->FirstEntry;
  833. while (CurrentBlock < Segment->LastValidEntry) {
  834. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  835. if (Entries == NULL) {
  836. Status = STATUS_NO_MEMORY;
  837. break;
  838. }
  839. Size = CurrentBlock->Size << HEAP_GRANULARITY_SHIFT;
  840. Entries->Size = Size;
  841. HeapInfo->NumberOfEntries++;
  842. if (CurrentBlock->Flags & HEAP_ENTRY_BUSY) {
  843. if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  844. ExtraStuff = (PHEAP_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size - 1);
  845. #if i386
  846. Entries->AllocatorBackTraceIndex = ExtraStuff->AllocatorBackTraceIndex;
  847. #endif // i386
  848. Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
  849. Entries->u.s1.Settable = ExtraStuff->Settable;
  850. Entries->u.s1.Tag = ExtraStuff->TagIndex;
  851. }
  852. else {
  853. Entries->u.s1.Tag = CurrentBlock->SmallTagIndex;
  854. }
  855. Entries->Flags |= RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
  856. }
  857. else
  858. if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  859. PHEAP_FREE_ENTRY_EXTRA FreeExtra;
  860. FreeExtra = (PHEAP_FREE_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size) - 1;
  861. Entries->u.s1.Tag = FreeExtra->TagIndex;
  862. Entries->AllocatorBackTraceIndex = FreeExtra->FreeBackTraceIndex;
  863. }
  864. if (CurrentBlock->Flags & HEAP_ENTRY_LAST_ENTRY) {
  865. CurrentBlock += CurrentBlock->Size;
  866. if (UnCommittedRange == NULL) {
  867. CurrentBlock = Segment->LastValidEntry;
  868. }
  869. else {
  870. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  871. if (Entries == NULL) {
  872. Status = STATUS_NO_MEMORY;
  873. break;
  874. }
  875. Entries->Flags = RTL_HEAP_UNCOMMITTED_RANGE;
  876. Entries->Size = UnCommittedRange->Size;
  877. HeapInfo->NumberOfEntries++;
  878. CurrentBlock = (PHEAP_ENTRY)
  879. ((PCHAR)UnCommittedRange->Address + UnCommittedRange->Size);
  880. UnCommittedRange = UnCommittedRange->Next;
  881. }
  882. }
  883. else {
  884. CurrentBlock += CurrentBlock->Size;
  885. }
  886. }
  887. }
  888. Head = &Heap->VirtualAllocdBlocks;
  889. Next = Head->Flink;
  890. while (Head != Next) {
  891. VirtualAllocBlock = CONTAINING_RECORD( Next, HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
  892. CurrentBlock = &VirtualAllocBlock->BusyBlock;
  893. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  894. if (Entries == NULL) {
  895. Status = STATUS_NO_MEMORY;
  896. break;
  897. }
  898. else
  899. if (HeapInfo->Entries == NULL) {
  900. HeapInfo->Entries = Entries;
  901. }
  902. Entries->Flags = RTL_HEAP_SEGMENT;
  903. Entries->Size = VirtualAllocBlock->ReserveSize;
  904. Entries->u.s2.CommittedSize = VirtualAllocBlock->CommitSize;
  905. Entries->u.s2.FirstBlock = CurrentBlock;
  906. HeapInfo->NumberOfEntries++;
  907. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  908. if (Entries == NULL) {
  909. Status = STATUS_NO_MEMORY;
  910. break;
  911. }
  912. Entries->Size = VirtualAllocBlock->CommitSize;
  913. Entries->Flags = RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
  914. #if i386
  915. Entries->AllocatorBackTraceIndex = VirtualAllocBlock->ExtraStuff.AllocatorBackTraceIndex;
  916. #endif // i386
  917. Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
  918. Entries->u.s1.Settable = VirtualAllocBlock->ExtraStuff.Settable;
  919. Entries->u.s1.Tag = VirtualAllocBlock->ExtraStuff.TagIndex;
  920. HeapInfo->NumberOfEntries++;
  921. Next = Next->Flink;
  922. }
  923. }
  924. finally {
  925. //
  926. // Unlock the heap
  927. //
  928. if (LockAcquired) {
  929. RtlLeaveCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
  930. }
  931. }
  932. }
  933. if (!NT_SUCCESS( Status )) {
  934. break;
  935. }
  936. }
  937. }
  938. }
  939. return Status;
  940. }
  941. NTSYSAPI
  942. NTSTATUS
  943. NTAPI
  944. RtlQueryProcessLockInformation(
  945. IN OUT PRTL_DEBUG_INFORMATION Buffer
  946. )
  947. {
  948. NTSTATUS Status;
  949. PLIST_ENTRY Head, Next;
  950. PRTL_PROCESS_LOCKS Locks;
  951. PRTL_PROCESS_LOCK_INFORMATION LockInfo;
  952. PRTL_CRITICAL_SECTION CriticalSection;
  953. PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
  954. PRTL_RESOURCE Resource;
  955. PRTL_RESOURCE_DEBUG ResourceDebugInfo;
  956. Locks = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_LOCKS, Locks ) );
  957. if (Locks == NULL) {
  958. return STATUS_NO_MEMORY;
  959. }
  960. RtlEnterCriticalSection( &RtlCriticalSectionLock );
  961. Head = &RtlCriticalSectionList;
  962. Next = Head->Flink;
  963. Status = STATUS_SUCCESS;
  964. while (Next != Head) {
  965. DebugInfo = CONTAINING_RECORD( Next,
  966. RTL_CRITICAL_SECTION_DEBUG,
  967. ProcessLocksList
  968. );
  969. LockInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
  970. if (LockInfo == NULL) {
  971. Status = STATUS_NO_MEMORY;
  972. break;
  973. }
  974. CriticalSection = DebugInfo->CriticalSection;
  975. try {
  976. LockInfo->Address = CriticalSection;
  977. LockInfo->Type = DebugInfo->Type;
  978. LockInfo->CreatorBackTraceIndex = DebugInfo->CreatorBackTraceIndex;
  979. if (LockInfo->Type == RTL_CRITSECT_TYPE) {
  980. LockInfo->OwningThread = CriticalSection->OwningThread;
  981. LockInfo->LockCount = CriticalSection->LockCount;
  982. LockInfo->RecursionCount = CriticalSection->RecursionCount;
  983. LockInfo->ContentionCount = DebugInfo->ContentionCount;
  984. LockInfo->EntryCount = DebugInfo->EntryCount;
  985. }
  986. else {
  987. Resource = (PRTL_RESOURCE)CriticalSection;
  988. ResourceDebugInfo = Resource->DebugInfo;
  989. LockInfo->ContentionCount = ResourceDebugInfo->ContentionCount;
  990. LockInfo->OwningThread = Resource->ExclusiveOwnerThread;
  991. LockInfo->LockCount = Resource->NumberOfActive;
  992. LockInfo->NumberOfWaitingShared = Resource->NumberOfWaitingShared;
  993. LockInfo->NumberOfWaitingExclusive = Resource->NumberOfWaitingExclusive;
  994. }
  995. Locks->NumberOfLocks++;
  996. }
  997. except (EXCEPTION_EXECUTE_HANDLER) {
  998. DbgPrint("NTDLL: Lost critical section %08lX\n", CriticalSection);
  999. RtlpDeCommitQueryDebugInfo( Buffer, LockInfo, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
  1000. }
  1001. if (Next == Next->Flink) {
  1002. //
  1003. // Bail if list is circular
  1004. //
  1005. break;
  1006. }
  1007. else {
  1008. Next = Next->Flink;
  1009. }
  1010. }
  1011. RtlLeaveCriticalSection( &RtlCriticalSectionLock );
  1012. if (NT_SUCCESS( Status )) {
  1013. Buffer->Locks = Locks;
  1014. }
  1015. return Status;
  1016. }