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.

898 lines
22 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. stktrace.c
  5. Abstract:
  6. This module implements routines to snapshot a set of stack back traces
  7. in a data base. Useful for heap allocators to track allocation requests
  8. cheaply.
  9. Author:
  10. Steve Wood (stevewo) 29-Jan-1992
  11. Revision History:
  12. 17-May-1999 (silviuc) : added RtlWalkFrameChain that replaces the
  13. unsafe RtlCaptureStackBackTrace.
  14. 29-Jul-2000 (silviuc) : added RtlCaptureStackContext.
  15. 6-Nov-2000 (silviuc): IA64 runtime stack traces.
  16. 18-Feb-2001 (silviuc) : moved all x86 specific code into i386 directory.
  17. --*/
  18. #include <ntos.h>
  19. #include <ntrtl.h>
  20. #include "ntrtlp.h"
  21. #include <nturtl.h>
  22. #include <zwapi.h>
  23. #include <stktrace.h>
  24. #include <heap.h>
  25. #include <heappriv.h>
  26. //
  27. // Forward declarations.
  28. //
  29. BOOLEAN
  30. RtlpCaptureStackLimits (
  31. ULONG_PTR HintAddress,
  32. PULONG_PTR StartStack,
  33. PULONG_PTR EndStack);
  34. BOOLEAN
  35. RtlpStkIsPointerInDllRange (
  36. ULONG_PTR Value
  37. );
  38. BOOLEAN
  39. RtlpStkIsPointerInNtdllRange (
  40. ULONG_PTR Value
  41. );
  42. VOID
  43. RtlpCaptureContext (
  44. OUT PCONTEXT ContextRecord
  45. );
  46. BOOLEAN
  47. NtdllOkayToLockRoutine(
  48. IN PVOID Lock
  49. );
  50. /////////////////////////////////////////////////////////////////////
  51. //////////////////////////////////////// Runtime stack trace database
  52. /////////////////////////////////////////////////////////////////////
  53. //
  54. // The following section implements a trace database used to store
  55. // stack traces captured with RtlCaptureStackBackTrace(). The database
  56. // is implemented as a hash table and does not allow deletions. It is
  57. // sensitive to "garbage" in the sense that spurios garbage (partially
  58. // correct stacks) will hash in different buckets and will tend to fill
  59. // the whole table. This is a problem only on x86 if "fuzzy" stack traces
  60. // are used. The typical function used to log the trace is
  61. // RtlLogStackBackTrace. One of the worst limitations of this package
  62. // is that traces are refered using a ushort index which means we cannot
  63. // ever store more than 65535 traces (remember we never delete traces).
  64. //
  65. //
  66. // Global per process stack trace database.
  67. //
  68. PSTACK_TRACE_DATABASE RtlpStackTraceDataBase;
  69. PRTL_STACK_TRACE_ENTRY
  70. RtlpExtendStackTraceDataBase(
  71. IN PRTL_STACK_TRACE_ENTRY InitialValue,
  72. IN SIZE_T Size
  73. );
  74. NTSTATUS
  75. RtlInitStackTraceDataBaseEx(
  76. IN PVOID CommitBase,
  77. IN SIZE_T CommitSize,
  78. IN SIZE_T ReserveSize,
  79. IN PRTL_INITIALIZE_LOCK_ROUTINE InitializeLockRoutine,
  80. IN PRTL_ACQUIRE_LOCK_ROUTINE AcquireLockRoutine,
  81. IN PRTL_RELEASE_LOCK_ROUTINE ReleaseLockRoutine,
  82. IN PRTL_OKAY_TO_LOCK_ROUTINE OkayToLockRoutine
  83. );
  84. NTSTATUS
  85. RtlInitStackTraceDataBaseEx(
  86. IN PVOID CommitBase,
  87. IN SIZE_T CommitSize,
  88. IN SIZE_T ReserveSize,
  89. IN PRTL_INITIALIZE_LOCK_ROUTINE InitializeLockRoutine,
  90. IN PRTL_ACQUIRE_LOCK_ROUTINE AcquireLockRoutine,
  91. IN PRTL_RELEASE_LOCK_ROUTINE ReleaseLockRoutine,
  92. IN PRTL_OKAY_TO_LOCK_ROUTINE OkayToLockRoutine
  93. )
  94. {
  95. NTSTATUS Status;
  96. PSTACK_TRACE_DATABASE DataBase;
  97. extern BOOLEAN RtlpFuzzyStackTracesEnabled;
  98. //
  99. // On x86 where runtime stack tracing algorithms are unreliable
  100. // if we have a big enough trace database then we can enable fuzzy
  101. // stack traces that do not hash very well and have the potential
  102. // to fill out the trace database.
  103. //
  104. #if defined(_X86_) && !defined(NTOS_KERNEL_RUNTIME)
  105. if (ReserveSize >= 16 * RTL_MEG) {
  106. RtlpFuzzyStackTracesEnabled = TRUE;
  107. }
  108. #endif
  109. DataBase = (PSTACK_TRACE_DATABASE)CommitBase;
  110. if (CommitSize == 0) {
  111. CommitSize = PAGE_SIZE;
  112. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  113. (PVOID *)&CommitBase,
  114. 0,
  115. &CommitSize,
  116. MEM_COMMIT,
  117. PAGE_READWRITE
  118. );
  119. if (!NT_SUCCESS( Status )) {
  120. KdPrint(( "RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
  121. Status
  122. ));
  123. return Status;
  124. }
  125. DataBase->PreCommitted = FALSE;
  126. }
  127. else
  128. if (CommitSize == ReserveSize) {
  129. RtlZeroMemory( DataBase, sizeof( *DataBase ) );
  130. DataBase->PreCommitted = TRUE;
  131. }
  132. else {
  133. return STATUS_INVALID_PARAMETER;
  134. }
  135. DataBase->CommitBase = CommitBase;
  136. DataBase->NumberOfBuckets = 137;
  137. DataBase->NextFreeLowerMemory = (PCHAR)
  138. (&DataBase->Buckets[ DataBase->NumberOfBuckets ]);
  139. DataBase->NextFreeUpperMemory = (PCHAR)CommitBase + ReserveSize;
  140. if(!DataBase->PreCommitted) {
  141. DataBase->CurrentLowerCommitLimit = (PCHAR)CommitBase + CommitSize;
  142. DataBase->CurrentUpperCommitLimit = (PCHAR)CommitBase + ReserveSize;
  143. }
  144. else {
  145. RtlZeroMemory( &DataBase->Buckets[ 0 ],
  146. DataBase->NumberOfBuckets * sizeof( DataBase->Buckets[ 0 ] )
  147. );
  148. }
  149. DataBase->EntryIndexArray = (PRTL_STACK_TRACE_ENTRY *)DataBase->NextFreeUpperMemory;
  150. DataBase->AcquireLockRoutine = AcquireLockRoutine;
  151. DataBase->ReleaseLockRoutine = ReleaseLockRoutine;
  152. DataBase->OkayToLockRoutine = OkayToLockRoutine;
  153. Status = (InitializeLockRoutine)( &DataBase->Lock.CriticalSection );
  154. if (!NT_SUCCESS( Status )) {
  155. KdPrint(( "RTL: Unable to initialize stack trace data base CriticalSection, Status = %lx\n",
  156. Status
  157. ));
  158. return( Status );
  159. }
  160. RtlpStackTraceDataBase = DataBase;
  161. return( STATUS_SUCCESS );
  162. }
  163. NTSTATUS
  164. RtlInitializeStackTraceDataBase(
  165. IN PVOID CommitBase,
  166. IN SIZE_T CommitSize,
  167. IN SIZE_T ReserveSize
  168. )
  169. {
  170. #ifdef NTOS_KERNEL_RUNTIME
  171. BOOLEAN
  172. ExOkayToLockRoutine(
  173. IN PVOID Lock
  174. );
  175. return RtlInitStackTraceDataBaseEx(
  176. CommitBase,
  177. CommitSize,
  178. ReserveSize,
  179. ExInitializeResourceLite,
  180. (PRTL_RELEASE_LOCK_ROUTINE)ExAcquireResourceExclusiveLite,
  181. (PRTL_RELEASE_LOCK_ROUTINE)ExReleaseResourceLite,
  182. ExOkayToLockRoutine
  183. );
  184. #else // #ifdef NTOS_KERNEL_RUNTIME
  185. return RtlInitStackTraceDataBaseEx(
  186. CommitBase,
  187. CommitSize,
  188. ReserveSize,
  189. RtlInitializeCriticalSection,
  190. RtlEnterCriticalSection,
  191. RtlLeaveCriticalSection,
  192. NtdllOkayToLockRoutine
  193. );
  194. #endif // #ifdef NTOS_KERNEL_RUNTIME
  195. }
  196. PSTACK_TRACE_DATABASE
  197. RtlpAcquireStackTraceDataBase( VOID )
  198. {
  199. if (RtlpStackTraceDataBase != NULL) {
  200. if (RtlpStackTraceDataBase->DumpInProgress ||
  201. !(RtlpStackTraceDataBase->OkayToLockRoutine)( &RtlpStackTraceDataBase->Lock.CriticalSection )
  202. ) {
  203. return( NULL );
  204. }
  205. (RtlpStackTraceDataBase->AcquireLockRoutine)( &RtlpStackTraceDataBase->Lock.CriticalSection );
  206. }
  207. return( RtlpStackTraceDataBase );
  208. }
  209. VOID
  210. RtlpReleaseStackTraceDataBase( VOID )
  211. {
  212. (RtlpStackTraceDataBase->ReleaseLockRoutine)( &RtlpStackTraceDataBase->Lock.CriticalSection );
  213. return;
  214. }
  215. PRTL_STACK_TRACE_ENTRY
  216. RtlpExtendStackTraceDataBase(
  217. IN PRTL_STACK_TRACE_ENTRY InitialValue,
  218. IN SIZE_T Size
  219. )
  220. /*++
  221. Routine Description:
  222. This routine extends the stack trace database in order to accomodate
  223. the new stack trace that has to be saved.
  224. Arguments:
  225. InitialValue - stack trace to be saved.
  226. Size - size of the stack trace in bytes. Note that this is not the
  227. depth of the trace but rather `Depth * sizeof(PVOID)'.
  228. Return Value:
  229. The address of the just saved stack trace or null in case we have hit
  230. the maximum size of the database or we get commit errors.
  231. Environment:
  232. User mode.
  233. Note. In order to make all this code work in kernel mode we have to
  234. rewrite this function that relies on VirtualAlloc.
  235. --*/
  236. {
  237. NTSTATUS Status;
  238. PRTL_STACK_TRACE_ENTRY p, *pp;
  239. SIZE_T CommitSize;
  240. PSTACK_TRACE_DATABASE DataBase;
  241. DataBase = RtlpStackTraceDataBase;
  242. //
  243. // We will try to find space for one stack trace entry in the
  244. // upper part of the database.
  245. //
  246. pp = (PRTL_STACK_TRACE_ENTRY *)DataBase->NextFreeUpperMemory;
  247. if ((! DataBase->PreCommitted) &&
  248. ((PCHAR)(pp - 1) < (PCHAR)DataBase->CurrentUpperCommitLimit)) {
  249. //
  250. // No more committed space in the upper part of the database.
  251. // We need to extend it downwards.
  252. //
  253. DataBase->CurrentUpperCommitLimit =
  254. (PVOID)((PCHAR)DataBase->CurrentUpperCommitLimit - PAGE_SIZE);
  255. if (DataBase->CurrentUpperCommitLimit < DataBase->CurrentLowerCommitLimit) {
  256. //
  257. // No more space at all. We have got over the lower part of the db.
  258. // We failed therefore increase back the UpperCommitLimit pointer.
  259. //
  260. DataBase->CurrentUpperCommitLimit =
  261. (PVOID)((PCHAR)DataBase->CurrentUpperCommitLimit + PAGE_SIZE);
  262. return( NULL );
  263. }
  264. CommitSize = PAGE_SIZE;
  265. Status = ZwAllocateVirtualMemory(
  266. NtCurrentProcess(),
  267. (PVOID *)&DataBase->CurrentUpperCommitLimit,
  268. 0,
  269. &CommitSize,
  270. MEM_COMMIT,
  271. PAGE_READWRITE
  272. );
  273. if (!NT_SUCCESS( Status )) {
  274. //
  275. // We tried to increase the upper part of the db by one page.
  276. // We failed therefore increase back the UpperCommitLimit pointer
  277. //
  278. DataBase->CurrentUpperCommitLimit =
  279. (PVOID)((PCHAR)DataBase->CurrentUpperCommitLimit + PAGE_SIZE);
  280. KdPrint(( "RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
  281. Status
  282. ));
  283. return( NULL );
  284. }
  285. }
  286. //
  287. // We managed to make sure we have usable space in the upper part
  288. // therefore we take out one stack trace entry address.
  289. //
  290. DataBase->NextFreeUpperMemory -= sizeof( *pp );
  291. //
  292. // Now we will try to find space in the lower part of the database for
  293. // for the eactual stack trace.
  294. //
  295. p = (PRTL_STACK_TRACE_ENTRY)DataBase->NextFreeLowerMemory;
  296. if ((! DataBase->PreCommitted) &&
  297. (((PCHAR)p + Size) > (PCHAR)DataBase->CurrentLowerCommitLimit)) {
  298. //
  299. // We need to extend the lower part.
  300. //
  301. if (DataBase->CurrentLowerCommitLimit >= DataBase->CurrentUpperCommitLimit) {
  302. //
  303. // We have hit the maximum size of the database.
  304. //
  305. return( NULL );
  306. }
  307. //
  308. // Extend the lower part of the database by one page.
  309. //
  310. CommitSize = Size;
  311. Status = ZwAllocateVirtualMemory(
  312. NtCurrentProcess(),
  313. (PVOID *)&DataBase->CurrentLowerCommitLimit,
  314. 0,
  315. &CommitSize,
  316. MEM_COMMIT,
  317. PAGE_READWRITE
  318. );
  319. if (! NT_SUCCESS( Status )) {
  320. KdPrint(( "RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
  321. Status
  322. ));
  323. return( NULL );
  324. }
  325. DataBase->CurrentLowerCommitLimit =
  326. (PCHAR)DataBase->CurrentLowerCommitLimit + CommitSize;
  327. }
  328. //
  329. // Take out the space for the stack trace.
  330. //
  331. DataBase->NextFreeLowerMemory += Size;
  332. //
  333. // Deal with a precommitted database case. If the lower and upper
  334. // pointers have crossed each other then rollback and return failure.
  335. //
  336. if (DataBase->PreCommitted &&
  337. DataBase->NextFreeLowerMemory >= DataBase->NextFreeUpperMemory) {
  338. DataBase->NextFreeUpperMemory += sizeof( *pp );
  339. DataBase->NextFreeLowerMemory -= Size;
  340. return( NULL );
  341. }
  342. //
  343. // Save the stack trace in the database
  344. //
  345. RtlMoveMemory( p, InitialValue, Size );
  346. p->HashChain = NULL;
  347. p->TraceCount = 0;
  348. p->Index = (USHORT)(++DataBase->NumberOfEntriesAdded);
  349. //
  350. // Save the address of the new stack trace entry in the
  351. // upper part of the databse.
  352. //
  353. *--pp = p;
  354. //
  355. // Return address of the saved stack trace entry.
  356. //
  357. return( p );
  358. }
  359. USHORT
  360. RtlLogStackBackTrace(
  361. VOID
  362. )
  363. /*++
  364. Routine Description:
  365. This routine will capture the current stacktrace (skipping the
  366. present function) and will save it in the global (per process)
  367. stack trace database. It should be noted that we do not save
  368. duplicate traces.
  369. Arguments:
  370. None.
  371. Return Value:
  372. Index of the stack trace saved. The index can be used by tools
  373. to access quickly the trace data. This is the reason at the end of
  374. the database we save downwards a list of pointers to trace entries.
  375. This index can be used to find this pointer in constant time.
  376. A zero index will be returned for error conditions (e.g. stack
  377. trace database not initialized).
  378. Environment:
  379. User mode.
  380. --*/
  381. {
  382. PSTACK_TRACE_DATABASE DataBase;
  383. RTL_STACK_TRACE_ENTRY StackTrace;
  384. PRTL_STACK_TRACE_ENTRY p, *pp;
  385. ULONG Hash, RequestedSize, DepthSize;
  386. if (RtlpStackTraceDataBase == NULL) {
  387. return 0;
  388. }
  389. Hash = 0;
  390. //
  391. // Capture stack trace. The try/except was useful
  392. // in the old days when the function did not validate
  393. // the stack frame chain. We keep it just ot be defensive.
  394. //
  395. try {
  396. StackTrace.Depth = RtlCaptureStackBackTrace(
  397. 1,
  398. MAX_STACK_DEPTH,
  399. StackTrace.BackTrace,
  400. &Hash
  401. );
  402. }
  403. except(EXCEPTION_EXECUTE_HANDLER) {
  404. StackTrace.Depth = 0;
  405. }
  406. if (StackTrace.Depth == 0) {
  407. return 0;
  408. }
  409. //
  410. // Lock the global per-process stack trace database.
  411. //
  412. DataBase = RtlpAcquireStackTraceDataBase();
  413. if (DataBase == NULL) {
  414. return( 0 );
  415. }
  416. DataBase->NumberOfEntriesLookedUp++;
  417. try {
  418. //
  419. // We will try to find out if the trace has been saved in the past.
  420. // We find the right hash chain and then traverse it.
  421. //
  422. DepthSize = StackTrace.Depth * sizeof( StackTrace.BackTrace[ 0 ] );
  423. pp = &DataBase->Buckets[ Hash % DataBase->NumberOfBuckets ];
  424. while (p = *pp) {
  425. if (p->Depth == StackTrace.Depth &&
  426. RtlCompareMemory( &p->BackTrace[ 0 ],
  427. &StackTrace.BackTrace[ 0 ],
  428. DepthSize
  429. ) == DepthSize
  430. ) {
  431. break;
  432. }
  433. else {
  434. pp = &p->HashChain;
  435. }
  436. }
  437. if (p == NULL) {
  438. //
  439. // We did not find the stack trace. We will extend the database
  440. // and save the new trace.
  441. //
  442. RequestedSize = FIELD_OFFSET( RTL_STACK_TRACE_ENTRY, BackTrace ) +
  443. DepthSize;
  444. p = RtlpExtendStackTraceDataBase( &StackTrace, RequestedSize );
  445. //
  446. // If we managed to stack the trace we need to link it as the last
  447. // element in the proper hash chain.
  448. //
  449. if (p != NULL) {
  450. *pp = p;
  451. }
  452. }
  453. }
  454. except(EXCEPTION_EXECUTE_HANDLER) {
  455. //
  456. // We should never get here if the algorithm is correct.
  457. //
  458. p = NULL;
  459. }
  460. //
  461. // Release global trace db.
  462. //
  463. RtlpReleaseStackTraceDataBase();
  464. if (p != NULL) {
  465. p->TraceCount++;
  466. return( p->Index );
  467. }
  468. else {
  469. return( 0 );
  470. }
  471. return 0;
  472. }
  473. PVOID
  474. RtlpGetStackTraceAddress (
  475. USHORT Index
  476. )
  477. {
  478. if (RtlpStackTraceDataBase == NULL) {
  479. return NULL;
  480. }
  481. if (! (Index > 0 && Index <= RtlpStackTraceDataBase->NumberOfEntriesAdded)) {
  482. return NULL;
  483. }
  484. return (PVOID)(RtlpStackTraceDataBase->EntryIndexArray[-Index]);
  485. }
  486. #if defined(NTOS_KERNEL_RUNTIME)
  487. USHORT
  488. RtlLogUmodeStackBackTrace(
  489. VOID
  490. )
  491. /*++
  492. Routine Description:
  493. This routine will capture the user mode stacktrace and will save
  494. it in the global (per system) stack trace database.
  495. It should be noted that we do not save duplicate traces.
  496. Arguments:
  497. None.
  498. Return Value:
  499. Index of the stack trace saved. The index can be used by tools
  500. to access quickly the trace data. This is the reason at the end of
  501. the database we save downwards a list of pointers to trace entries.
  502. This index can be used to find this pointer in constant time.
  503. A zero index will be returned for error conditions (e.g. stack
  504. trace database not initialized).
  505. Environment:
  506. User mode.
  507. --*/
  508. {
  509. PSTACK_TRACE_DATABASE DataBase;
  510. RTL_STACK_TRACE_ENTRY StackTrace;
  511. PRTL_STACK_TRACE_ENTRY p, *pp;
  512. ULONG Hash, RequestedSize, DepthSize;
  513. ULONG Index;
  514. if (RtlpStackTraceDataBase == NULL) {
  515. return 0;
  516. }
  517. Hash = 0;
  518. //
  519. // Avoid weird situations.
  520. //
  521. if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
  522. return 0;
  523. }
  524. //
  525. // Capture user mode stack trace and hash value.
  526. //
  527. StackTrace.Depth = (USHORT) RtlWalkFrameChain(StackTrace.BackTrace,
  528. MAX_STACK_DEPTH,
  529. 1);
  530. if (StackTrace.Depth == 0) {
  531. return 0;
  532. }
  533. for (Index = 0; Index < StackTrace.Depth; Index += 1) {
  534. Hash += PtrToUlong (StackTrace.BackTrace[Index]);
  535. }
  536. //
  537. // Lock the global per-process stack trace database.
  538. //
  539. DataBase = RtlpAcquireStackTraceDataBase();
  540. if (DataBase == NULL) {
  541. return( 0 );
  542. }
  543. DataBase->NumberOfEntriesLookedUp++;
  544. try {
  545. //
  546. // We will try to find out if the trace has been saved in the past.
  547. // We find the right hash chain and then traverse it.
  548. //
  549. DepthSize = StackTrace.Depth * sizeof( StackTrace.BackTrace[ 0 ] );
  550. pp = &DataBase->Buckets[ Hash % DataBase->NumberOfBuckets ];
  551. while (p = *pp) {
  552. if (p->Depth == StackTrace.Depth &&
  553. RtlCompareMemory( &p->BackTrace[ 0 ],
  554. &StackTrace.BackTrace[ 0 ],
  555. DepthSize
  556. ) == DepthSize
  557. ) {
  558. break;
  559. }
  560. else {
  561. pp = &p->HashChain;
  562. }
  563. }
  564. if (p == NULL) {
  565. //
  566. // We did not find the stack trace. We will extend the database
  567. // and save the new trace.
  568. //
  569. RequestedSize = FIELD_OFFSET( RTL_STACK_TRACE_ENTRY, BackTrace ) +
  570. DepthSize;
  571. p = RtlpExtendStackTraceDataBase( &StackTrace, RequestedSize );
  572. //
  573. // If we managed to stack the trace we need to link it as the last
  574. // element in the proper hash chain.
  575. //
  576. if (p != NULL) {
  577. *pp = p;
  578. }
  579. }
  580. }
  581. except(EXCEPTION_EXECUTE_HANDLER) {
  582. //
  583. // We should never get here if the algorithm is correct.
  584. //
  585. p = NULL;
  586. }
  587. //
  588. // Release global trace db.
  589. //
  590. RtlpReleaseStackTraceDataBase();
  591. if (p != NULL) {
  592. p->TraceCount++;
  593. return( p->Index );
  594. }
  595. else {
  596. return( 0 );
  597. }
  598. return 0;
  599. }
  600. #endif // #if defined(NTOS_KERNEL_RUNTIME)
  601. BOOLEAN
  602. RtlpCaptureStackLimits (
  603. ULONG_PTR HintAddress,
  604. PULONG_PTR StartStack,
  605. PULONG_PTR EndStack)
  606. /*++
  607. Routine Description:
  608. This routine figures out what are the stack limits for the current thread.
  609. This is used in other routines that need to grovel the stack for various
  610. information (e.g. potential return addresses).
  611. The function is especially tricky in K-mode where the information kept in
  612. the thread structure about stack limits is not always valid because the
  613. thread might execute a DPC routine and in this case we use a different stack
  614. with different limits.
  615. Arguments:
  616. HintAddress - Address of a local variable or parameter of the caller of the
  617. function that should be the start of the stack.
  618. StartStack - start address of the stack (lower value).
  619. EndStack - end address of the stack (upper value).
  620. Return value:
  621. False if some weird condition is discovered, like an End lower than a Start.
  622. --*/
  623. {
  624. #ifdef NTOS_KERNEL_RUNTIME
  625. //
  626. // Avoid weird conditions. Doing this in an ISR is never a good idea.
  627. //
  628. if (KeGetCurrentIrql() > DISPATCH_LEVEL) {
  629. return FALSE;
  630. }
  631. *StartStack = (ULONG_PTR)(KeGetCurrentThread()->StackLimit);
  632. *EndStack = (ULONG_PTR)(KeGetCurrentThread()->StackBase);
  633. if (*StartStack <= HintAddress && HintAddress <= *EndStack) {
  634. *StartStack = HintAddress;
  635. }
  636. else {
  637. #if defined(_WIN64)
  638. //
  639. // On Win64 we do not know yet where DPCs are executed.
  640. //
  641. return FALSE;
  642. #else
  643. *EndStack = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
  644. #endif
  645. *StartStack = *EndStack - KERNEL_STACK_SIZE;
  646. //
  647. // Check if this is within the DPC stack for the current
  648. // processor.
  649. //
  650. if (*EndStack && *StartStack <= HintAddress && HintAddress <= *EndStack) {
  651. *StartStack = HintAddress;
  652. }
  653. else {
  654. //
  655. // This is not current thread's stack and is not the DPC stack
  656. // of the current processor. Basically we have no idea on what
  657. // stack we are running. We need to investigate this. On free
  658. // builds we try to make the best out of it by using only one
  659. // page for stack limits.
  660. //
  661. // SilviuC: I disabled the code below because it seems under certain
  662. // conditions drivers do indeed switch execution to a different stack.
  663. // This function will need to be improved to deal with this too.
  664. //
  665. #if 0
  666. DbgPrint ("RtlpCaptureStackLimits: mysterious stack (prcb @ %p) \n",
  667. KeGetPcr()->Prcb);
  668. DbgBreakPoint ();
  669. #endif
  670. *StartStack = HintAddress;
  671. *EndStack = (*StartStack + PAGE_SIZE) & ~((ULONG_PTR)PAGE_SIZE - 1);
  672. }
  673. }
  674. #else
  675. *StartStack = HintAddress;
  676. *EndStack = (ULONG_PTR)(NtCurrentTeb()->NtTib.StackBase);
  677. #endif
  678. return TRUE;
  679. }