Leaked source code of windows server 2003
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.

1443 lines
49 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 "ldrp.h"
  12. #include <ntos.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. //
  18. // Define the offset from the real control data to the copy thats mapped into target processes.
  19. // We need to copies so the target process can't corrupt the information.
  20. //
  21. #define CONTROL_OFFSET (0x10000)
  22. #define CONTROL_TO_FAKE(Buffer) ((PRTL_DEBUG_INFORMATION)((PUCHAR)(Buffer) + CONTROL_OFFSET))
  23. #define FAKE_TO_CONTROL(Buffer) ((PRTL_DEBUG_INFORMATION)((PUCHAR)(Buffer) - CONTROL_OFFSET))
  24. NTSYSAPI
  25. NTSTATUS
  26. NTAPI
  27. RtlpQueryProcessDebugInformationRemote(
  28. IN OUT PRTL_DEBUG_INFORMATION Buffer
  29. )
  30. /*++
  31. Routine Description:
  32. This is the target routine for a remote query. It runds in the context of an injected thread.
  33. If event pairs are used then this code loops repeatedly as an optimization.
  34. Arguments:
  35. Buffer - Query buffer to fill out with the query results
  36. Return Value:
  37. NTSTATUS - Status of call
  38. --*/
  39. {
  40. NTSTATUS Status, Status1;
  41. ULONG i;
  42. ULONG_PTR Delta;
  43. PRTL_PROCESS_HEAPS Heaps;
  44. PRTL_HEAP_INFORMATION HeapInfo;
  45. HANDLE EventPairTarget;
  46. EventPairTarget = Buffer->EventPairTarget;
  47. if (EventPairTarget != NULL) {
  48. Status = NtWaitLowEventPair (EventPairTarget);
  49. } else {
  50. Status = STATUS_SUCCESS;
  51. }
  52. while (NT_SUCCESS (Status)) {
  53. Status = RtlQueryProcessDebugInformation (NtCurrentTeb()->ClientId.UniqueProcess,
  54. Buffer->Flags,
  55. Buffer);
  56. if (NT_SUCCESS (Status)) {
  57. Delta = Buffer->ViewBaseDelta;
  58. if (Delta) {
  59. //
  60. // Need to relocate buffer pointers back to client addresses
  61. //
  62. AdjustPointer (PRTL_PROCESS_MODULES, Buffer->Modules, Delta);
  63. AdjustPointer (PRTL_PROCESS_BACKTRACES, Buffer->BackTraces, Delta);
  64. Heaps = AdjustPointer (PRTL_PROCESS_HEAPS, Buffer->Heaps, Delta);
  65. if (Heaps != NULL) {
  66. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  67. HeapInfo = &Heaps->Heaps[ i ];
  68. AdjustPointer (PRTL_HEAP_TAG, HeapInfo->Tags, Delta);
  69. AdjustPointer (PRTL_HEAP_ENTRY, HeapInfo->Entries, Delta);
  70. }
  71. }
  72. AdjustPointer (PRTL_PROCESS_LOCKS, Buffer->Locks, Delta);
  73. }
  74. }
  75. //
  76. // If we were supposed to be a one shot then exit now.
  77. //
  78. if (EventPairTarget == NULL) {
  79. //
  80. // If no event pair handle, then exit loop and terminate
  81. //
  82. break;
  83. }
  84. Status = NtSetHighWaitLowEventPair (EventPairTarget);
  85. //
  86. // The client side will clear this variable to signal we should exit
  87. //
  88. if (Buffer->EventPairTarget == NULL) {
  89. //
  90. // If no event pair handle, then exit loop and terminate
  91. //
  92. break;
  93. }
  94. }
  95. //
  96. // All done with buffer, remove from our address space
  97. // then terminate ourselves so client wakes up.
  98. //
  99. Buffer->ViewBaseTarget = NULL;
  100. Status1 = NtUnmapViewOfSection (NtCurrentProcess(), Buffer);
  101. ASSERT (NT_SUCCESS (Status1));
  102. RtlExitUserThread (Status);
  103. //
  104. // NEVER REACHED.
  105. //
  106. }
  107. NTSTATUS
  108. RtlpChangeQueryDebugBufferTarget(
  109. IN PRTL_DEBUG_INFORMATION Buffer,
  110. IN HANDLE TargetProcessId,
  111. OUT PHANDLE ReturnedTargetProcessHandle OPTIONAL
  112. )
  113. /*++
  114. Routine Description:
  115. This routine changes the target process being queried. If the current target is set then we
  116. cleanup any state assocuated with this query. If we are using event pairs then we causes the
  117. cached thread to exit the target.
  118. Arguments:
  119. Buffer - Query buffer to be assigned and deassigned from the processes.
  120. TargetProcessId - New target to be queueried. If NULL then just clear current context
  121. ReturnedProcessHandle - OPTIONAL, If present receives the process handle of the new target
  122. if there is one.
  123. Return Value:
  124. NTSTATUS - Status of call
  125. --*/
  126. {
  127. NTSTATUS Status, Status1;
  128. CLIENT_ID OldTargetClientId, NewTargetClientId;
  129. OBJECT_ATTRIBUTES ObjectAttributes;
  130. HANDLE OldTargetProcess, NewTargetProcess, NewHandle;
  131. PRTL_DEBUG_INFORMATION TargetBuffer;
  132. LARGE_INTEGER SectionOffset;
  133. HANDLE EventPairTarget = NULL;
  134. TargetBuffer = CONTROL_TO_FAKE (Buffer);
  135. if (Buffer->EventPairClient != NULL &&
  136. Buffer->TargetProcessId == TargetProcessId) {
  137. return STATUS_SUCCESS;
  138. }
  139. if (Buffer->TargetThreadHandle != NULL) {
  140. EventPairTarget = Buffer->EventPairTarget;
  141. TargetBuffer->EventPairTarget = NULL;
  142. Buffer->EventPairTarget = NULL;
  143. if (Buffer->EventPairClient != NULL) {
  144. Status = NtSetLowEventPair (Buffer->EventPairClient);
  145. ASSERT (NT_SUCCESS (Status));
  146. }
  147. Status = NtWaitForSingleObject (Buffer->TargetThreadHandle,
  148. TRUE,
  149. NULL);
  150. Status = NtClose (Buffer->TargetThreadHandle);
  151. Buffer->TargetThreadHandle = NULL;
  152. ASSERT (NT_SUCCESS (Status));
  153. Status = NtClose (Buffer->TargetProcessHandle);
  154. Buffer->TargetProcessHandle = NULL;
  155. ASSERT (NT_SUCCESS (Status));
  156. }
  157. InitializeObjectAttributes( &ObjectAttributes,
  158. NULL,
  159. 0,
  160. NULL,
  161. NULL
  162. );
  163. if (Buffer->TargetProcessId != NULL) {
  164. OldTargetClientId.UniqueProcess = Buffer->TargetProcessId;
  165. OldTargetClientId.UniqueThread = 0;
  166. Status = NtOpenProcess (&OldTargetProcess,
  167. PROCESS_ALL_ACCESS,
  168. &ObjectAttributes,
  169. &OldTargetClientId);
  170. if (!NT_SUCCESS (Status)) {
  171. return Status;
  172. }
  173. } else {
  174. OldTargetProcess = NtCurrentProcess ();
  175. }
  176. if (ARGUMENT_PRESENT( TargetProcessId )) {
  177. NewTargetClientId.UniqueProcess = TargetProcessId;
  178. NewTargetClientId.UniqueThread = 0;
  179. Status = NtOpenProcess( &NewTargetProcess,
  180. PROCESS_ALL_ACCESS,
  181. &ObjectAttributes,
  182. &NewTargetClientId
  183. );
  184. if (!NT_SUCCESS( Status )) {
  185. if (EventPairTarget != NULL) {
  186. Status = NtDuplicateObject (OldTargetProcess,
  187. EventPairTarget,
  188. NULL,
  189. NULL,
  190. 0,
  191. 0,
  192. DUPLICATE_CLOSE_SOURCE);
  193. //
  194. // The target process could have closed the handle to cause us problems.
  195. // We ignore this error as the target is only damaging itself.
  196. //
  197. }
  198. if (OldTargetProcess != NtCurrentProcess()) {
  199. Status1 = NtClose (OldTargetProcess);
  200. ASSERT (NT_SUCCESS (Status1));
  201. }
  202. return Status;
  203. }
  204. } else {
  205. NewTargetProcess = NULL;
  206. }
  207. NewHandle = NULL;
  208. if (Buffer->EventPairClient) {
  209. if (EventPairTarget != NULL) {
  210. Status = NtDuplicateObject (OldTargetProcess,
  211. EventPairTarget,
  212. NULL,
  213. NULL,
  214. 0,
  215. 0,
  216. DUPLICATE_CLOSE_SOURCE);
  217. //
  218. // The target process could have closed the handle to cause us problems.
  219. // We ignore this error as the target is only damaging itself.
  220. //
  221. }
  222. if (NewTargetProcess != NULL) {
  223. Status = NtDuplicateObject (NtCurrentProcess (),
  224. Buffer->EventPairClient,
  225. NewTargetProcess,
  226. &NewHandle,
  227. 0,
  228. 0,
  229. DUPLICATE_SAME_ACCESS);
  230. if (!NT_SUCCESS (Status)) {
  231. if (OldTargetProcess != NtCurrentProcess()) {
  232. Status1 = NtClose (OldTargetProcess);
  233. ASSERT (NT_SUCCESS (Status1));
  234. }
  235. NtClose (NewTargetProcess);
  236. return Status;
  237. }
  238. }
  239. }
  240. if (OldTargetProcess != NtCurrentProcess()) {
  241. if (TargetBuffer->ViewBaseTarget != NULL) {
  242. Status1 = NtUnmapViewOfSection (OldTargetProcess, TargetBuffer->ViewBaseTarget);
  243. TargetBuffer->ViewBaseTarget = NULL;
  244. }
  245. Status1 = NtClose (OldTargetProcess);
  246. ASSERT (NT_SUCCESS (Status1));
  247. } else {
  248. Buffer->ViewBaseTarget = Buffer->ViewBaseClient;
  249. }
  250. SectionOffset.QuadPart = CONTROL_OFFSET;
  251. if (NewTargetProcess != NULL) {
  252. Status = NtMapViewOfSection( Buffer->SectionHandleClient,
  253. NewTargetProcess,
  254. &Buffer->ViewBaseTarget,
  255. 0,
  256. 0,
  257. &SectionOffset,
  258. &Buffer->ViewSize,
  259. ViewUnmap,
  260. 0,
  261. PAGE_READWRITE
  262. );
  263. if (Status == STATUS_CONFLICTING_ADDRESSES) {
  264. Buffer->ViewBaseTarget = NULL;
  265. Status = NtMapViewOfSection( Buffer->SectionHandleClient,
  266. NewTargetProcess,
  267. &Buffer->ViewBaseTarget,
  268. 0,
  269. 0,
  270. &SectionOffset,
  271. &Buffer->ViewSize,
  272. ViewUnmap,
  273. 0,
  274. PAGE_READWRITE
  275. );
  276. }
  277. if (!NT_SUCCESS( Status )) {
  278. if (NewHandle != NULL) {
  279. NtDuplicateObject (NewTargetProcess,
  280. &NewHandle,
  281. NULL,
  282. NULL,
  283. 0,
  284. 0,
  285. DUPLICATE_CLOSE_SOURCE);
  286. }
  287. NtClose( NewTargetProcess );
  288. return Status;
  289. }
  290. if (ARGUMENT_PRESENT( ReturnedTargetProcessHandle )) {
  291. *ReturnedTargetProcessHandle = NewTargetProcess;
  292. } else {
  293. Status = NtClose (NewTargetProcess);
  294. ASSERT (NT_SUCCESS (Status));
  295. }
  296. }
  297. Buffer->EventPairTarget = NewHandle;
  298. Buffer->ViewBaseDelta = (ULONG_PTR)Buffer->ViewBaseClient - (ULONG_PTR)Buffer->ViewBaseTarget;
  299. Buffer->TargetProcessId = TargetProcessId;
  300. *TargetBuffer = *Buffer;
  301. return STATUS_SUCCESS;
  302. }
  303. PVOID
  304. RtlpCommitQueryDebugInfo(
  305. IN PRTL_DEBUG_INFORMATION Buffer,
  306. IN ULONG Size
  307. )
  308. /*++
  309. Routine Description:
  310. This routine commits a range of memory in the buffer and returns its address.
  311. Arguments:
  312. Buffer - Query buffer to have space allocated to.
  313. If there is not enough commited space then we expand.
  314. Size - Size of data to return
  315. Return Value:
  316. PVOID - Pointer to the commited space.
  317. --*/
  318. {
  319. NTSTATUS Status;
  320. PVOID Result;
  321. PVOID CommitBase;
  322. SIZE_T CommitSize;
  323. SIZE_T NeededSize;
  324. if (Size > (MAXULONG - sizeof(PVOID) + 1)) {
  325. return NULL;
  326. }
  327. Size = (Size + sizeof (PVOID) - 1) & ~(sizeof (PVOID) - 1);
  328. NeededSize = Buffer->OffsetFree + Size;
  329. if (NeededSize > Buffer->CommitSize) {
  330. if (NeededSize >= Buffer->ViewSize) {
  331. return NULL;
  332. }
  333. CommitBase = (PCHAR)Buffer + Buffer->CommitSize;
  334. CommitSize = NeededSize - Buffer->CommitSize;
  335. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  336. &CommitBase,
  337. 0,
  338. &CommitSize,
  339. MEM_COMMIT,
  340. PAGE_READWRITE
  341. );
  342. if (!NT_SUCCESS( Status )) {
  343. return NULL;
  344. }
  345. Buffer->CommitSize += CommitSize;
  346. }
  347. Result = (PCHAR)Buffer + Buffer->OffsetFree;
  348. Buffer->OffsetFree = NeededSize;
  349. return Result;
  350. }
  351. VOID
  352. RtlpDeCommitQueryDebugInfo(
  353. IN PRTL_DEBUG_INFORMATION Buffer,
  354. IN PVOID p,
  355. IN ULONG Size
  356. )
  357. /*++
  358. Routine Description:
  359. This routine returns a range of previously commited data to the buffer.
  360. Arguments:
  361. Buffer - Query buffer to have space returned to.
  362. Size - Size of data to return
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. if (Size > (MAXULONG - sizeof(PVOID) + 1)) {
  368. return;
  369. }
  370. Size = (Size + sizeof(PVOID) - 1) & ~(sizeof (PVOID) - 1);
  371. if (p == (PVOID)(Buffer->OffsetFree - Size)) {
  372. Buffer->OffsetFree -= Size;
  373. }
  374. }
  375. NTSYSAPI
  376. PRTL_DEBUG_INFORMATION
  377. NTAPI
  378. RtlCreateQueryDebugBuffer(
  379. IN ULONG MaximumCommit OPTIONAL,
  380. IN BOOLEAN UseEventPair
  381. )
  382. /*++
  383. Routine Description:
  384. Creates a new query buffer to allow a remote of local query to be done.
  385. Arguments:
  386. MaximumCommit - Largest query buffer size allowed
  387. UseEventPair - If TRUE the codes caches a single thread in the target to make repeated queries fast.
  388. Return Value:
  389. PRTL_DEBUG_INFORMATION - NULL on failure, non-NULL otherwise.
  390. --*/
  391. {
  392. NTSTATUS Status;
  393. HANDLE Section;
  394. PRTL_DEBUG_INFORMATION Buffer, ReturnBuffer;
  395. LARGE_INTEGER MaximumSize;
  396. ULONG_PTR ViewSize, CommitSize;
  397. if (!ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)MaximumCommit )) { // Sundown Note: ULONG zero-extended.
  398. MaximumCommit = 4 * 1024 * 1024;
  399. }
  400. ViewSize = MaximumCommit + CONTROL_OFFSET;
  401. MaximumSize.QuadPart = ViewSize;
  402. Status = NtCreateSection( &Section,
  403. SECTION_ALL_ACCESS,
  404. NULL,
  405. &MaximumSize,
  406. PAGE_READWRITE,
  407. SEC_RESERVE,
  408. NULL
  409. );
  410. if (!NT_SUCCESS( Status )) {
  411. return NULL;
  412. }
  413. Buffer = NULL;
  414. Status = NtMapViewOfSection( Section,
  415. NtCurrentProcess(),
  416. &Buffer,
  417. 0,
  418. 0,
  419. NULL,
  420. &ViewSize,
  421. ViewUnmap,
  422. 0,
  423. PAGE_READWRITE
  424. );
  425. if (!NT_SUCCESS (Status)) {
  426. NtClose (Section);
  427. return NULL;
  428. }
  429. CommitSize = 1 + CONTROL_OFFSET;
  430. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  431. &Buffer,
  432. 0,
  433. &CommitSize,
  434. MEM_COMMIT,
  435. PAGE_READWRITE
  436. );
  437. if (!NT_SUCCESS( Status )) {
  438. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  439. NtClose( Section );
  440. return NULL;
  441. }
  442. if (UseEventPair) {
  443. Status = NtCreateEventPair( &Buffer->EventPairClient,
  444. EVENT_PAIR_ALL_ACCESS,
  445. NULL
  446. );
  447. if (!NT_SUCCESS( Status )) {
  448. NtFreeVirtualMemory( NtCurrentProcess(), &Buffer, &CommitSize,
  449. MEM_RELEASE );
  450. NtUnmapViewOfSection( NtCurrentProcess(), Buffer );
  451. NtClose( Section );
  452. return NULL;
  453. }
  454. }
  455. ReturnBuffer = CONTROL_TO_FAKE (Buffer);
  456. Buffer->SectionHandleClient = Section;
  457. Buffer->ViewBaseClient = ReturnBuffer;
  458. Buffer->OffsetFree = sizeof (RTL_DEBUG_INFORMATION);
  459. Buffer->CommitSize = CommitSize - CONTROL_OFFSET;
  460. Buffer->ViewSize = ViewSize - CONTROL_OFFSET;
  461. *ReturnBuffer = *Buffer;
  462. return ReturnBuffer;
  463. }
  464. NTSYSAPI
  465. NTSTATUS
  466. NTAPI
  467. RtlDestroyQueryDebugBuffer(
  468. IN PRTL_DEBUG_INFORMATION Buffer
  469. )
  470. /*++
  471. Routine Description:
  472. Destroys a previously created buffer that was returned by RtlCreateQueryDebugBuffer
  473. Arguments:
  474. Buffer - Buffer pointer obtained from RtlCreateQueryDebugBuffer
  475. Return Value:
  476. NTSTATUS - Status of operation.
  477. --*/
  478. {
  479. NTSTATUS Status;
  480. PRTL_DEBUG_INFORMATION RealBuffer;
  481. RealBuffer = FAKE_TO_CONTROL (Buffer);
  482. RtlpChangeQueryDebugBufferTarget (RealBuffer, NULL, NULL);
  483. if (RealBuffer->EventPairClient != NULL) {
  484. Status = NtClose (RealBuffer->EventPairClient);
  485. ASSERT (NT_SUCCESS (Status));
  486. }
  487. Status = NtClose (RealBuffer->SectionHandleClient);
  488. ASSERT (NT_SUCCESS (Status));
  489. Status = NtUnmapViewOfSection (NtCurrentProcess(), RealBuffer);
  490. ASSERT (NT_SUCCESS (Status));
  491. return STATUS_SUCCESS;
  492. }
  493. NTSYSAPI
  494. NTSTATUS
  495. NTAPI
  496. RtlQueryProcessDebugInformation(
  497. IN HANDLE UniqueProcessId,
  498. IN ULONG Flags,
  499. IN OUT PRTL_DEBUG_INFORMATION Buffer
  500. )
  501. /*++
  502. Routine Description:
  503. Queries the current or a remote process for the specified debug information
  504. Arguments:
  505. UniqueProcessId - ProcessId of process to query
  506. Flags - Flags mask describing what to query
  507. Buffer - Buffer pointer obtained from RtlCreateQueryDebugBuffer
  508. Return Value:
  509. NTSTATUS - Status of operation.
  510. --*/
  511. {
  512. NTSTATUS Status = STATUS_SUCCESS;
  513. HANDLE ProcessHandle, ThreadHandle;
  514. THREAD_BASIC_INFORMATION BasicInformation;
  515. PRTL_DEBUG_INFORMATION RealBuffer;
  516. HANDLE hNiProcess = NULL;
  517. Buffer->Flags = Flags;
  518. if (Buffer->OffsetFree != 0) {
  519. RtlZeroMemory( (Buffer+1), Buffer->OffsetFree - (SIZE_T)sizeof(*Buffer) );
  520. }
  521. Buffer->OffsetFree = sizeof( *Buffer );
  522. //
  523. // Get process handle for noninvasive query if required
  524. //
  525. if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
  526. (Flags & RTL_QUERY_PROCESS_NONINVASIVE) &&
  527. (Flags & ( RTL_QUERY_PROCESS_MODULES |
  528. RTL_QUERY_PROCESS_MODULES32
  529. )
  530. ) &&
  531. !(Flags & ~( RTL_QUERY_PROCESS_MODULES |
  532. RTL_QUERY_PROCESS_MODULES32 |
  533. RTL_QUERY_PROCESS_NONINVASIVE
  534. )
  535. )
  536. ) {
  537. OBJECT_ATTRIBUTES ObjectAttributes;
  538. CLIENT_ID NiProcessId;
  539. InitializeObjectAttributes( &ObjectAttributes,
  540. NULL,
  541. 0,
  542. NULL,
  543. NULL
  544. );
  545. NiProcessId.UniqueProcess = UniqueProcessId;
  546. NiProcessId.UniqueThread = 0;
  547. if (!NT_SUCCESS( NtOpenProcess( &hNiProcess,
  548. PROCESS_ALL_ACCESS,
  549. &ObjectAttributes,
  550. &NiProcessId
  551. )
  552. )
  553. ) {
  554. hNiProcess = NULL;
  555. }
  556. }
  557. if ( (NtCurrentTeb()->ClientId.UniqueProcess != UniqueProcessId) &&
  558. !hNiProcess) {
  559. RealBuffer = FAKE_TO_CONTROL (Buffer);
  560. RealBuffer->Flags = Flags;
  561. RealBuffer->OffsetFree = sizeof (*Buffer);
  562. //
  563. // Perform remote query
  564. //
  565. ProcessHandle = NULL;
  566. Status = RtlpChangeQueryDebugBufferTarget (RealBuffer, UniqueProcessId, &ProcessHandle);
  567. if (!NT_SUCCESS( Status )) {
  568. return Status;
  569. }
  570. if (ProcessHandle == NULL) {
  571. waitForDump:
  572. Status = NtSetLowWaitHighEventPair( RealBuffer->EventPairClient );
  573. } else {
  574. //
  575. // don't let the debugger see this remote thread !
  576. // This is a very ugly but effective way to prevent
  577. // the debugger deadlocking with the target process when calling
  578. // this function.
  579. //
  580. Status = RtlCreateUserThread( ProcessHandle,
  581. NULL,
  582. TRUE,
  583. 0,
  584. 0,
  585. 0,
  586. RtlpQueryProcessDebugInformationRemote,
  587. RealBuffer->ViewBaseTarget,
  588. &ThreadHandle,
  589. NULL
  590. );
  591. if (NT_SUCCESS( Status )) {
  592. Status = NtSetInformationThread( ThreadHandle,
  593. ThreadHideFromDebugger,
  594. NULL,
  595. 0
  596. );
  597. if ( !NT_SUCCESS(Status) ) {
  598. NtTerminateThread(ThreadHandle,Status);
  599. NtClose(ThreadHandle);
  600. NtClose(ProcessHandle);
  601. return Status;
  602. }
  603. NtResumeThread(ThreadHandle,NULL);
  604. if (RealBuffer->EventPairClient != NULL) {
  605. RealBuffer->TargetThreadHandle = ThreadHandle;
  606. RealBuffer->TargetProcessHandle = ProcessHandle;
  607. goto waitForDump;
  608. }
  609. Status = NtWaitForSingleObject( ThreadHandle,
  610. TRUE,
  611. NULL
  612. );
  613. if (NT_SUCCESS( Status )) {
  614. Status = NtQueryInformationThread( ThreadHandle,
  615. ThreadBasicInformation,
  616. &BasicInformation,
  617. sizeof( BasicInformation ),
  618. NULL
  619. );
  620. if (NT_SUCCESS( Status )) {
  621. Status = BasicInformation.ExitStatus;
  622. }
  623. if (NT_SUCCESS (Status) &&
  624. (Flags&(RTL_QUERY_PROCESS_MODULES|RTL_QUERY_PROCESS_MODULES32)) != 0 &&
  625. Buffer->Modules == NULL) {
  626. Status = STATUS_PROCESS_IS_TERMINATING;
  627. }
  628. }
  629. NtClose( ThreadHandle );
  630. }
  631. NtClose( ProcessHandle );
  632. }
  633. } else {
  634. if (Flags & (RTL_QUERY_PROCESS_MODULES | RTL_QUERY_PROCESS_MODULES32)) {
  635. Status = RtlQueryProcessModuleInformation( hNiProcess, Flags, Buffer );
  636. if (Status != STATUS_SUCCESS) {
  637. goto closeNiProcessAndBreak;
  638. }
  639. }
  640. if (Flags & RTL_QUERY_PROCESS_BACKTRACES) {
  641. Status = RtlQueryProcessBackTraceInformation( Buffer );
  642. if (Status != STATUS_SUCCESS) {
  643. goto closeNiProcessAndBreak;
  644. }
  645. }
  646. if (Flags & RTL_QUERY_PROCESS_LOCKS) {
  647. Status = RtlQueryProcessLockInformation( Buffer );
  648. if (Status != STATUS_SUCCESS) {
  649. goto closeNiProcessAndBreak;
  650. }
  651. }
  652. if (Flags & (RTL_QUERY_PROCESS_HEAP_SUMMARY |
  653. RTL_QUERY_PROCESS_HEAP_TAGS |
  654. RTL_QUERY_PROCESS_HEAP_ENTRIES
  655. )
  656. ) {
  657. Status = RtlQueryProcessHeapInformation( Buffer );
  658. if (Status != STATUS_SUCCESS) {
  659. goto closeNiProcessAndBreak;
  660. }
  661. }
  662. closeNiProcessAndBreak:
  663. if ( hNiProcess ) {
  664. NtClose( hNiProcess );
  665. }
  666. }
  667. return Status;
  668. }
  669. NTSTATUS
  670. LdrQueryProcessModuleInformationEx(
  671. IN HANDLE hProcess OPTIONAL,
  672. IN ULONG_PTR Flags OPTIONAL,
  673. OUT PRTL_PROCESS_MODULES ModuleInformation,
  674. IN ULONG ModuleInformationLength,
  675. OUT PULONG ReturnLength OPTIONAL
  676. );
  677. NTSTATUS
  678. NTAPI
  679. RtlQueryProcessModuleInformation
  680. (
  681. IN HANDLE hProcess OPTIONAL,
  682. IN ULONG Flags,
  683. IN OUT PRTL_DEBUG_INFORMATION Buffer
  684. )
  685. /*++
  686. Routine Description:
  687. Queries the current or a remote process for loaded module information
  688. Arguments:
  689. hProcess - Handle to the process being queuried
  690. Flags - Flags mask describing what to query
  691. Buffer - Buffer pointer obtained from RtlCreateQueryDebugBuffer
  692. Return Value:
  693. NTSTATUS - Status of operation.
  694. --*/
  695. {
  696. NTSTATUS Status;
  697. ULONG RequiredLength, BufferSize;
  698. PRTL_PROCESS_MODULES Modules;
  699. ULONG LdrFlags = (Flags & RTL_QUERY_PROCESS_MODULES32) != 0;
  700. Status = LdrQueryProcessModuleInformationEx( hProcess,
  701. LdrFlags,
  702. NULL,
  703. 0,
  704. &BufferSize
  705. );
  706. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  707. Modules = RtlpCommitQueryDebugInfo( Buffer, BufferSize );
  708. if (Modules != NULL) {
  709. RtlZeroMemory( Modules, BufferSize );
  710. Status = LdrQueryProcessModuleInformationEx( hProcess,
  711. LdrFlags,
  712. Modules,
  713. BufferSize,
  714. &RequiredLength
  715. );
  716. if (NT_SUCCESS( Status )) {
  717. Buffer->Modules = Modules;
  718. return STATUS_SUCCESS;
  719. }
  720. RtlpDeCommitQueryDebugInfo( Buffer, Modules, BufferSize );
  721. }
  722. else {
  723. Status = STATUS_NO_MEMORY;
  724. }
  725. }
  726. return Status;
  727. }
  728. NTSTATUS
  729. RtlQueryProcessBackTraceInformation(
  730. IN OUT PRTL_DEBUG_INFORMATION Buffer
  731. )
  732. /*++
  733. Routine Description:
  734. Queries the current process for back trace information
  735. Arguments:
  736. Buffer - Buffer pointer obtained from RtlCreateQueryDebugBuffer
  737. Return Value:
  738. NTSTATUS - Status of operation.
  739. --*/
  740. {
  741. #if i386
  742. NTSTATUS Status;
  743. OUT PRTL_PROCESS_BACKTRACES BackTraces;
  744. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  745. PSTACK_TRACE_DATABASE DataBase;
  746. PRTL_STACK_TRACE_ENTRY p, *pp;
  747. ULONG n;
  748. DataBase = RtlpAcquireStackTraceDataBase();
  749. if (DataBase == NULL) {
  750. return STATUS_SUCCESS;
  751. }
  752. BackTraces = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_BACKTRACES, BackTraces ) );
  753. if (BackTraces == NULL) {
  754. return STATUS_NO_MEMORY;
  755. }
  756. DataBase->DumpInProgress = TRUE;
  757. RtlpReleaseStackTraceDataBase();
  758. Status = STATUS_ACCESS_VIOLATION;
  759. try {
  760. BackTraces->CommittedMemory = (ULONG)DataBase->CurrentUpperCommitLimit -
  761. (ULONG)DataBase->CommitBase;
  762. BackTraces->ReservedMemory = (ULONG)DataBase->EntryIndexArray -
  763. (ULONG)DataBase->CommitBase;
  764. BackTraces->NumberOfBackTraceLookups = DataBase->NumberOfEntriesLookedUp;
  765. BackTraces->NumberOfBackTraces = DataBase->NumberOfEntriesAdded;
  766. BackTraceInfo = RtlpCommitQueryDebugInfo( Buffer, (sizeof( *BackTraceInfo ) * BackTraces->NumberOfBackTraces) );
  767. if (BackTraceInfo == NULL) {
  768. Status = STATUS_NO_MEMORY;
  769. RtlpDeCommitQueryDebugInfo(
  770. Buffer,
  771. BackTraces,
  772. FIELD_OFFSET( RTL_PROCESS_BACKTRACES, BackTraces )
  773. );
  774. }
  775. else {
  776. Status = STATUS_SUCCESS;
  777. n = DataBase->NumberOfEntriesAdded;
  778. pp = DataBase->EntryIndexArray;
  779. while (n--) {
  780. p = *--pp;
  781. BackTraceInfo->SymbolicBackTrace = NULL;
  782. BackTraceInfo->TraceCount = p->TraceCount;
  783. BackTraceInfo->Index = p->Index;
  784. BackTraceInfo->Depth = p->Depth;
  785. RtlMoveMemory( BackTraceInfo->BackTrace,
  786. p->BackTrace,
  787. p->Depth * sizeof( PVOID )
  788. );
  789. BackTraceInfo++;
  790. }
  791. }
  792. }
  793. finally {
  794. DataBase->DumpInProgress = FALSE;
  795. }
  796. if (NT_SUCCESS( Status )) {
  797. Buffer->BackTraces = BackTraces;
  798. }
  799. return Status;
  800. #else
  801. UNREFERENCED_PARAMETER (Buffer);
  802. return STATUS_SUCCESS;
  803. #endif // i386
  804. }
  805. NTSTATUS
  806. RtlpQueryProcessEnumHeapsRoutine(
  807. PVOID HeapHandle,
  808. PVOID Parameter
  809. )
  810. {
  811. PRTL_DEBUG_INFORMATION Buffer = (PRTL_DEBUG_INFORMATION)Parameter;
  812. PRTL_PROCESS_HEAPS Heaps = Buffer->Heaps;
  813. PHEAP Heap = (PHEAP)HeapHandle;
  814. PRTL_HEAP_INFORMATION HeapInfo;
  815. PHEAP_SEGMENT Segment;
  816. UCHAR SegmentIndex;
  817. //
  818. // NOTICE-2002/03/24-ELi
  819. // This function assumes that HeapInfo is allocated immediately following
  820. // the Buffer->Heaps allocation. Therefore, HeapInfo is not leaked.
  821. //
  822. HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
  823. if (HeapInfo == NULL) {
  824. return STATUS_NO_MEMORY;
  825. }
  826. RtlZeroMemory( HeapInfo, sizeof( *HeapInfo ) );
  827. HeapInfo->BaseAddress = Heap;
  828. HeapInfo->Flags = Heap->Flags;
  829. HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
  830. HeapInfo->CreatorBackTraceIndex = Heap->AllocatorBackTraceIndex;
  831. SegmentIndex = HEAP_MAXIMUM_SEGMENTS;
  832. while (SegmentIndex--) {
  833. Segment = Heap->Segments[ SegmentIndex ];
  834. if (Segment) {
  835. HeapInfo->BytesCommitted += (Segment->NumberOfPages -
  836. Segment->NumberOfUnCommittedPages
  837. ) * PAGE_SIZE;
  838. }
  839. }
  840. HeapInfo->BytesAllocated = HeapInfo->BytesCommitted -
  841. (Heap->TotalFreeSize << HEAP_GRANULARITY_SHIFT);
  842. Heaps->NumberOfHeaps += 1;
  843. return STATUS_SUCCESS;
  844. }
  845. NTSYSAPI
  846. NTSTATUS
  847. NTAPI
  848. RtlQueryProcessHeapInformation(
  849. IN OUT PRTL_DEBUG_INFORMATION Buffer
  850. )
  851. {
  852. NTSTATUS Status;
  853. PHEAP Heap;
  854. BOOLEAN LockAcquired;
  855. PRTL_PROCESS_HEAPS Heaps;
  856. PRTL_HEAP_INFORMATION HeapInfo;
  857. UCHAR SegmentIndex;
  858. ULONG i, n, TagIndex;
  859. PHEAP_SEGMENT Segment;
  860. PRTL_HEAP_TAG Tags;
  861. PHEAP_PSEUDO_TAG_ENTRY PseudoTags;
  862. PRTL_HEAP_ENTRY Entries;
  863. PHEAP_ENTRY CurrentBlock;
  864. PHEAP_ENTRY_EXTRA ExtraStuff;
  865. PLIST_ENTRY Head, Next;
  866. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  867. ULONG Size;
  868. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
  869. Heaps = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_HEAPS, Heaps ) );
  870. if (Heaps == NULL) {
  871. return STATUS_NO_MEMORY;
  872. }
  873. Heaps->NumberOfHeaps = 0;
  874. Buffer->Heaps = Heaps;
  875. Status = RtlEnumProcessHeaps( RtlpQueryProcessEnumHeapsRoutine, Buffer );
  876. if (NT_SUCCESS( Status )) {
  877. if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_TAGS) {
  878. Heap = RtlpGlobalTagHeap;
  879. if (Heap->TagEntries != NULL) {
  880. HeapInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( *HeapInfo ) );
  881. if (HeapInfo == NULL) {
  882. return STATUS_NO_MEMORY;
  883. }
  884. RtlZeroMemory( HeapInfo, sizeof( *HeapInfo ) );
  885. HeapInfo->BaseAddress = Heap;
  886. HeapInfo->Flags = Heap->Flags;
  887. HeapInfo->EntryOverhead = sizeof( HEAP_ENTRY );
  888. Heaps->NumberOfHeaps += 1;
  889. }
  890. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  891. HeapInfo = &Heaps->Heaps[ i ];
  892. if (Buffer->SpecificHeap == NULL ||
  893. Buffer->SpecificHeap == HeapInfo->BaseAddress
  894. ) {
  895. Heap = HeapInfo->BaseAddress;
  896. HeapInfo->NumberOfTags = Heap->NextAvailableTagIndex;
  897. n = HeapInfo->NumberOfTags * sizeof( RTL_HEAP_TAG );
  898. if (Heap->PseudoTagEntries != NULL) {
  899. HeapInfo->NumberOfTags += HEAP_MAXIMUM_FREELISTS + 1;
  900. n += (HEAP_MAXIMUM_FREELISTS + 1) * sizeof( RTL_HEAP_TAG );
  901. }
  902. Tags = RtlpCommitQueryDebugInfo( Buffer, n );
  903. if (Tags == NULL) {
  904. Status = STATUS_NO_MEMORY;
  905. break;
  906. }
  907. RtlZeroMemory( Tags, n );
  908. HeapInfo->Tags = Tags;
  909. if ((PseudoTags = Heap->PseudoTagEntries) != NULL) {
  910. HeapInfo->NumberOfPseudoTags = HEAP_NUMBER_OF_PSEUDO_TAG;
  911. HeapInfo->PseudoTagGranularity = HEAP_GRANULARITY;
  912. for (TagIndex=0; TagIndex<=HEAP_MAXIMUM_FREELISTS; TagIndex++) {
  913. Tags->NumberOfAllocations = PseudoTags->Allocs;
  914. Tags->NumberOfFrees = PseudoTags->Frees;
  915. Tags->BytesAllocated = PseudoTags->Size << HEAP_GRANULARITY_SHIFT;
  916. Tags->TagIndex = (USHORT)(TagIndex | HEAP_PSEUDO_TAG_FLAG);
  917. if (TagIndex == 0) {
  918. swprintf( Tags->TagName, L"Objects>%4u",
  919. HEAP_MAXIMUM_FREELISTS << HEAP_GRANULARITY_SHIFT
  920. );
  921. }
  922. else
  923. if (TagIndex < HEAP_MAXIMUM_FREELISTS) {
  924. swprintf( Tags->TagName, L"Objects=%4u",
  925. TagIndex << HEAP_GRANULARITY_SHIFT
  926. );
  927. }
  928. else {
  929. swprintf( Tags->TagName, L"VirtualAlloc" );
  930. }
  931. Tags += 1;
  932. PseudoTags += 1;
  933. }
  934. }
  935. RtlMoveMemory( Tags,
  936. Heap->TagEntries,
  937. Heap->NextAvailableTagIndex * sizeof( RTL_HEAP_TAG )
  938. );
  939. for (TagIndex=0; TagIndex<Heap->NextAvailableTagIndex; TagIndex++) {
  940. Tags->BytesAllocated <<= HEAP_GRANULARITY_SHIFT;
  941. Tags += 1;
  942. }
  943. }
  944. }
  945. }
  946. }
  947. else {
  948. Buffer->Heaps = NULL;
  949. }
  950. if (NT_SUCCESS( Status )) {
  951. if (Buffer->Flags & RTL_QUERY_PROCESS_HEAP_ENTRIES) {
  952. for (i=0; i<Heaps->NumberOfHeaps; i++) {
  953. HeapInfo = &Heaps->Heaps[ i ];
  954. Heap = HeapInfo->BaseAddress;
  955. if (Buffer->SpecificHeap == NULL ||
  956. Buffer->SpecificHeap == Heap
  957. ) {
  958. if (!(Heap->Flags & HEAP_NO_SERIALIZE)) {
  959. RtlEnterCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
  960. LockAcquired = TRUE;
  961. }
  962. else {
  963. LockAcquired = FALSE;
  964. }
  965. try {
  966. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  967. Segment = Heap->Segments[ SegmentIndex ];
  968. if (!Segment) {
  969. continue;
  970. }
  971. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  972. if (Entries == NULL) {
  973. Status = STATUS_NO_MEMORY;
  974. leave;
  975. }
  976. else
  977. if (HeapInfo->Entries == NULL) {
  978. HeapInfo->Entries = Entries;
  979. }
  980. RtlZeroMemory( Entries, sizeof( *Entries ) );
  981. Entries->Flags = RTL_HEAP_SEGMENT;
  982. Entries->AllocatorBackTraceIndex = Segment->AllocatorBackTraceIndex;
  983. Entries->Size = Segment->NumberOfPages * PAGE_SIZE;
  984. Entries->u.s2.CommittedSize = (Segment->NumberOfPages -
  985. Segment->NumberOfUnCommittedPages
  986. ) * PAGE_SIZE;
  987. Entries->u.s2.FirstBlock = Segment->FirstEntry;
  988. HeapInfo->NumberOfEntries++;
  989. UnCommittedRange = Segment->UnCommittedRanges;
  990. CurrentBlock = Segment->FirstEntry;
  991. while (CurrentBlock < Segment->LastValidEntry) {
  992. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  993. if (Entries == NULL) {
  994. Status = STATUS_NO_MEMORY;
  995. leave;
  996. }
  997. RtlZeroMemory( Entries, sizeof( *Entries ) );
  998. Size = CurrentBlock->Size << HEAP_GRANULARITY_SHIFT;
  999. Entries->Size = Size;
  1000. HeapInfo->NumberOfEntries++;
  1001. if (CurrentBlock->Flags & HEAP_ENTRY_BUSY) {
  1002. if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1003. ExtraStuff = (PHEAP_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size - 1);
  1004. #if i386
  1005. Entries->AllocatorBackTraceIndex = ExtraStuff->AllocatorBackTraceIndex;
  1006. #endif // i386
  1007. Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
  1008. Entries->u.s1.Settable = ExtraStuff->Settable;
  1009. Entries->u.s1.Tag = ExtraStuff->TagIndex;
  1010. }
  1011. else {
  1012. Entries->u.s1.Tag = CurrentBlock->SmallTagIndex;
  1013. }
  1014. Entries->Flags |= RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
  1015. }
  1016. else
  1017. if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1018. PHEAP_FREE_ENTRY_EXTRA FreeExtra;
  1019. FreeExtra = (PHEAP_FREE_ENTRY_EXTRA)(CurrentBlock + CurrentBlock->Size) - 1;
  1020. Entries->u.s1.Tag = FreeExtra->TagIndex;
  1021. Entries->AllocatorBackTraceIndex = FreeExtra->FreeBackTraceIndex;
  1022. }
  1023. if (CurrentBlock->Flags & HEAP_ENTRY_LAST_ENTRY) {
  1024. CurrentBlock += CurrentBlock->Size;
  1025. if (UnCommittedRange == NULL) {
  1026. CurrentBlock = Segment->LastValidEntry;
  1027. }
  1028. else {
  1029. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  1030. if (Entries == NULL) {
  1031. Status = STATUS_NO_MEMORY;
  1032. leave;
  1033. }
  1034. RtlZeroMemory( Entries, sizeof( *Entries ) );
  1035. Entries->Flags = RTL_HEAP_UNCOMMITTED_RANGE;
  1036. Entries->Size = UnCommittedRange->Size;
  1037. HeapInfo->NumberOfEntries++;
  1038. CurrentBlock = (PHEAP_ENTRY)
  1039. ((PCHAR)UnCommittedRange->Address + UnCommittedRange->Size);
  1040. UnCommittedRange = UnCommittedRange->Next;
  1041. }
  1042. }
  1043. else {
  1044. CurrentBlock += CurrentBlock->Size;
  1045. }
  1046. }
  1047. }
  1048. Head = &Heap->VirtualAllocdBlocks;
  1049. Next = Head->Flink;
  1050. while (Head != Next) {
  1051. VirtualAllocBlock = CONTAINING_RECORD( Next, HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
  1052. CurrentBlock = &VirtualAllocBlock->BusyBlock;
  1053. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  1054. if (Entries == NULL) {
  1055. Status = STATUS_NO_MEMORY;
  1056. leave;
  1057. }
  1058. else
  1059. if (HeapInfo->Entries == NULL) {
  1060. HeapInfo->Entries = Entries;
  1061. }
  1062. RtlZeroMemory( Entries, sizeof( *Entries ) );
  1063. Entries->Flags = RTL_HEAP_SEGMENT;
  1064. Entries->Size = VirtualAllocBlock->ReserveSize;
  1065. Entries->u.s2.CommittedSize = VirtualAllocBlock->CommitSize;
  1066. Entries->u.s2.FirstBlock = CurrentBlock;
  1067. HeapInfo->NumberOfEntries++;
  1068. Entries = RtlpCommitQueryDebugInfo( Buffer, sizeof( *Entries ) );
  1069. if (Entries == NULL) {
  1070. Status = STATUS_NO_MEMORY;
  1071. leave;
  1072. }
  1073. RtlZeroMemory( Entries, sizeof( *Entries ) );
  1074. Entries->Size = VirtualAllocBlock->CommitSize;
  1075. Entries->Flags = RTL_HEAP_BUSY | (CurrentBlock->Flags & HEAP_ENTRY_SETTABLE_FLAGS);
  1076. #if i386
  1077. Entries->AllocatorBackTraceIndex = VirtualAllocBlock->ExtraStuff.AllocatorBackTraceIndex;
  1078. #endif // i386
  1079. Entries->Flags |= RTL_HEAP_SETTABLE_VALUE;
  1080. Entries->u.s1.Settable = VirtualAllocBlock->ExtraStuff.Settable;
  1081. Entries->u.s1.Tag = VirtualAllocBlock->ExtraStuff.TagIndex;
  1082. HeapInfo->NumberOfEntries++;
  1083. Next = Next->Flink;
  1084. }
  1085. }
  1086. finally {
  1087. //
  1088. // Unlock the heap
  1089. //
  1090. if (LockAcquired) {
  1091. RtlLeaveCriticalSection( (PRTL_CRITICAL_SECTION)Heap->LockVariable );
  1092. }
  1093. }
  1094. }
  1095. if (!NT_SUCCESS( Status )) {
  1096. break;
  1097. }
  1098. }
  1099. }
  1100. }
  1101. return Status;
  1102. }
  1103. NTSYSAPI
  1104. NTSTATUS
  1105. NTAPI
  1106. RtlQueryProcessLockInformation(
  1107. IN OUT PRTL_DEBUG_INFORMATION Buffer
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Queries the current process for ciritcal section information
  1112. Arguments:
  1113. Buffer - Buffer pointer obtained from RtlCreateQueryDebugBuffer
  1114. Return Value:
  1115. NTSTATUS - Status of operation.
  1116. --*/
  1117. {
  1118. NTSTATUS Status;
  1119. PLIST_ENTRY Head, Next;
  1120. PRTL_PROCESS_LOCKS Locks;
  1121. PRTL_PROCESS_LOCK_INFORMATION LockInfo;
  1122. PRTL_CRITICAL_SECTION CriticalSection;
  1123. PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
  1124. PRTL_RESOURCE Resource;
  1125. PRTL_RESOURCE_DEBUG ResourceDebugInfo;
  1126. Locks = RtlpCommitQueryDebugInfo( Buffer, FIELD_OFFSET( RTL_PROCESS_LOCKS, Locks ) );
  1127. if (Locks == NULL) {
  1128. return STATUS_NO_MEMORY;
  1129. }
  1130. Locks->NumberOfLocks = 0;
  1131. Head = &RtlCriticalSectionList;
  1132. RtlEnterCriticalSection( &RtlCriticalSectionLock );
  1133. Next = Head->Flink;
  1134. Status = STATUS_SUCCESS;
  1135. while (Next != Head) {
  1136. DebugInfo = CONTAINING_RECORD( Next,
  1137. RTL_CRITICAL_SECTION_DEBUG,
  1138. ProcessLocksList
  1139. );
  1140. LockInfo = RtlpCommitQueryDebugInfo( Buffer, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
  1141. if (LockInfo == NULL) {
  1142. Status = STATUS_NO_MEMORY;
  1143. break;
  1144. }
  1145. CriticalSection = DebugInfo->CriticalSection;
  1146. try {
  1147. LockInfo->Address = CriticalSection;
  1148. LockInfo->Type = DebugInfo->Type;
  1149. LockInfo->CreatorBackTraceIndex = DebugInfo->CreatorBackTraceIndex;
  1150. if (LockInfo->Type == RTL_CRITSECT_TYPE) {
  1151. LockInfo->OwningThread = CriticalSection->OwningThread;
  1152. LockInfo->LockCount = CriticalSection->LockCount;
  1153. LockInfo->RecursionCount = CriticalSection->RecursionCount;
  1154. LockInfo->ContentionCount = DebugInfo->ContentionCount;
  1155. LockInfo->EntryCount = DebugInfo->EntryCount;
  1156. LockInfo->NumberOfWaitingShared = 0;
  1157. LockInfo->NumberOfWaitingExclusive = 0;
  1158. }
  1159. else {
  1160. Resource = (PRTL_RESOURCE)CriticalSection;
  1161. ResourceDebugInfo = Resource->DebugInfo;
  1162. LockInfo->ContentionCount = ResourceDebugInfo->ContentionCount;
  1163. LockInfo->OwningThread = Resource->ExclusiveOwnerThread;
  1164. LockInfo->LockCount = Resource->NumberOfActive;
  1165. LockInfo->NumberOfWaitingShared = Resource->NumberOfWaitingShared;
  1166. LockInfo->NumberOfWaitingExclusive = Resource->NumberOfWaitingExclusive;
  1167. LockInfo->EntryCount = 0;
  1168. LockInfo->RecursionCount = 0;
  1169. }
  1170. Locks->NumberOfLocks++;
  1171. } except (EXCEPTION_EXECUTE_HANDLER) {
  1172. DbgPrint("NTDLL: Lost critical section %08lX\n", CriticalSection);
  1173. RtlpDeCommitQueryDebugInfo( Buffer, LockInfo, sizeof( RTL_PROCESS_LOCK_INFORMATION ) );
  1174. }
  1175. if (Next == Next->Flink) {
  1176. //
  1177. // Bail if list is circular
  1178. //
  1179. Status = STATUS_INTERNAL_ERROR;
  1180. break;
  1181. }
  1182. else {
  1183. Next = Next->Flink;
  1184. }
  1185. }
  1186. RtlLeaveCriticalSection( &RtlCriticalSectionLock );
  1187. if (NT_SUCCESS( Status )) {
  1188. Buffer->Locks = Locks;
  1189. }
  1190. else {
  1191. RtlpDeCommitQueryDebugInfo( Buffer, Locks,
  1192. FIELD_OFFSET( RTL_PROCESS_LOCKS, Locks ) );
  1193. }
  1194. return Status;
  1195. }