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.

1365 lines
37 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. critsect.c
  5. Abstract:
  6. Critical section debugger extension for both ntsd and kd.
  7. Author:
  8. Daniel Mihai (DMihai) 8-Feb-2001
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. /////////////////////////////////////////////////////////////////////
  16. BOOL
  17. ReadStructFieldVerbose( ULONG64 AddrStructBase,
  18. PCHAR StructTypeName,
  19. PCHAR StructFieldName,
  20. PVOID Buffer,
  21. ULONG BufferSize )
  22. {
  23. ULONG FieldOffset;
  24. ULONG ErrorCode;
  25. BOOL Success;
  26. Success = FALSE;
  27. //
  28. // Get the field offset
  29. //
  30. ErrorCode = GetFieldOffset (StructTypeName,
  31. StructFieldName,
  32. &FieldOffset );
  33. if (ErrorCode == S_OK) {
  34. //
  35. // Read the data
  36. //
  37. Success = ReadMemory (AddrStructBase + FieldOffset,
  38. Buffer,
  39. BufferSize,
  40. NULL );
  41. if (Success != TRUE) {
  42. dprintf ("Cannot read structure field value at 0x%p, error %u\n",
  43. AddrStructBase + FieldOffset,
  44. ErrorCode );
  45. }
  46. }
  47. else {
  48. dprintf ("Cannot get field offset of %s in %s, error %u\n",
  49. StructFieldName,
  50. StructTypeName,
  51. ErrorCode );
  52. }
  53. return Success;
  54. }
  55. /////////////////////////////////////////////////////////////////////
  56. BOOL
  57. ReadPtrStructFieldVerbose( ULONG64 AddrStructBase,
  58. PCHAR StructTypeName,
  59. PCHAR StructFieldName,
  60. PULONG64 Buffer )
  61. {
  62. ULONG FieldOffset;
  63. ULONG ErrorCode;
  64. BOOL Success;
  65. Success = FALSE;
  66. //
  67. // Get the field offset inside the structure
  68. //
  69. ErrorCode = GetFieldOffset ( StructTypeName,
  70. StructFieldName,
  71. &FieldOffset );
  72. if (ErrorCode == S_OK) {
  73. //
  74. // Read the data
  75. //
  76. if (ReadPointer(AddrStructBase + FieldOffset, Buffer) == FALSE) {
  77. dprintf ("Cannot read structure field value at 0x%p\n",
  78. AddrStructBase + FieldOffset);
  79. }
  80. else {
  81. Success = TRUE;
  82. }
  83. }
  84. else {
  85. dprintf ("Cannot get field offset of %s in structure %s, error %u\n",
  86. StructFieldName,
  87. StructTypeName,
  88. ErrorCode );
  89. }
  90. return Success;
  91. }
  92. /////////////////////////////////////////////////////////////////////////////
  93. ULONG64
  94. GetStackTraceAddress( ULONG StackTraceIndex,
  95. ULONG PointerSize )
  96. {
  97. ULONG64 TraceDatabaseAddress;
  98. ULONG64 TraceDatabase;
  99. ULONG64 EntryIndexArray;
  100. ULONG64 StackTraceAddress;
  101. ULONG64 StackTraceToDump;
  102. ULONG NumberOfEntriesAdded;
  103. ULONG ErrorCode;
  104. BOOL Success;
  105. StackTraceToDump = 0;
  106. //
  107. // Stack trace database address
  108. //
  109. TraceDatabaseAddress = GetExpression("&NTDLL!RtlpStackTraceDataBase");
  110. if ( TraceDatabaseAddress == 0 ) {
  111. dprintf( "!cs: Unable to resolve NTDLL!RtlpStackTraceDataBase\n"
  112. "Please check your symbols\n" );
  113. goto Done;
  114. }
  115. if (ReadPointer (TraceDatabaseAddress, &TraceDatabase ) == FALSE) {
  116. dprintf( "!cs: Cannot read pointer at NTDLL!RtlpStackTraceDataBase\n" );
  117. goto Done;
  118. }
  119. else if (TraceDatabase == 0) {
  120. dprintf( "NTDLL!RtlpStackTraceDataBase is NULL. Probably the stack traces are not enabled.\n" );
  121. goto Done;
  122. }
  123. //
  124. // Read the number of entries in the database
  125. //
  126. Success = ReadStructFieldVerbose (TraceDatabase,
  127. "NTDLL!_STACK_TRACE_DATABASE",
  128. "NumberOfEntriesAdded",
  129. &NumberOfEntriesAdded,
  130. sizeof( NumberOfEntriesAdded ) );
  131. if( Success == FALSE ) {
  132. dprintf( "Cannot read the number of stack traces database entries\n" );
  133. goto Done;
  134. }
  135. else if( StackTraceIndex == 0 ) {
  136. dprintf( "No stack trace found.\n" );
  137. goto Done;
  138. }
  139. else if( NumberOfEntriesAdded < StackTraceIndex ) {
  140. dprintf( "Stack trace index 0x%X is invalid, current number of stack traces is 0x%X\n",
  141. StackTraceIndex,
  142. NumberOfEntriesAdded );
  143. goto Done;
  144. }
  145. //
  146. // Find the array of stack traces
  147. //
  148. Success = ReadPtrStructFieldVerbose (TraceDatabase,
  149. "NTDLL!_STACK_TRACE_DATABASE",
  150. "EntryIndexArray",
  151. &EntryIndexArray );
  152. if( Success == FALSE ) {
  153. dprintf( "Cannot read the stack database array address\n" );
  154. goto Done;
  155. }
  156. //
  157. // Compute the address of our stack trace pointer
  158. //
  159. StackTraceAddress = EntryIndexArray - StackTraceIndex * PointerSize;
  160. //
  161. // Read the pointer to our trace entry in the array
  162. //
  163. if( ReadPointer (StackTraceAddress, &StackTraceToDump) == FALSE) {
  164. dprintf( "Cannot read stack trace address at 0x%p\n",
  165. StackTraceAddress );
  166. StackTraceToDump = 0;
  167. }
  168. Done:
  169. return StackTraceToDump;
  170. }
  171. //////////////////////////////////////////////////////////////////////
  172. VOID
  173. DumpStackTraceAtAddress (ULONG64 StackTraceAddress,
  174. ULONG PointerSize)
  175. {
  176. ULONG64 CrtTraceAddress;
  177. ULONG64 CodeAddress;
  178. ULONG64 Displacement;
  179. ULONG ErrorCode;
  180. ULONG BackTraceFieldOffset;
  181. USHORT Depth;
  182. USHORT CrtEntryIndex;
  183. BOOL Success;
  184. CHAR Symbol[ 1024 ];
  185. //
  186. // Read the stack trace depth
  187. //
  188. Success = ReadStructFieldVerbose (StackTraceAddress,
  189. "NTDLL!_RTL_STACK_TRACE_ENTRY",
  190. "Depth",
  191. &Depth,
  192. sizeof( Depth ));
  193. if( Success == FALSE ) {
  194. dprintf ("!cs: Cannot read depth for stack trace at 0x%p\n",
  195. StackTraceAddress);
  196. goto Done;
  197. }
  198. //
  199. // Limit the depth to 20 to protect ourselves from corrupted data
  200. //
  201. Depth = __min( Depth, 20 );
  202. //
  203. // Get a pointer to the BackTrace array
  204. //
  205. ErrorCode = GetFieldOffset ("NTDLL!_RTL_STACK_TRACE_ENTRY",
  206. "BackTrace",
  207. &BackTraceFieldOffset);
  208. if (ErrorCode != S_OK) {
  209. dprintf ("!cs: Cannot get the BackTrace field offset\n");
  210. goto Done;
  211. }
  212. CrtTraceAddress = StackTraceAddress + BackTraceFieldOffset;
  213. //
  214. // Dump this stack trace
  215. //
  216. for( CrtEntryIndex = 0; CrtEntryIndex < Depth; CrtEntryIndex += 1 ) {
  217. if (ReadPointer (CrtTraceAddress, &CodeAddress) == FALSE) {
  218. dprintf ("!cs: Cannot read address at 0x%p\n",
  219. CrtTraceAddress );
  220. }
  221. GetSymbol( CodeAddress,
  222. Symbol,
  223. &Displacement);
  224. dprintf ("0x%p: %s+0x%I64X\n",
  225. CodeAddress,
  226. Symbol,
  227. Displacement );
  228. CrtTraceAddress += PointerSize;
  229. }
  230. Done:
  231. NOTHING;
  232. }
  233. //////////////////////////////////////////////////////////////////////
  234. BOOL
  235. DumpCriticalSection ( ULONG64 AddrCritSec,
  236. ULONG64 AddrEndCritSect,
  237. ULONG64 AddrDebugInfo,
  238. ULONG PointerSize,
  239. BOOL DumpStackTrace )
  240. {
  241. ULONG64 DebugInfo;
  242. ULONG64 OtherDebugInfo;
  243. ULONG64 CritSec;
  244. ULONG64 SpinCount;
  245. ULONG64 OwningThread;
  246. ULONG64 LockSemaphore;
  247. ULONG64 StackTraceAddress;
  248. ULONG64 Displacement;
  249. LONG LockCount;
  250. LONG RecursionCount;
  251. USHORT CreatorBackTraceIndex;
  252. ULONG DebugInfoFieldOffset;
  253. ULONG CriticalSectionFieldOffset;
  254. ULONG ErrorCode;
  255. BOOL HaveGoodSymbols;
  256. BOOL Success;
  257. CHAR Symbol[1024];
  258. HaveGoodSymbols = FALSE;
  259. //
  260. // The caller must supply at least one of the
  261. // critical section or debug information address.
  262. //
  263. if (AddrCritSec == 0 && AddrDebugInfo == 0) {
  264. dprintf ("Internal debugger extension error: Both critical section and debug info are NULL\n");
  265. goto Done;
  266. }
  267. //
  268. // Get the field offsets for various structures and check if we have
  269. // good symbols, with type information.
  270. //
  271. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION",
  272. "DebugInfo",
  273. &DebugInfoFieldOffset );
  274. if (ErrorCode != S_OK)
  275. {
  276. dprintf( "Bad symbols for NTDLL (error %u). Aborting.\n",
  277. ErrorCode );
  278. goto Done;
  279. }
  280. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  281. "CriticalSection",
  282. &CriticalSectionFieldOffset );
  283. if (ErrorCode != S_OK)
  284. {
  285. dprintf( "Bad symbols for NTDLL (error %u). Aborting.\n",
  286. ErrorCode );
  287. goto Done;
  288. }
  289. HaveGoodSymbols = TRUE;
  290. //
  291. // Read all the rest of the information we need
  292. //
  293. CritSec = AddrCritSec;
  294. DebugInfo = AddrDebugInfo;
  295. if (AddrCritSec == 0 || (AddrEndCritSect != 0 && AddrDebugInfo != 0)) {
  296. //
  297. // Read the critical section address
  298. //
  299. if (ReadPointer (AddrDebugInfo + CriticalSectionFieldOffset, &CritSec) == FALSE ) {
  300. dprintf ("Cannot read the critical section address at 0x%p.\n"
  301. "The memory is probably paged out or the active critical section list is corrupted.\n",
  302. AddrDebugInfo + CriticalSectionFieldOffset );
  303. //
  304. // We don't have any useful information to dump
  305. // since we can't read the address of the critical section structure.
  306. //
  307. // Just display the stack trace since the active critical section list
  308. // might be corrupted.
  309. //
  310. DumpStackTrace = TRUE;
  311. goto DisplayStackTrace;
  312. }
  313. if (AddrCritSec != 0 ) {
  314. //
  315. // We are dumpig all the critical sections in a range.
  316. //
  317. if (CritSec < AddrCritSec || CritSec > AddrEndCritSect) {
  318. //
  319. // We don't want to display this critical section
  320. // because it is out of the range.
  321. //
  322. goto Done;
  323. }
  324. }
  325. //
  326. // Read the the critical section address from the DebugInfo
  327. //
  328. dprintf( "-----------------------------------------\n" );
  329. dprintf ("DebugInfo = 0x%p\n",
  330. AddrDebugInfo );
  331. GetSymbol( CritSec,
  332. Symbol,
  333. &Displacement);
  334. dprintf ("Critical section = 0x%p (%s+0x%I64X)\n",
  335. CritSec,
  336. Symbol,
  337. Displacement );
  338. }
  339. else {
  340. //
  341. // We have the critical section address from our caller
  342. //
  343. GetSymbol( CritSec,
  344. Symbol,
  345. &Displacement);
  346. dprintf( "-----------------------------------------\n" );
  347. dprintf ("Critical section = 0x%p (%s+0x%I64X)\n",
  348. AddrCritSec,
  349. Symbol,
  350. Displacement );
  351. if (DebugInfo == 0) {
  352. //
  353. // Read the DebugInfo address from the critical section structure
  354. //
  355. if (ReadPointer (AddrCritSec + DebugInfoFieldOffset, &DebugInfo) == FALSE) {
  356. dprintf ("Cannot read DebugInfo adddress at 0x%p. Possible causes:\n"
  357. "\t- The critical section is not initialized, deleted or corrupted\n"
  358. "\t- The critical section was a global variable in a DLL that was unloaded\n"
  359. "\t- The memory is paged out\n",
  360. AddrCritSec + DebugInfoFieldOffset );
  361. }
  362. }
  363. if (DebugInfo != 0) {
  364. dprintf ("DebugInfo = 0x%p\n",
  365. DebugInfo );
  366. }
  367. else {
  368. dprintf ("Uninitialized or deleted.\n");
  369. }
  370. }
  371. //
  372. // Read all the rest of the fields of this critical section
  373. //
  374. Success = ReadStructFieldVerbose (CritSec,
  375. "NTDLL!_RTL_CRITICAL_SECTION",
  376. "LockCount",
  377. &LockCount,
  378. sizeof( LockCount ) );
  379. if( Success != TRUE )
  380. {
  381. //
  382. // Couldn't read the LockCount so we cannot say if it's
  383. // locked or not. This can happen especially in stress where everything is
  384. // paged out because of memory pressure.
  385. //
  386. dprintf ("Cannot determine if the critical section is locked or not.\n" );
  387. goto DisplayStackTrace;
  388. }
  389. //
  390. // Determine if the critical section is locked or not
  391. //
  392. if (LockCount == -1) {
  393. //
  394. // The critical section is not locked
  395. //
  396. dprintf ("NOT LOCKED\n");
  397. }
  398. else {
  399. //
  400. // The critical section is currently locked
  401. //
  402. dprintf ("LOCKED\n"
  403. "LockCount = 0x%X\n",
  404. LockCount );
  405. //
  406. // OwningThread
  407. //
  408. Success = ReadPtrStructFieldVerbose( CritSec,
  409. "NTDLL!_RTL_CRITICAL_SECTION",
  410. "OwningThread",
  411. &OwningThread);
  412. if (Success != FALSE)
  413. {
  414. dprintf ("OwningThread = 0x%p\n",
  415. OwningThread );
  416. }
  417. //
  418. // RecursionCount
  419. //
  420. Success = ReadStructFieldVerbose( CritSec,
  421. "NTDLL!_RTL_CRITICAL_SECTION",
  422. "RecursionCount",
  423. &RecursionCount,
  424. sizeof( RecursionCount ) );
  425. if (Success != FALSE)
  426. {
  427. dprintf ("RecursionCount = 0x%X\n",
  428. RecursionCount);
  429. }
  430. }
  431. //
  432. // LockSemaphore
  433. //
  434. Success = ReadStructFieldVerbose (CritSec,
  435. "NTDLL!_RTL_CRITICAL_SECTION",
  436. "LockSemaphore",
  437. &LockSemaphore,
  438. sizeof( LockSemaphore ));
  439. if (Success != FALSE)
  440. {
  441. dprintf ("LockSemaphore = 0x%X\n",
  442. LockSemaphore );
  443. }
  444. //
  445. // SpinCount
  446. //
  447. Success = ReadPtrStructFieldVerbose (CritSec,
  448. "NTDLL!_RTL_CRITICAL_SECTION",
  449. "SpinCount",
  450. &SpinCount);
  451. if (Success != FALSE)
  452. {
  453. dprintf ("SpinCount = 0x%p\n",
  454. SpinCount );
  455. }
  456. //
  457. // Simple checks for orphaned critical sections
  458. //
  459. if (AddrDebugInfo != 0) {
  460. //
  461. // AddrDebugInfo is a DebugInfo address from the active list.
  462. // Verify that the critical section's DebugInfo is pointing
  463. // back to AddrDebugInfo.
  464. //
  465. Success = ReadPtrStructFieldVerbose (CritSec,
  466. "NTDLL!_RTL_CRITICAL_SECTION",
  467. "DebugInfo",
  468. &OtherDebugInfo );
  469. if (Success != FALSE && OtherDebugInfo != AddrDebugInfo)
  470. {
  471. dprintf ("\nWARNING: critical section DebugInfo = 0x%p doesn't point back\n"
  472. "to the DebugInfo found in the active critical sections list = 0x%p.\n"
  473. "The critical section was probably reused without calling DeleteCriticalSection.\n\n",
  474. OtherDebugInfo,
  475. AddrDebugInfo );
  476. Success = ReadStructFieldVerbose (OtherDebugInfo,
  477. "NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  478. "CreatorBackTraceIndex",
  479. &CreatorBackTraceIndex,
  480. sizeof( CreatorBackTraceIndex ) );
  481. StackTraceAddress = GetStackTraceAddress (CreatorBackTraceIndex,
  482. PointerSize );
  483. if (StackTraceAddress != 0)
  484. {
  485. dprintf ("\nStack trace for DebugInfo = 0x%p:\n\n",
  486. OtherDebugInfo );
  487. DumpStackTraceAtAddress (StackTraceAddress,
  488. PointerSize);
  489. }
  490. //
  491. // Dump the second stack trace too
  492. //
  493. DumpStackTrace = TRUE;
  494. }
  495. }
  496. DisplayStackTrace:
  497. if (!DumpStackTrace || DebugInfo == 0) {
  498. goto Done;
  499. }
  500. //
  501. // Dump the initialization stack trace for this critical section
  502. //
  503. Success = ReadStructFieldVerbose (DebugInfo,
  504. "NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  505. "CreatorBackTraceIndex",
  506. &CreatorBackTraceIndex,
  507. sizeof (CreatorBackTraceIndex));
  508. if (Success != FALSE) {
  509. StackTraceAddress = GetStackTraceAddress (CreatorBackTraceIndex,
  510. PointerSize );
  511. if (StackTraceAddress != 0)
  512. {
  513. dprintf ("\n\nStack trace for DebugInfo = 0x%p:\n\n",
  514. DebugInfo );
  515. DumpStackTraceAtAddress (StackTraceAddress,
  516. PointerSize);
  517. }
  518. }
  519. Done:
  520. return HaveGoodSymbols;
  521. }
  522. /////////////////////////////////////////////////////////////////////////////
  523. ULONG CriticalSectionFieldOffset;
  524. ULONG DebugInfoFieldOffset;
  525. ULONG LeftChildFieldOffset;
  526. ULONG RightChildFieldOffset;
  527. ULONG EnterThreadFieldOffset;
  528. ULONG WaitThreadFieldOffset;
  529. ULONG TryEnterThreadFieldOffset;
  530. ULONG LeaveThreadFieldOffset;
  531. BOOL
  532. DumpCSTreeRecursively (ULONG Level,
  533. ULONG64 TreeRoot)
  534. {
  535. ULONG64 CriticalSection;
  536. ULONG64 LeftChild;
  537. ULONG64 RightChild;
  538. ULONG64 DebugInfo;
  539. ULONG64 EnterThread;
  540. ULONG64 WaitThread;
  541. ULONG64 TryEnterThread;
  542. ULONG64 LeaveThread;
  543. ULONG64 ErrorCode;
  544. BOOL Continue = TRUE;
  545. if (CheckControlC()) {
  546. Continue = FALSE;
  547. goto Done;
  548. }
  549. //
  550. // Read the current CS address and dump information about it.
  551. //
  552. if (ReadPointer (TreeRoot + CriticalSectionFieldOffset, &CriticalSection) == FALSE) {
  553. dprintf ("Cannot read CriticalSection address at %p\n",
  554. TreeRoot + CriticalSectionFieldOffset);
  555. goto Done;
  556. }
  557. if (ReadPointer (TreeRoot + DebugInfoFieldOffset, &DebugInfo) == FALSE) {
  558. dprintf ("Cannot read DebugInfo address at %p\n",
  559. TreeRoot + DebugInfoFieldOffset);
  560. goto Done;
  561. }
  562. //
  563. // Read the left child address.
  564. //
  565. if (ReadPointer (TreeRoot + LeftChildFieldOffset, &LeftChild) == FALSE) {
  566. dprintf ("Cannot read left child address at %p\n",
  567. TreeRoot + LeftChildFieldOffset);
  568. goto Done;
  569. }
  570. //
  571. // Read the right child address.
  572. //
  573. if (ReadPointer (TreeRoot + RightChildFieldOffset, &RightChild) == FALSE) {
  574. dprintf ("Cannot read right child address at %p\n",
  575. TreeRoot + RightChildFieldOffset);
  576. goto Done;
  577. }
  578. //
  579. // Dump the information about the current node.
  580. //
  581. dprintf ("%5u %p %p %p ",
  582. Level,
  583. TreeRoot,
  584. CriticalSection,
  585. DebugInfo);
  586. if (EnterThreadFieldOffset != 0 ) {
  587. //
  588. // Read the EnterThread
  589. //
  590. if (ReadPointer (TreeRoot + EnterThreadFieldOffset, &EnterThread) == FALSE) {
  591. dprintf ("Cannot read EnterThread at %p\n",
  592. TreeRoot + EnterThreadFieldOffset);
  593. goto OlderThan3591;
  594. }
  595. //
  596. // Read the WaitThread
  597. //
  598. if (ReadPointer (TreeRoot + WaitThreadFieldOffset, &WaitThread) == FALSE) {
  599. dprintf ("Cannot read WaitThread at %p\n",
  600. TreeRoot + WaitThreadFieldOffset);
  601. goto OlderThan3591;
  602. }
  603. //
  604. // Read the TryEnterThread
  605. //
  606. if (ReadPointer (TreeRoot + TryEnterThreadFieldOffset, &TryEnterThread) == FALSE) {
  607. dprintf ("Cannot read TryEnterThread at %p\n",
  608. TreeRoot + TryEnterThreadFieldOffset);
  609. goto OlderThan3591;
  610. }
  611. //
  612. // Read the LeaveThread
  613. //
  614. if (ReadPointer (TreeRoot + LeaveThreadFieldOffset, &LeaveThread) == FALSE) {
  615. dprintf ("Cannot read right LeaveThread at %p\n",
  616. TreeRoot + LeaveThreadFieldOffset);
  617. goto OlderThan3591;
  618. }
  619. dprintf ("%8p %8p %8p %8p\n",
  620. EnterThread,
  621. WaitThread,
  622. TryEnterThread,
  623. LeaveThread);
  624. }
  625. else {
  626. dprintf ("\n");
  627. }
  628. OlderThan3591:
  629. //
  630. // Dump the left subtree.
  631. //
  632. if (LeftChild != 0) {
  633. Continue = DumpCSTreeRecursively (Level + 1,
  634. LeftChild);
  635. if (Continue == FALSE) {
  636. goto Done;
  637. }
  638. }
  639. //
  640. // Dump the right subtree.
  641. //
  642. if (RightChild != 0) {
  643. Continue = DumpCSTreeRecursively (Level + 1,
  644. RightChild);
  645. if (Continue == FALSE) {
  646. goto Done;
  647. }
  648. }
  649. Done:
  650. return Continue;
  651. }
  652. /////////////////////////////////////////////////////////////////////////////
  653. VOID
  654. DisplayHelp( VOID )
  655. {
  656. dprintf( "!cs [-s] - dump all the active critical sections in the current process.\n" );
  657. dprintf( "!cs [-s] address - dump critical section at this address.\n" );
  658. dprintf( "!cs [-s] address1 address2 - dump all the active critical sections in this range.\n" );
  659. dprintf( "!cs [-s] -d address - dump critical section corresponding to DebugInfo at this address.\n" );
  660. dprintf( "\n\"-s\" will dump the critical section initialization stack trace if it's available.\n" );
  661. }
  662. /////////////////////////////////////////////////////////////////////////////
  663. DECLARE_API( cs )
  664. /*++
  665. Routine Description:
  666. Dump critical sections (both Kernel and User Debugger)
  667. Arguments:
  668. args - [address] [options]
  669. Return Value:
  670. None
  671. --*/
  672. {
  673. ULONG64 AddrCritSec;
  674. ULONG64 AddrEndCritSect;
  675. ULONG64 AddrDebugInfo;
  676. ULONG64 AddrListHead;
  677. ULONG64 ListHead;
  678. ULONG64 Next;
  679. ULONG64 AddrTreeRoot;
  680. ULONG64 TreeRoot = 0;
  681. LPCSTR Current;
  682. LPCSTR NextParam;
  683. BOOL StackTraces = FALSE;
  684. BOOL UseTree = FALSE;
  685. BOOL HaveGoodSymbols;
  686. ULONG ErrorCode;
  687. ULONG ProcessLocksListFieldOffset;
  688. ULONG Level;
  689. ULONG PointerSize;
  690. INIT_API();
  691. AddrDebugInfo = 0;
  692. AddrCritSec = 0;
  693. AddrEndCritSect = 0;
  694. //
  695. // Parse the command line arguments for:
  696. //
  697. // -s : dump initialization stack traces
  698. // -d : find the critical section using a DebugInfo pointer
  699. //
  700. for (Current = args; *Current != '\0'; Current += 1) {
  701. if (*Current == '-') {
  702. Current += 1;
  703. switch (*Current) {
  704. case '?':
  705. case 'h':
  706. case 'H':
  707. //
  708. // Need some help.
  709. //
  710. DisplayHelp();
  711. goto Done;
  712. case 's':
  713. case 'S':
  714. //
  715. // Dump stack traces
  716. //
  717. StackTraces = TRUE;
  718. if(*( Current + 1 ) != '\0') {
  719. Current += 1;
  720. }
  721. break;
  722. case 't':
  723. case 'T':
  724. //
  725. // Use the critical section tree
  726. //
  727. UseTree = TRUE;
  728. if(*( Current + 1 ) != '\0') {
  729. Current += 1;
  730. }
  731. do {
  732. Current += 1;
  733. }
  734. while (*Current == ' ');
  735. if (*Current != '\0') {
  736. TreeRoot = GetExpression(Current);
  737. }
  738. break;
  739. case 'd':
  740. case 'D':
  741. //
  742. // The next parameter should be the DebugInfo
  743. //
  744. do {
  745. Current += 1;
  746. }
  747. while (*Current == ' ');
  748. AddrDebugInfo = GetExpression(Current);
  749. if (AddrDebugInfo == 0) {
  750. dprintf("!cs: expected DebugInfo address after -d\n");
  751. //
  752. // Decrement Current since the for loop will increment it again.
  753. // Otherwise, if this is the end of the string we will overrun
  754. // the args buffer.
  755. //
  756. Current -= 1;
  757. goto Done;
  758. }
  759. else {
  760. goto DoneParsingArguments;
  761. }
  762. break;
  763. case ' ':
  764. Current += 1;
  765. break;
  766. default:
  767. dprintf ("!cs: invalid option flag '-%c'\n",
  768. *Current);
  769. break;
  770. }
  771. }
  772. else if(*Current == ' ') {
  773. Current ++;
  774. }
  775. else {
  776. break;
  777. }
  778. }
  779. DoneParsingArguments:
  780. //
  781. // Get the size of a pointer
  782. //
  783. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  784. PointerSize = 4;
  785. }
  786. else {
  787. PointerSize = 8;
  788. }
  789. if( AddrDebugInfo == 0 && UseTree == FALSE )
  790. {
  791. //
  792. // If the user doesn't want us to use a DebugInfo
  793. // then he might have asked us to dump a critical section
  794. //
  795. if (*Current != '\0')
  796. {
  797. AddrCritSec = GetExpression(Current);
  798. if (AddrCritSec != 0) {
  799. //
  800. // We might have an additional argument if the user
  801. // wants to dump all the active critical sections in
  802. // an address range.
  803. //
  804. NextParam = strchr (Current,
  805. ' ' );
  806. if (NextParam != NULL) {
  807. AddrEndCritSect = GetExpression(NextParam);
  808. }
  809. }
  810. }
  811. }
  812. //
  813. // Start the real work
  814. //
  815. if ((AddrCritSec != 0 && AddrEndCritSect == 0) || AddrDebugInfo != 0)
  816. {
  817. //
  818. // The user wants details only about this critical section
  819. //
  820. DumpCriticalSection (AddrCritSec, // critical section address
  821. 0, // end of address range if we are searching for critical sections
  822. AddrDebugInfo, // debug info address
  823. PointerSize,
  824. StackTraces ); // dump the stack trace
  825. }
  826. else
  827. {
  828. if (UseTree == FALSE) {
  829. //
  830. // Parse all the critical sections list
  831. //
  832. //
  833. // Get the offset of the list entry in the DebugInfo structure
  834. //
  835. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  836. "ProcessLocksList",
  837. &ProcessLocksListFieldOffset );
  838. if (ErrorCode != S_OK) {
  839. dprintf ("Bad symbols for NTDLL (error %u). Aborting.\n",
  840. ErrorCode );
  841. goto Done;
  842. }
  843. //
  844. // Locate the address of the list head.
  845. //
  846. AddrListHead = GetExpression ("&NTDLL!RtlCriticalSectionList");
  847. if (AddrListHead == 0 ) {
  848. dprintf( "!cs: Unable to resolve NTDLL!RtlCriticalSectionList\n"
  849. "Please check your symbols\n" );
  850. goto Done;
  851. }
  852. //
  853. // Read the list head
  854. //
  855. if (ReadPointer(AddrListHead, &ListHead) == FALSE) {
  856. dprintf( "!cs: Unable to read memory at NTDLL!RtlCriticalSectionList\n" );
  857. goto Done;
  858. }
  859. Next = ListHead;
  860. while (Next != AddrListHead) {
  861. if (CheckControlC()) {
  862. break;
  863. }
  864. HaveGoodSymbols = DumpCriticalSection (
  865. AddrCritSec, // critical section address
  866. AddrEndCritSect, // end of address range if we are searching for critical sections
  867. Next - ProcessLocksListFieldOffset, // debug info address
  868. PointerSize,
  869. StackTraces ); // dump the stack trace
  870. //
  871. // Read the pointer to Next element from the list
  872. //
  873. if( HaveGoodSymbols == FALSE )
  874. {
  875. break;
  876. }
  877. if (ReadPointer (Next, &Next) == FALSE) {
  878. dprintf ("!cs: Unable to read list entry at 0x%p - aborting.\n",
  879. Next);
  880. goto Done;
  881. }
  882. }
  883. }
  884. else {
  885. //
  886. // Parse all the critical section tree in verifier.dll.
  887. //
  888. if (TreeRoot == 0) {
  889. AddrTreeRoot = GetExpression ("&verifier!CritSectSplayRoot");
  890. if (AddrTreeRoot == 0 ) {
  891. dprintf( "!cs: Unable to resolve verifier!CritSectSplayRoot\n"
  892. "Please check your symbols\n" );
  893. goto Done;
  894. }
  895. //
  896. // Read the tree root.
  897. //
  898. if (ReadPointer(AddrTreeRoot, &TreeRoot) == FALSE) {
  899. dprintf( "!cs: Unable to read memory at verifier!CritSectSplayRoot\n" );
  900. goto Done;
  901. }
  902. }
  903. dprintf ("Tree root %p\n",
  904. TreeRoot);
  905. //
  906. // Get the offset of the CriticalSection in the CRITICAL_SECTION_SPLAY_NODE structure.
  907. //
  908. ErrorCode = GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  909. "CriticalSection",
  910. &CriticalSectionFieldOffset );
  911. if (ErrorCode != S_OK) {
  912. dprintf ("Bad symbols for verifier.dll (error %u). Aborting.\n",
  913. ErrorCode );
  914. goto Done;
  915. }
  916. //
  917. // Get the offset of the DebugInfo in the CRITICAL_SECTION_SPLAY_NODE structure.
  918. //
  919. ErrorCode = GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  920. "DebugInfo",
  921. &DebugInfoFieldOffset );
  922. if (ErrorCode != S_OK) {
  923. dprintf ("Bad symbols for verifier.dll (error %u). Aborting.\n",
  924. ErrorCode );
  925. goto Done;
  926. }
  927. //
  928. // Get the offset of the LeftChild in the CRITICAL_SECTION_SPLAY_NODE structure.
  929. //
  930. ErrorCode = GetFieldOffset ("verifier!_RTL_SPLAY_LINKS",
  931. "LeftChild",
  932. &LeftChildFieldOffset );
  933. if (ErrorCode != S_OK) {
  934. dprintf ("Bad symbols for verifier.dll (error %u). Aborting.\n",
  935. ErrorCode );
  936. goto Done;
  937. }
  938. //
  939. // Get the offset of the RightChild in the CRITICAL_SECTION_SPLAY_NODE structure.
  940. //
  941. ErrorCode = GetFieldOffset ("verifier!_RTL_SPLAY_LINKS",
  942. "RightChild",
  943. &RightChildFieldOffset );
  944. if (ErrorCode != S_OK) {
  945. dprintf ("Bad symbols for verifier.dll (error %u). Aborting.\n",
  946. ErrorCode );
  947. goto Done;
  948. }
  949. //
  950. // Get the offset of the EnterThread, WaitThread, TryEnterThread, LeaveThread fields
  951. // in the CRITICAL_SECTION_SPLAY_NODE structure.
  952. // These fields were added after build 3590 (.NET Server Beta 3).
  953. //
  954. ErrorCode = GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  955. "EnterThread",
  956. &EnterThreadFieldOffset );
  957. if (ErrorCode == S_OK) {
  958. GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  959. "WaitThread",
  960. &WaitThreadFieldOffset );
  961. GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  962. "TryEnterThread",
  963. &TryEnterThreadFieldOffset );
  964. GetFieldOffset ("verifier!_CRITICAL_SECTION_SPLAY_NODE",
  965. "LeaveThread",
  966. &LeaveThreadFieldOffset );
  967. }
  968. else {
  969. //
  970. // These fields are either not defined or we have a problem with ths symbols.
  971. //
  972. EnterThreadFieldOffset = 0;
  973. }
  974. //
  975. // Dump the tree recursively.
  976. //
  977. if (PointerSize == 4 ) {
  978. dprintf ("Level %8s %8s %8s %8s %8s %8s %8s\n",
  979. "Node",
  980. "CS",
  981. "Debug",
  982. "Enter",
  983. "Wait",
  984. "TryEnter",
  985. "Leave");
  986. dprintf ("--------------------------------------------------------------------\n");
  987. }
  988. else {
  989. dprintf ("Level %16s %16s %16s %8s %8s %8s %8s\n",
  990. "Node",
  991. "CS",
  992. "Debug",
  993. "Enter",
  994. "Wait",
  995. "TryEnter",
  996. "Leave");
  997. dprintf ("--------------------------------------------------------------------------------------------\n");
  998. }
  999. Level = 0;
  1000. DumpCSTreeRecursively (Level,
  1001. TreeRoot);
  1002. }
  1003. }
  1004. Done:
  1005. EXIT_API();
  1006. return S_OK;
  1007. }