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.

1006 lines
26 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. ErrorCode = ReadPtr( AddrStructBase + FieldOffset,
  77. Buffer );
  78. if (ErrorCode != S_OK) {
  79. dprintf( "Cannot read structure field value at 0x%p, error %u\n",
  80. AddrStructBase + FieldOffset,
  81. ErrorCode );
  82. }
  83. else {
  84. Success = TRUE;
  85. }
  86. }
  87. else {
  88. dprintf( "Cannot get field offset of %s in structure %s, error %u\n",
  89. StructFieldName,
  90. StructTypeName,
  91. ErrorCode );
  92. }
  93. return Success;
  94. }
  95. /////////////////////////////////////////////////////////////////////////////
  96. ULONG64
  97. GetStackTraceAddress( ULONG StackTraceIndex,
  98. ULONG PointerSize )
  99. {
  100. ULONG64 TraceDatabaseAddress;
  101. ULONG64 TraceDatabase;
  102. ULONG64 EntryIndexArray;
  103. ULONG64 StackTraceAddress;
  104. ULONG64 StackTraceToDump;
  105. ULONG NumberOfEntriesAdded;
  106. ULONG ErrorCode;
  107. BOOL Success;
  108. StackTraceToDump = 0;
  109. //
  110. // Stack trace database address
  111. //
  112. TraceDatabaseAddress = GetExpression("&NTDLL!RtlpStackTraceDataBase");
  113. if ( TraceDatabaseAddress == 0 ) {
  114. dprintf( "!cs: Unable to resolve NTDLL!RtlpStackTraceDataBase\n"
  115. "Please check your symbols\n" );
  116. goto Done;
  117. }
  118. ErrorCode = ReadPtr (TraceDatabaseAddress,
  119. &TraceDatabase );
  120. if (ErrorCode != S_OK) {
  121. dprintf( "!cs: Cannot read pointer at NTDLL!RtlpStackTraceDataBase\n" );
  122. goto Done;
  123. }
  124. else if (TraceDatabase == 0) {
  125. dprintf( "NTDLL!RtlpStackTraceDataBase is NULL. Probably the stack traces are not enabled.\n" );
  126. goto Done;
  127. }
  128. //
  129. // Read the number of entries in the database
  130. //
  131. Success = ReadStructFieldVerbose (TraceDatabase,
  132. "NTDLL!_STACK_TRACE_DATABASE",
  133. "NumberOfEntriesAdded",
  134. &NumberOfEntriesAdded,
  135. sizeof( NumberOfEntriesAdded ) );
  136. if( Success == FALSE ) {
  137. dprintf( "Cannot read the number of stack traces database entries\n" );
  138. goto Done;
  139. }
  140. else if( StackTraceIndex == 0 ) {
  141. dprintf( "No stack trace found.\n" );
  142. goto Done;
  143. }
  144. else if( NumberOfEntriesAdded < StackTraceIndex ) {
  145. dprintf( "Stack trace index 0x%X is invalid, current number of stack traces is 0x%X\n",
  146. StackTraceIndex,
  147. NumberOfEntriesAdded );
  148. goto Done;
  149. }
  150. //
  151. // Find the array of stack traces
  152. //
  153. Success = ReadPtrStructFieldVerbose (TraceDatabase,
  154. "NTDLL!_STACK_TRACE_DATABASE",
  155. "EntryIndexArray",
  156. &EntryIndexArray );
  157. if( Success == FALSE ) {
  158. dprintf( "Cannot read the stack database array address\n" );
  159. goto Done;
  160. }
  161. //
  162. // Compute the address of our stack trace pointer
  163. //
  164. StackTraceAddress = EntryIndexArray - StackTraceIndex * PointerSize;
  165. //
  166. // Read the pointer to our trace entry in the array
  167. //
  168. ErrorCode = ReadPtr (StackTraceAddress,
  169. &StackTraceToDump );
  170. if (ErrorCode != S_OK) {
  171. dprintf( "Cannot read stack trace address at 0x%p\n",
  172. StackTraceAddress );
  173. StackTraceToDump = 0;
  174. }
  175. Done:
  176. return StackTraceToDump;
  177. }
  178. //////////////////////////////////////////////////////////////////////
  179. VOID
  180. DumpStackTraceAtAddress (ULONG64 StackTraceAddress,
  181. ULONG PointerSize)
  182. {
  183. ULONG64 CrtTraceAddress;
  184. ULONG64 CodeAddress;
  185. ULONG64 Displacement;
  186. ULONG ErrorCode;
  187. ULONG BackTraceFieldOffset;
  188. USHORT Depth;
  189. USHORT CrtEntryIndex;
  190. BOOL Success;
  191. CHAR Symbol[ 1024 ];
  192. //
  193. // Read the stack trace depth
  194. //
  195. Success = ReadStructFieldVerbose (StackTraceAddress,
  196. "NTDLL!_RTL_STACK_TRACE_ENTRY",
  197. "Depth",
  198. &Depth,
  199. sizeof( Depth ));
  200. if( Success == FALSE ) {
  201. dprintf ("!cs: Cannot read depth for stack trace at 0x%p\n",
  202. StackTraceAddress);
  203. goto Done;
  204. }
  205. //
  206. // Limit the depth to 20 to protect ourselves from corrupted data
  207. //
  208. Depth = __min( Depth, 20 );
  209. //
  210. // Get a pointer to the BackTrace array
  211. //
  212. ErrorCode = GetFieldOffset ("NTDLL!_RTL_STACK_TRACE_ENTRY",
  213. "BackTrace",
  214. &BackTraceFieldOffset);
  215. if (ErrorCode != S_OK) {
  216. dprintf ("!cs: Cannot get the BackTrace field offset\n");
  217. goto Done;
  218. }
  219. CrtTraceAddress = StackTraceAddress + BackTraceFieldOffset;
  220. //
  221. // Dump this stack trace
  222. //
  223. for( CrtEntryIndex = 0; CrtEntryIndex < Depth; CrtEntryIndex += 1 ) {
  224. ErrorCode = ReadPtr (CrtTraceAddress,
  225. &CodeAddress );
  226. if (ErrorCode != S_OK) {
  227. dprintf ("!cs: Cannot read address at 0x%p\n",
  228. CrtTraceAddress );
  229. }
  230. GetSymbol( CodeAddress,
  231. Symbol,
  232. &Displacement);
  233. dprintf ("0x%p: %s+0x%I64X\n",
  234. CodeAddress,
  235. Symbol,
  236. Displacement );
  237. CrtTraceAddress += PointerSize;
  238. }
  239. Done:
  240. NOTHING;
  241. }
  242. //////////////////////////////////////////////////////////////////////
  243. BOOL
  244. DumpCriticalSection ( ULONG64 AddrCritSec,
  245. ULONG64 AddrEndCritSect,
  246. ULONG64 AddrDebugInfo,
  247. BOOL DumpStackTrace )
  248. {
  249. ULONG64 DebugInfo;
  250. ULONG64 OtherDebugInfo;
  251. ULONG64 CritSec;
  252. ULONG64 SpinCount;
  253. ULONG64 OwningThread;
  254. ULONG64 LockSemaphore;
  255. ULONG64 StackTraceAddress;
  256. ULONG64 Displacement;
  257. LONG LockCount;
  258. LONG RecursionCount;
  259. USHORT CreatorBackTraceIndex;
  260. ULONG PointerSize;
  261. ULONG DebugInfoFieldOffset;
  262. ULONG CriticalSectionFieldOffset;
  263. ULONG ErrorCode;
  264. BOOL HaveGoodSymbols;
  265. BOOL Success;
  266. CHAR Symbol[1024];
  267. HaveGoodSymbols = FALSE;
  268. //
  269. // The caller must supply at least one of the
  270. // critical section or debug information address.
  271. //
  272. if (AddrCritSec == 0 && AddrDebugInfo == 0) {
  273. dprintf ("Internal debugger extension error: Both critical section and debug info are NULL\n");
  274. goto Done;
  275. }
  276. //
  277. // Get the field offsets for various structures and check if we have
  278. // good symbols, with type information.
  279. //
  280. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION",
  281. "DebugInfo",
  282. &DebugInfoFieldOffset );
  283. if (ErrorCode != S_OK)
  284. {
  285. dprintf( "Bad symbols for NTDLL (error %u). Aborting.\n",
  286. ErrorCode );
  287. goto Done;
  288. }
  289. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  290. "CriticalSection",
  291. &CriticalSectionFieldOffset );
  292. if (ErrorCode != S_OK)
  293. {
  294. dprintf( "Bad symbols for NTDLL (error %u). Aborting.\n",
  295. ErrorCode );
  296. goto Done;
  297. }
  298. //
  299. // Get the size of a pointer
  300. //
  301. PointerSize = GetTypeSize ("ntdll!PVOID");
  302. if (PointerSize == 0) {
  303. dprintf ("Cannot get the pointer size.\n");
  304. goto Done;
  305. }
  306. HaveGoodSymbols = TRUE;
  307. //
  308. // Read all the rest of the information we need
  309. //
  310. CritSec = AddrCritSec;
  311. DebugInfo = AddrDebugInfo;
  312. if (AddrCritSec == 0 || (AddrEndCritSect != 0 && AddrDebugInfo != 0)) {
  313. //
  314. // Read the critical section address
  315. //
  316. ErrorCode = ReadPtr (AddrDebugInfo + CriticalSectionFieldOffset,
  317. &CritSec );
  318. if (ErrorCode != S_OK)
  319. {
  320. dprintf ("Cannot read the critical section address at 0x%p.\n"
  321. "The memory is probably paged out or the active critical section list is corrupted.\n",
  322. AddrDebugInfo + CriticalSectionFieldOffset );
  323. //
  324. // We don't have any useful information to dump
  325. // since we can't read the address of the critical section structure.
  326. //
  327. // Just display the stack trace since the active critical section list
  328. // might be corrupted.
  329. //
  330. DumpStackTrace = TRUE;
  331. goto DisplayStackTrace;
  332. }
  333. if (AddrCritSec != 0 ) {
  334. //
  335. // We are dumpig all the critical sections in a range.
  336. //
  337. if (CritSec < AddrCritSec || CritSec > AddrEndCritSect) {
  338. //
  339. // We don't want to display this critical section
  340. // because it is out of the range.
  341. //
  342. goto Done;
  343. }
  344. }
  345. //
  346. // Read the the critical section address from the DebugInfo
  347. //
  348. dprintf( "-----------------------------------------\n" );
  349. dprintf ("DebugInfo = 0x%p\n",
  350. AddrDebugInfo );
  351. GetSymbol( CritSec,
  352. Symbol,
  353. &Displacement);
  354. dprintf ("Critical section = 0x%p (%s+0x%I64X)\n",
  355. CritSec,
  356. Symbol,
  357. Displacement );
  358. }
  359. else {
  360. //
  361. // We have the critical section address from our caller
  362. //
  363. GetSymbol( CritSec,
  364. Symbol,
  365. &Displacement);
  366. dprintf( "-----------------------------------------\n" );
  367. dprintf ("Critical section = 0x%p (%s+0x%I64X)\n",
  368. AddrCritSec,
  369. Symbol,
  370. Displacement );
  371. if ( DebugInfo == 0 ) {
  372. //
  373. // Read the DebugInfo address from the critical section structure
  374. //
  375. ErrorCode = ReadPtr (AddrCritSec + DebugInfoFieldOffset,
  376. &DebugInfo );
  377. if (ErrorCode != S_OK) {
  378. dprintf ("Cannot read DebugInfo adddress at 0x%p. Possible causes:\n"
  379. "\t- The critical section is not initialized, deleted or corrupted\n"
  380. "\t- The critical section was a global variable in a DLL that was unloaded\n"
  381. "\t- The memory is paged out\n",
  382. AddrCritSec + DebugInfoFieldOffset );
  383. }
  384. }
  385. if (DebugInfo != 0) {
  386. dprintf ("DebugInfo = 0x%p\n",
  387. DebugInfo );
  388. }
  389. }
  390. //
  391. // Read all the rest of the fields of this critical section
  392. //
  393. Success = ReadStructFieldVerbose (CritSec,
  394. "NTDLL!_RTL_CRITICAL_SECTION",
  395. "LockCount",
  396. &LockCount,
  397. sizeof( LockCount ) );
  398. if( Success != TRUE )
  399. {
  400. //
  401. // Couldn't read the LockCount so we cannot say if it's
  402. // locked or not. This can happen especially in stress where everything is
  403. // paged out because of memory pressure.
  404. //
  405. dprintf ("Cannot determine if the critical section is locked or not.\n" );
  406. goto DisplayStackTrace;
  407. }
  408. //
  409. // Determine if the critical section is locked or not
  410. //
  411. if (LockCount == -1) {
  412. //
  413. // The critical section is not locked
  414. //
  415. dprintf ("NOT LOCKED\n");
  416. }
  417. else {
  418. //
  419. // The critical section is currently locked
  420. //
  421. dprintf ("LOCKED\n"
  422. "LockCount = 0x%X\n",
  423. LockCount );
  424. //
  425. // OwningThread
  426. //
  427. Success = ReadPtrStructFieldVerbose( CritSec,
  428. "NTDLL!_RTL_CRITICAL_SECTION",
  429. "OwningThread",
  430. &OwningThread);
  431. if (Success != FALSE)
  432. {
  433. dprintf ("OwningThread = 0x%p\n",
  434. OwningThread );
  435. }
  436. //
  437. // RecursionCount
  438. //
  439. Success = ReadStructFieldVerbose( CritSec,
  440. "NTDLL!_RTL_CRITICAL_SECTION",
  441. "RecursionCount",
  442. &RecursionCount,
  443. sizeof( RecursionCount ) );
  444. if (Success != FALSE)
  445. {
  446. dprintf ("RecursionCount = 0x%X\n",
  447. RecursionCount);
  448. }
  449. }
  450. //
  451. // LockSemaphore
  452. //
  453. Success = ReadStructFieldVerbose (CritSec,
  454. "NTDLL!_RTL_CRITICAL_SECTION",
  455. "LockSemaphore",
  456. &LockSemaphore,
  457. sizeof( LockSemaphore ));
  458. if (Success != FALSE)
  459. {
  460. dprintf ("LockSemaphore = 0x%X\n",
  461. LockSemaphore );
  462. }
  463. //
  464. // SpinCount
  465. //
  466. Success = ReadPtrStructFieldVerbose (CritSec,
  467. "NTDLL!_RTL_CRITICAL_SECTION",
  468. "SpinCount",
  469. &SpinCount);
  470. if (Success != FALSE)
  471. {
  472. dprintf ("SpinCount = 0x%p\n",
  473. SpinCount );
  474. }
  475. //
  476. // Simple checks for orphaned critical sections
  477. //
  478. if (AddrDebugInfo != 0) {
  479. //
  480. // AddrDebugInfo is a DebugInfo address from the active list.
  481. // Verify that the critical section's DebugInfo is pointing
  482. // back to AddrDebugInfo.
  483. //
  484. Success = ReadPtrStructFieldVerbose (CritSec,
  485. "NTDLL!_RTL_CRITICAL_SECTION",
  486. "DebugInfo",
  487. &OtherDebugInfo );
  488. if (Success != FALSE && OtherDebugInfo != AddrDebugInfo)
  489. {
  490. dprintf ("\nWARNING: critical section DebugInfo = 0x%p doesn't point back\n"
  491. "to the DebugInfo found in the active critical sections list = 0x%p.\n"
  492. "The critical section was probably reused without calling DeleteCriticalSection.\n\n",
  493. OtherDebugInfo,
  494. AddrDebugInfo );
  495. Success = ReadStructFieldVerbose (OtherDebugInfo,
  496. "NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  497. "CreatorBackTraceIndex",
  498. &CreatorBackTraceIndex,
  499. sizeof( CreatorBackTraceIndex ) );
  500. StackTraceAddress = GetStackTraceAddress (CreatorBackTraceIndex,
  501. PointerSize );
  502. if (StackTraceAddress != 0)
  503. {
  504. dprintf ("\nStack trace for DebugInfo = 0x%p:\n\n",
  505. OtherDebugInfo );
  506. DumpStackTraceAtAddress (StackTraceAddress,
  507. PointerSize);
  508. }
  509. //
  510. // Dump the second stack trace too
  511. //
  512. DumpStackTrace = TRUE;
  513. }
  514. }
  515. DisplayStackTrace:
  516. if (!DumpStackTrace) {
  517. goto Done;
  518. }
  519. //
  520. // Dump the initialization stack trace for this critical section
  521. //
  522. Success = ReadStructFieldVerbose (DebugInfo,
  523. "NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  524. "CreatorBackTraceIndex",
  525. &CreatorBackTraceIndex,
  526. sizeof (CreatorBackTraceIndex));
  527. if (Success != FALSE) {
  528. StackTraceAddress = GetStackTraceAddress (CreatorBackTraceIndex,
  529. PointerSize );
  530. if (StackTraceAddress != 0)
  531. {
  532. dprintf ("\n\nStack trace for DebugInfo = 0x%p:\n\n",
  533. DebugInfo );
  534. DumpStackTraceAtAddress (StackTraceAddress,
  535. PointerSize);
  536. }
  537. }
  538. Done:
  539. return HaveGoodSymbols;
  540. }
  541. /////////////////////////////////////////////////////////////////////////////
  542. VOID
  543. DisplayHelp( VOID )
  544. {
  545. dprintf( "!cs [-s] - dump all the active critical sections in the current process.\n" );
  546. dprintf( "!cs [-s] address - dump critical section at this address.\n" );
  547. dprintf( "!cs [-s] address1 address2 - dump all the active critical sections in this range.\n" );
  548. dprintf( "!cs [-s] -d address - dump critical section corresponding to DebugInfo at this address.\n" );
  549. dprintf( "\n\"-s\" will dump the critical section initialization stack trace if it's available.\n" );
  550. }
  551. /////////////////////////////////////////////////////////////////////////////
  552. DECLARE_API( cs )
  553. /*++
  554. Routine Description:
  555. Dump critical sections (both Kernel and User Debugger)
  556. Arguments:
  557. args - [address] [options]
  558. Return Value:
  559. None
  560. --*/
  561. {
  562. ULONG64 AddrCritSec;
  563. ULONG64 AddrEndCritSect;
  564. ULONG64 AddrDebugInfo;
  565. ULONG64 AddrListHead;
  566. ULONG64 ListHead;
  567. ULONG64 Next;
  568. LPCSTR Current;
  569. LPCSTR NextParam;
  570. BOOL StackTraces = FALSE;
  571. BOOL HaveGoodSymbols;
  572. ULONG ErrorCode;
  573. ULONG ProcessLocksListFieldOffset;
  574. INIT_API();
  575. AddrDebugInfo = 0;
  576. AddrCritSec = 0;
  577. AddrEndCritSect = 0;
  578. //
  579. // Parse the command line arguments for:
  580. //
  581. // -s : dump initialization stack traces
  582. // -d : find the critical section using a DebugInfo pointer
  583. //
  584. for (Current = args; *Current != '\0'; Current += 1) {
  585. if (*Current == '-') {
  586. Current += 1;
  587. switch (*Current) {
  588. case '?':
  589. case 'h':
  590. case 'H':
  591. //
  592. // Need some help.
  593. //
  594. DisplayHelp();
  595. goto Done;
  596. case 's':
  597. case 'S':
  598. //
  599. // Dump stack traces
  600. //
  601. StackTraces = TRUE;
  602. if(*( Current + 1 ) != '\0') {
  603. Current += 1;
  604. }
  605. break;
  606. case 'd':
  607. case 'D':
  608. //
  609. // The next parameter should be the DebugInfo
  610. //
  611. do {
  612. Current += 1;
  613. }
  614. while (*Current == ' ');
  615. AddrDebugInfo = GetExpression(Current);
  616. if (AddrDebugInfo == 0) {
  617. dprintf("!cs: expected DebugInfo address after -d\n");
  618. //
  619. // Decrement Current since the for loop will increment it again.
  620. // Otherwise, if this is the end of the string we will overrun
  621. // the args buffer.
  622. //
  623. Current -= 1;
  624. goto Done;
  625. }
  626. else {
  627. goto DoneParsingArguments;
  628. }
  629. break;
  630. case ' ':
  631. Current += 1;
  632. break;
  633. default:
  634. dprintf ("!cs: invalid option flag '-%c'\n",
  635. *Current);
  636. break;
  637. }
  638. }
  639. else if(*Current == ' ') {
  640. Current ++;
  641. }
  642. else {
  643. break;
  644. }
  645. }
  646. DoneParsingArguments:
  647. if( AddrDebugInfo == 0 )
  648. {
  649. //
  650. // If the user doesn't want us to use a DebugInfo
  651. // then he might have asked us to dump a critical section
  652. //
  653. if (*Current != '\0')
  654. {
  655. AddrCritSec = GetExpression(Current);
  656. if (AddrCritSec != 0) {
  657. //
  658. // We might have an additional argument if the user
  659. // wants to dump all the active critical sections in
  660. // an address range.
  661. //
  662. NextParam = strchr (Current,
  663. ' ' );
  664. if (NextParam != NULL) {
  665. AddrEndCritSect = GetExpression(NextParam);
  666. }
  667. }
  668. }
  669. }
  670. //
  671. // Start the real work
  672. //
  673. if ((AddrCritSec != 0 && AddrEndCritSect == 0) || AddrDebugInfo != 0)
  674. {
  675. //
  676. // The user wants details only about this critical section
  677. //
  678. DumpCriticalSection (AddrCritSec, // critical section address
  679. 0, // end of address range if we are searching for critical sections
  680. AddrDebugInfo, // debug info address
  681. StackTraces ); // dump the stack trace
  682. }
  683. else
  684. {
  685. //
  686. // Get the offset of the list entry in the DebugInfo structure
  687. //
  688. ErrorCode = GetFieldOffset ("NTDLL!_RTL_CRITICAL_SECTION_DEBUG",
  689. "ProcessLocksList",
  690. &ProcessLocksListFieldOffset );
  691. if (ErrorCode != S_OK) {
  692. dprintf ("Bad symbols for NTDLL (error %u). Aborting.\n",
  693. ErrorCode );
  694. goto Done;
  695. }
  696. //
  697. // Parse all the critical sections list
  698. //
  699. //
  700. // Locate the address of the list head.
  701. //
  702. AddrListHead = GetExpression ("&NTDLL!RtlCriticalSectionList");
  703. if (AddrListHead == 0 ) {
  704. dprintf( "!cs: Unable to resolve NTDLL!RtlCriticalSectionList\n"
  705. "Please check your symbols\n" );
  706. goto Done;
  707. }
  708. //
  709. // Read the list head
  710. //
  711. ErrorCode = ReadPtr(AddrListHead,
  712. &ListHead );
  713. if (ErrorCode != S_OK) {
  714. dprintf( "!cs: Unable to read memory at NTDLL!RtlCriticalSectionList\n" );
  715. goto Done;
  716. }
  717. Next = ListHead;
  718. while (Next != AddrListHead) {
  719. if (CheckControlC()) {
  720. break;
  721. }
  722. HaveGoodSymbols = DumpCriticalSection (
  723. AddrCritSec, // critical section address
  724. AddrEndCritSect, // end of address range if we are searching for critical sections
  725. Next - ProcessLocksListFieldOffset, // debug info address
  726. StackTraces ); // dump the stack trace
  727. //
  728. // Read the pointer to Next element from the list
  729. //
  730. if( HaveGoodSymbols == FALSE )
  731. {
  732. break;
  733. }
  734. ErrorCode = ReadPtr (Next,
  735. &Next );
  736. if (ErrorCode != S_OK) {
  737. dprintf ("!cs: Unable to read list entry at 0x%p - aborting.\n",
  738. Next);
  739. goto Done;
  740. }
  741. }
  742. }
  743. Done:
  744. EXIT_API();
  745. return S_OK;
  746. }