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.

1333 lines
37 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. deadlock.c
  5. Abstract:
  6. This module implements the debug extension for the deadlock
  7. verification package for critical section operations.
  8. Environment:
  9. User Mode
  10. Author:
  11. Silviu Calinoiu (SilviuC) 6-Feb-2002
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. //
  17. // This has to be in sync with the definition from
  18. // base\win32\vrifier\deadlock.c
  19. //
  20. #define AVRF_DEADLOCK_HASH_BINS 0x1F
  21. #if 0
  22. typedef enum _AVRF_DEADLOCK_RESOURCE_TYPE {
  23. AVrfpDeadlockTypeUnknown = 0,
  24. AVrfpDeadlockTypeCriticalSection = 1,
  25. AVrfpDeadlockTypeMaximum = 2
  26. } AVRF_DEADLOCK_RESOURCE_TYPE, *PAVRF_DEADLOCK_RESOURCE_TYPE;
  27. #endif
  28. PUCHAR ResourceTypes[] =
  29. {
  30. "Unknown",
  31. "Critical Section",
  32. };
  33. #define RESOURCE_TYPE_MAXIMUM 5
  34. #define DEADLOCK_EXT_FLAG_DUMP_STACKS 1
  35. #define DEADLOCK_EXT_FLAG_DUMP_NODES 2
  36. #define DEADLOCK_EXT_FLAG_ANALYZE 4
  37. extern
  38. VOID
  39. DumpSymbolicAddress(
  40. ULONG64 Address,
  41. PUCHAR Buffer,
  42. BOOL AlwaysShowHex
  43. );
  44. #define MAX_DEADLOCK_PARTICIPANTS 32
  45. #define VI_MAX_STACK_DEPTH 8
  46. typedef struct _DEADLOCK_VECTOR
  47. {
  48. ULONG64 Thread;
  49. ULONG64 Node;
  50. ULONG64 ResourceAddress;
  51. ULONG64 StackAddress;
  52. ULONG64 ParentStackAddress;
  53. ULONG64 ThreadEntry;
  54. ULONG Type;
  55. BOOLEAN TryAcquire;
  56. } DEADLOCK_VECTOR, *PDEADLOCK_VECTOR;
  57. //
  58. // Functions from `verifier.c'
  59. //
  60. extern
  61. ULONG64
  62. ReadPVOID (
  63. ULONG64 Address
  64. );
  65. extern
  66. ULONG
  67. ReadULONG(
  68. ULONG64 Address
  69. );
  70. #define ReadPvoid ReadPVOID
  71. #define ReadUlong ReadULONG
  72. //
  73. // Forward declarations for local functions
  74. //
  75. VOID
  76. PrintGlobalStatistics (
  77. ULONG64 GlobalsAddress
  78. );
  79. BOOLEAN
  80. SearchForResource (
  81. ULONG64 GlobalsAddress,
  82. ULONG64 ResourceAddress
  83. );
  84. BOOLEAN
  85. SearchForThread (
  86. ULONG64 GlobalsAddress,
  87. ULONG64 ThreadAddress
  88. );
  89. BOOLEAN
  90. AnalyzeResource (
  91. ULONG64 Resource,
  92. BOOLEAN Verbose
  93. );
  94. BOOLEAN
  95. AnalyzeResources (
  96. ULONG64 GlobalsAddress
  97. );
  98. /////////////////////////////////////////////////////////////////////
  99. /////////////////////////////////////////////////////////// Deadlocks
  100. /////////////////////////////////////////////////////////////////////
  101. //
  102. // Defines copied from nt\base\ntos\verifier\vfdeadlock.c .
  103. //
  104. #define AVRF_DEADLOCK_ISSUE_SELF_DEADLOCK 0x1000
  105. #define AVRF_DEADLOCK_ISSUE_DEADLOCK_DETECTED 0x1001
  106. #define AVRF_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE 0x1002
  107. #define AVRF_DEADLOCK_ISSUE_UNEXPECTED_RELEASE 0x1003
  108. #define AVRF_DEADLOCK_ISSUE_UNEXPECTED_THREAD 0x1004
  109. #define AVRF_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION 0x1005
  110. #define AVRF_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES 0x1006
  111. #define AVRF_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE 0x1007
  112. #define DUMP_FIELD(Name) dprintf ("%-20s %I64u \n", #Name, ReadField (Name))
  113. DECLARE_API( udeadlock )
  114. /*++
  115. Routine Description:
  116. Verifier deadlock detection module extension.
  117. Arguments:
  118. arg - not used for now.
  119. Return Value:
  120. None.
  121. --*/
  122. {
  123. ULONG64 GlobalsPointer;
  124. ULONG64 GlobalsAddress;
  125. ULONG64 InitializedAddress;
  126. ULONG64 EnabledAddress;
  127. ULONG64 InstigatorAddress;
  128. ULONG64 ParticipantAddress;
  129. ULONG64 LastResourceAddress;
  130. ULONG64 RootAddress;
  131. ULONG64 CurrentResourceAddress;
  132. ULONG64 CurrentThread;
  133. ULONG64 ThreadForChain;
  134. ULONG64 CurrentStack;
  135. ULONG64 NextStack;
  136. ULONG64 SymbolOffset;
  137. ULONG StackTraceSize;
  138. ULONG Processor=0;
  139. ULONG ParticipantOffset;
  140. ULONG StackOffset;
  141. ULONG ParentStackOffset;
  142. ULONG InitializedValue;
  143. ULONG EnabledValue;
  144. ULONG NumberOfParticipants;
  145. ULONG NumberOfResources;
  146. ULONG NumberOfThreads;
  147. ULONG ThreadNumber;
  148. ULONG ResourceNumber;
  149. ULONG ResourceType;
  150. ULONG TryAcquireUsed;
  151. ULONG PtrSize;
  152. ULONG J, I;
  153. BOOLEAN DumpStacks = FALSE;
  154. BOOLEAN DumpNodes = FALSE;
  155. BOOLEAN Analyze = FALSE;
  156. ULONG64 Flags;
  157. UCHAR SymbolName[512];
  158. HANDLE CurrentThreadHandle = NULL;
  159. DEADLOCK_VECTOR Participants[MAX_DEADLOCK_PARTICIPANTS+1];
  160. ULONG64 Issue[4];
  161. ULONG64 SearchAddress = 0;
  162. INIT_API();
  163. //
  164. // Check if help requested
  165. //
  166. if (strstr (args, "?")) {
  167. dprintf ("\n");
  168. dprintf ("!deadlock Statistics and deadlock layout \n");
  169. dprintf ("!deadlock 3 Detailed deadlock layout \n");
  170. dprintf ("!deadlock ADDRESS Search for ADDRESS among deadlock verifier data \n");
  171. dprintf ("\n");
  172. Status = S_OK;
  173. goto Exit;
  174. }
  175. Flags = GetExpression(args);
  176. if (Flags > 0x10000000) {
  177. SearchAddress = Flags;
  178. }
  179. else {
  180. if (Flags & DEADLOCK_EXT_FLAG_DUMP_STACKS) {
  181. DumpStacks = TRUE;
  182. }
  183. if (Flags & DEADLOCK_EXT_FLAG_DUMP_NODES) {
  184. DumpNodes = TRUE;
  185. }
  186. if (Flags & DEADLOCK_EXT_FLAG_ANALYZE) {
  187. Analyze = TRUE;
  188. }
  189. }
  190. GlobalsPointer = (ULONG64) GetExpression ("verifier!AVrfpDeadlockGlobals");
  191. EnabledAddress = (ULONG64) GetExpression ("verifier!AVrfpDeadlockDetectionEnabled");
  192. if (GlobalsPointer == 0 || EnabledAddress == 0) {
  193. dprintf ("Error: incorrect symbols for kernel \n");
  194. Status = E_INVALIDARG;
  195. goto Exit;
  196. }
  197. GlobalsAddress = 0;
  198. ReadPointer (GlobalsPointer, &GlobalsAddress);
  199. EnabledValue = ReadUlong (EnabledAddress);
  200. if (GlobalsAddress == 0) {
  201. dprintf ("Deadlock detection not initialized \n");
  202. Status = E_INVALIDARG;
  203. goto Exit;
  204. }
  205. InitializedValue = 1;
  206. if (EnabledValue == 0) {
  207. dprintf ("Deadlock detection not enabled \n");
  208. Status = E_INVALIDARG;
  209. goto Exit;
  210. }
  211. //
  212. // Do a search if this is requested.
  213. //
  214. if (SearchAddress) {
  215. BOOLEAN FoundSomething = FALSE;
  216. dprintf ("Searching for %p ... \n", SearchAddress);
  217. if (FoundSomething == FALSE) {
  218. FoundSomething = SearchForResource (GlobalsAddress, SearchAddress);
  219. }
  220. if (FoundSomething == FALSE) {
  221. FoundSomething = SearchForThread (GlobalsAddress, SearchAddress);
  222. }
  223. Status = S_OK;
  224. goto Exit;
  225. }
  226. //
  227. // Analyze if this is needed.
  228. //
  229. if (Analyze) {
  230. AnalyzeResources (GlobalsAddress);
  231. Status = S_OK;
  232. goto Exit;
  233. }
  234. //
  235. // Get the AVrfpDeadlockIssue[0..3] vector.
  236. //
  237. {
  238. ULONG ValueSize;
  239. ULONG64 IssueAddress;
  240. ValueSize = IsPtr64()? 8: 4;
  241. IssueAddress = GetExpression ("verifier!AVrfpDeadlockIssue");
  242. for (I = 0; I < 4; I += 1) {
  243. ReadPointer (IssueAddress + I * ValueSize, &(Issue[I]));
  244. }
  245. if (Issue[0] == 0) {
  246. dprintf ("\n");
  247. PrintGlobalStatistics (GlobalsAddress);
  248. dprintf ("\nNo deadlock verifier issues. \n");
  249. Status = S_OK;
  250. goto Exit;
  251. }
  252. else {
  253. if (ValueSize == 4) {
  254. dprintf ("issue: %08X %08X %08X %08X \n",
  255. Issue[0], Issue[1], Issue[2], Issue[3]);
  256. }
  257. else {
  258. dprintf ("issue: %I64X %I64X %I64X %I64X \n",
  259. Issue[0], Issue[1], Issue[2], Issue[3]);
  260. }
  261. }
  262. switch (Issue[0]) {
  263. case AVRF_DEADLOCK_ISSUE_SELF_DEADLOCK:
  264. dprintf ("Resource %I64X is acquired recursively. \n", Issue[1]);
  265. Status = S_OK;
  266. goto Exit;
  267. case AVRF_DEADLOCK_ISSUE_DEADLOCK_DETECTED:
  268. break;
  269. case AVRF_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE:
  270. dprintf ("Resource %I64X is used before being initialized. \n", Issue[1]);
  271. Status = S_OK;
  272. goto Exit;
  273. case AVRF_DEADLOCK_ISSUE_UNEXPECTED_RELEASE:
  274. dprintf ("Resource %I64X is released out of order. \n", Issue[2]);
  275. Status = S_OK;
  276. goto Exit;
  277. case AVRF_DEADLOCK_ISSUE_UNEXPECTED_THREAD:
  278. dprintf ("Current thread is releasing resource %I64X which was acquired in thread %I64X. \n",
  279. Issue[1], Issue[2]);
  280. Status = S_OK;
  281. goto Exit;
  282. case AVRF_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION:
  283. dprintf ("Resource %I64X has already been initialized. \n", Issue[1]);
  284. Status = S_OK;
  285. goto Exit;
  286. case AVRF_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES:
  287. if (Issue[3] == 0) {
  288. dprintf ("Deleting thread %I64X (descriptor %I64X) "
  289. "which still holds resources. \n",
  290. Issue[1], Issue[2]);
  291. } else {
  292. dprintf ("Deleting thread %I64X which still holds resource %I64X "
  293. "(descriptor %I64X). \n",
  294. Issue[2], Issue[1], Issue[3]);
  295. }
  296. Status = S_OK;
  297. goto Exit;
  298. case AVRF_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE:
  299. dprintf ("Releasing resource %I64X that was never acquired. \n", Issue[1]);
  300. Status = S_OK;
  301. goto Exit;
  302. default:
  303. dprintf ("Unrecognized issue code %I64X ! \n", Issue[0]);
  304. Status = S_OK;
  305. goto Exit;
  306. }
  307. }
  308. //
  309. // Figure out how big a pointer is
  310. //
  311. PtrSize = IsPtr64()? 8: 4;
  312. if (PtrSize == 0) {
  313. dprintf ("Cannot get size of PVOID \n");
  314. Status = E_INVALIDARG;
  315. goto Exit;
  316. }
  317. //
  318. // Dump the globals structure
  319. //
  320. InitTypeRead (GlobalsAddress, verifier!_AVRF_DEADLOCK_GLOBALS);
  321. //
  322. // Find out the address of the resource that causes the deadlock
  323. //
  324. InstigatorAddress = ReadField(Instigator);
  325. NumberOfParticipants = (ULONG) ReadField(NumberOfParticipants);
  326. if (NumberOfParticipants > MAX_DEADLOCK_PARTICIPANTS) {
  327. dprintf("\nCannot have %x participants in a deadlock!\n",NumberOfParticipants);
  328. Status = E_INVALIDARG;
  329. goto Exit;
  330. }
  331. if (0 == NumberOfParticipants) {
  332. dprintf("\nNo deadlock detected\n");
  333. Status = S_OK;
  334. goto Exit;
  335. }
  336. GetFieldOffset("verifier!_AVRF_DEADLOCK_GLOBALS",
  337. "Participant",
  338. &ParticipantOffset
  339. );
  340. ParticipantAddress = GlobalsAddress + ParticipantOffset;
  341. //
  342. // Read the vector of AVRF_DEADLOCK_NODEs that
  343. // participate in the deadlock.
  344. //
  345. //
  346. for (J = 0; J < NumberOfParticipants; J++) {
  347. Participants[J].Node = ReadPvoid(ParticipantAddress + J * PtrSize);
  348. // dprintf("Participant %c: %08x\n", 'A' + J, Participants[J].Node);
  349. }
  350. //
  351. // Gather the information we'll need to print out exact
  352. // context for the deadlock.
  353. //
  354. GetFieldOffset("verifier!_AVRF_DEADLOCK_NODE",
  355. "StackTrace",
  356. &StackOffset
  357. );
  358. GetFieldOffset("verifier!_AVRF_DEADLOCK_NODE",
  359. "ParentStackTrace",
  360. &ParentStackOffset
  361. );
  362. //
  363. // The stack trace size is 1 on free builds and 6 (or bigger) on
  364. // checked builds. We assume that the ParentStackTrace field comes
  365. // immediately after StackTrace field in the NODE structure.
  366. //
  367. StackTraceSize = (ParentStackOffset - StackOffset) / PtrSize;
  368. for (J = 0; J < NumberOfParticipants; J++) {
  369. InitTypeRead (Participants[J].Node, verifier!_AVRF_DEADLOCK_NODE);
  370. RootAddress = ReadField(Root);
  371. GetFieldValue(RootAddress,
  372. "verifier!_AVRF_DEADLOCK_RESOURCE",
  373. "ResourceAddress" ,
  374. Participants[J].ResourceAddress
  375. );
  376. GetFieldValue(RootAddress,
  377. "verifier!_AVRF_DEADLOCK_RESOURCE",
  378. "Type",
  379. Participants[J].Type
  380. );
  381. if (Participants[J].Type > RESOURCE_TYPE_MAXIMUM) {
  382. Participants[J].Type = 0;
  383. }
  384. Participants[J].ThreadEntry = ReadField(ThreadEntry);
  385. Participants[J].StackAddress = Participants[J].Node + StackOffset;
  386. Participants[J].ParentStackAddress = Participants[J].Node +
  387. ParentStackOffset;
  388. Participants[J].TryAcquire = (BOOLEAN) ReadField(OnlyTryAcquireUsed);
  389. GetFieldValue(Participants[J].ThreadEntry,
  390. "verifier!_AVRF_DEADLOCK_THREAD",
  391. "Thread",
  392. Participants[J].Thread
  393. );
  394. }
  395. if (Participants[0].ResourceAddress != InstigatorAddress) {
  396. dprintf("\nDeadlock Improperly formed participant list\n");
  397. Status = E_INVALIDARG;
  398. goto Exit;
  399. }
  400. //
  401. // The last participant is the Instigator of the deadlock
  402. //
  403. Participants[NumberOfParticipants].Thread = 0;
  404. Participants[NumberOfParticipants].Node = 0;
  405. Participants[NumberOfParticipants].ResourceAddress = InstigatorAddress;
  406. Participants[NumberOfParticipants].StackAddress = 0;
  407. Participants[NumberOfParticipants].ParentStackAddress =
  408. Participants[NumberOfParticipants-1].StackAddress;
  409. Participants[NumberOfParticipants].Type =
  410. Participants[0].Type;
  411. Participants[NumberOfParticipants].TryAcquire = FALSE; // can't cause a deadlock with try
  412. Participants[NumberOfParticipants].ThreadEntry = 0;
  413. //
  414. // At this point we have all of the raw data we need.
  415. // We have to munge it up a bit so that we have the most
  416. // recent data. For instance, take the simple deadlock AB-BA.
  417. // The stack for A in the AB context may be wrong because
  418. // another thread may have come and taken A at a different point.
  419. // This is why we have the parent stack address.
  420. //
  421. // So the rules we have to adhere to are as follows:
  422. // Where we have a chain, (eg ABC meaning A taken then B then C),
  423. // the thread used will always be the thread for the last resource taken,
  424. // and the stacks used will be the the childs parent stack where
  425. // applicable.
  426. //
  427. // For example, if C was taken by thread 1, A & B would be munged
  428. // to use thread 1. Since in order to get to C, A and B must have
  429. // been taken by thread 1 at some point, even if the thread they
  430. // have saved now is a different one. C would use its own stack,
  431. // B would use C's parent stack, since that was the stack that
  432. // B had been acquired with when C was taken, and A will use
  433. // B's parent stack.
  434. //
  435. // We can identify the start of a chain when the same resource
  436. // is on the participant list twice in a row.
  437. //
  438. LastResourceAddress = InstigatorAddress;
  439. NumberOfResources = 0;
  440. NumberOfThreads = 0;
  441. for (J = 0; J <= NumberOfParticipants; J++) {
  442. I = NumberOfParticipants - J;
  443. CurrentResourceAddress = Participants[I].ResourceAddress;
  444. if (CurrentResourceAddress == LastResourceAddress) {
  445. //
  446. // This is the beginning of a chain. Use the current
  447. // stack and the current thread, and set the chain
  448. // thread to ours
  449. //
  450. ThreadForChain = Participants[I].Thread;
  451. CurrentStack = Participants[I].StackAddress;
  452. NumberOfThreads++;
  453. } else {
  454. //
  455. // This is a resource we haven't seen before
  456. //
  457. NumberOfResources++;
  458. }
  459. NextStack = Participants[I].ParentStackAddress;
  460. Participants[I].StackAddress = CurrentStack;
  461. Participants[I].Thread = ThreadForChain;
  462. //
  463. // Parent stack isn't used any more -- nullify it.
  464. //
  465. Participants[I].ParentStackAddress = 0;
  466. CurrentStack = NextStack;
  467. LastResourceAddress = CurrentResourceAddress;
  468. }
  469. //
  470. // Now that we've munged the vectors, we can go ahead and print out the
  471. // deadlock information.
  472. //
  473. dprintf("\nDeadlock detected (%d resources in %d threads):\n\n",NumberOfResources, NumberOfThreads);
  474. if (! DumpStacks )
  475. {
  476. //
  477. // Print out the 'short' form
  478. // Example:
  479. //
  480. // !dealock detected:
  481. // Thread 1: A B
  482. // Thread 2: B C
  483. // Thread 3: C A
  484. //
  485. // Thread 1 = <address>
  486. // Thread 2 = <address>
  487. // Thread 3 = <address>
  488. //
  489. // Lock A = <address> (spinlock)
  490. // Lock B = <address> (mutex)
  491. // Lock C = <address> (spinlock)
  492. //
  493. ThreadNumber = 0;
  494. ResourceNumber = 0;
  495. J=0;
  496. //
  497. // Dump out the deadlock topology
  498. //
  499. while (J <= NumberOfParticipants)
  500. {
  501. ThreadForChain = Participants[J].Thread;
  502. dprintf("Thread %d: ",ThreadNumber);
  503. do {
  504. if (J == NumberOfParticipants) {
  505. ResourceNumber = 0;
  506. }
  507. dprintf("%c ",
  508. 'A' + ResourceNumber
  509. );
  510. J++;
  511. ResourceNumber++;
  512. } while( J <= NumberOfParticipants && Participants[J].ResourceAddress != Participants[J-1].ResourceAddress);
  513. dprintf("\n");
  514. ThreadNumber++;
  515. ResourceNumber--;
  516. }
  517. dprintf("\nWhere:\n");
  518. //
  519. // Dump out the thread addresses
  520. //
  521. ThreadNumber = 0;
  522. ResourceNumber = 0;
  523. J=0;
  524. while (J <= NumberOfParticipants) {
  525. ThreadForChain = Participants[J].Thread;
  526. dprintf("Thread %d = %08x\n",ThreadNumber, ThreadForChain);
  527. do {
  528. if (J == NumberOfParticipants) {
  529. ResourceNumber = 0;
  530. }
  531. J++;
  532. ResourceNumber++;
  533. } while( J <= NumberOfParticipants && Participants[J].ResourceAddress != Participants[J-1].ResourceAddress);
  534. ThreadNumber++;
  535. ResourceNumber--;
  536. }
  537. //
  538. // Dump out the resource addresses
  539. //
  540. ThreadNumber = 0;
  541. ResourceNumber = 0;
  542. J=0;
  543. #if 1
  544. while (J < NumberOfParticipants)
  545. {
  546. while(J < NumberOfParticipants && Participants[J].ResourceAddress != Participants[J+1].ResourceAddress) {
  547. if (Participants[J].ResourceAddress != Participants[J+1].ResourceAddress) {
  548. CHAR Buffer[0xFF];
  549. ULONG64 Displacement = 0;
  550. GetSymbol(Participants[J].ResourceAddress, Buffer, &Displacement);
  551. dprintf("Lock %c = %s", 'A' + ResourceNumber, Buffer );
  552. if (Displacement != 0) {
  553. dprintf("%s%x", (Displacement < 0xFFF)?"+0x":"",Displacement);
  554. }
  555. dprintf(" Type '%s' ",ResourceTypes[Participants[J].Type]);
  556. dprintf("\n");
  557. ResourceNumber++;
  558. }
  559. J++;
  560. }
  561. J++;
  562. }
  563. #endif
  564. } else {
  565. //
  566. // Dump out verbose deadlock information -- with stacks
  567. // Here is an exapmle:
  568. //
  569. // Deadlock detected (3 resources in 3 threads):
  570. //
  571. //Thread 0 (829785B0) took locks in the following order:
  572. //
  573. // Lock A (Spinlock) @ bfc7c254
  574. // Node: 82887F88
  575. // Stack: NDIS!ndisNotifyMiniports+0xC1
  576. // NDIS!ndisPowerStateCallback+0x6E
  577. // ntkrnlmp!ExNotifyCallback+0x72
  578. // ntkrnlmp!PopDispatchCallback+0x13
  579. // ntkrnlmp!PopPolicyWorkerNotify+0x8F
  580. // ntkrnlmp!PopPolicyWorkerThread+0x10F
  581. // ntkrnlmp!ExpWorkerThread+0x294
  582. // ntkrnlmp!PspSystemThreadStartup+0x4B
  583. //
  584. // Lock B (Spinlock) @ 8283b87c
  585. // Node: 82879148
  586. // Stack: NDIS!ndisDereferenceRef+0x10F
  587. // NDIS!ndisDereferenceDriver+0x3A
  588. // NDIS!ndisNotifyMiniports+0xD1
  589. // NDIS!ndisPowerStateCallback+0x6E
  590. // ntkrnlmp!ExNotifyCallback+0x72
  591. // ntkrnlmp!PopDispatchCallback+0x13
  592. // ntkrnlmp!PopPolicyWorkerNotify+0x8F
  593. // ntkrnlmp!PopPolicyWorkerThread+0x10F
  594. //
  595. //Thread 1 (829785B0) took locks in the following order:
  596. //
  597. // Lock B (Spinlock) @ 8283b87c
  598. // Node: 82879008
  599. // Stack: NDIS!ndisReferenceNextUnprocessedMiniport+0x3E
  600. // NDIS!ndisNotifyMiniports+0xB3
  601. // NDIS!ndisPowerStateCallback+0x6E
  602. // ntkrnlmp!ExNotifyCallback+0x72
  603. // ntkrnlmp!PopDispatchCallback+0x13
  604. // ntkrnlmp!PopPolicyWorkerNotify+0x8F
  605. // ntkrnlmp!PopPolicyWorkerThread+0x10F
  606. // ntkrnlmp!ExpWorkerThread+0x294
  607. //
  608. // Lock C (Spinlock) @ 82862b48
  609. // Node: 8288D008
  610. // Stack: NDIS!ndisReferenceRef+0x10F
  611. // NDIS!ndisReferenceMiniport+0x4A
  612. // NDIS!ndisReferenceNextUnprocessedMiniport+0x70
  613. // NDIS!ndisNotifyMiniports+0xB3
  614. // NDIS!ndisPowerStateCallback+0x6E
  615. // ntkrnlmp!ExNotifyCallback+0x72
  616. // ntkrnlmp!PopDispatchCallback+0x13
  617. // ntkrnlmp!PopPolicyWorkerNotify+0x8F
  618. //
  619. //Thread 2 (82978310) took locks in the following order:
  620. //
  621. // Lock C (Spinlock) @ 82862b48
  622. // Node: 82904708
  623. // Stack: NDIS!ndisPnPRemoveDevice+0x20B
  624. // NDIS!ndisPnPDispatch+0x319
  625. // ntkrnlmp!IopfCallDriver+0x62
  626. // ntkrnlmp!IovCallDriver+0x9D
  627. // ntkrnlmp!IopSynchronousCall+0xFA
  628. // ntkrnlmp!IopRemoveDevice+0x11E
  629. // ntkrnlmp!IopDeleteLockedDeviceNode+0x3AF
  630. // ntkrnlmp!IopDeleteLockedDeviceNodes+0xF5
  631. //
  632. // Lock A (Spinlock) @ bfc7c254
  633. // Stack: << Current stack >>
  634. //
  635. ThreadNumber = 0;
  636. ResourceNumber = 0;
  637. J=0;
  638. while (J <= NumberOfParticipants) {
  639. ThreadForChain = Participants[J].Thread;
  640. dprintf("Thread %d: %08X",ThreadNumber, ThreadForChain);
  641. if (DumpNodes && Participants[J].ThreadEntry) {
  642. dprintf(" (ThreadEntry = %X)\n ", (ULONG) Participants[J].ThreadEntry);
  643. }
  644. dprintf(" took locks in the following order:\n\n");
  645. //
  646. // This is a do .. while so that we can never get an infinite loop.
  647. //
  648. do {
  649. UINT64 CurrentStackAddress;
  650. UINT64 StackFrame;
  651. CHAR Buffer[0xFF];
  652. ULONG64 Displacement = 0;
  653. if (J == NumberOfParticipants) {
  654. ResourceNumber = 0;
  655. }
  656. GetSymbol(Participants[J].ResourceAddress, Buffer, &Displacement);
  657. dprintf(" Lock %c -- %s", 'A' + ResourceNumber, Buffer );
  658. if (Displacement != 0) {
  659. dprintf("%s%x", (Displacement < 0xFFF)?"+0x":"",Displacement);
  660. }
  661. dprintf(" (%s)\n",ResourceTypes[Participants[J].Type]);
  662. if (DumpNodes && Participants[J].Node)
  663. dprintf(" Node: %X\n", (ULONG) Participants[J].Node);
  664. dprintf(" Stack: ");
  665. CurrentStackAddress = Participants[J].StackAddress;
  666. if (CurrentStackAddress == 0) {
  667. dprintf ("<< Current stack >>\n");
  668. } else {
  669. for (I = 0; I < StackTraceSize; I++) {
  670. ULONG SourceLine;
  671. SymbolName[0] = '\0';
  672. StackFrame = ReadPvoid(CurrentStackAddress);
  673. if (0 == StackFrame)
  674. break;
  675. GetSymbol(StackFrame, SymbolName, &SymbolOffset);
  676. if (I) {
  677. dprintf(" ");
  678. }
  679. if ((LONG64) SymbolOffset > 0 ) {
  680. dprintf ("%s+0x%X",
  681. SymbolName, (ULONG) SymbolOffset);
  682. } else {
  683. dprintf ("%X", (ULONG) StackFrame);
  684. }
  685. if (SUCCEEDED(g_ExtSymbols->lpVtbl->GetLineByOffset
  686. (g_ExtSymbols, StackFrame,
  687. &SourceLine, SymbolName,
  688. sizeof(SymbolName), NULL,
  689. &Displacement))) {
  690. dprintf (" [%s @ %d]", SymbolName, SourceLine);
  691. }
  692. dprintf ("\n");
  693. CurrentStackAddress += PtrSize;
  694. }
  695. }
  696. dprintf("\n");
  697. J++;
  698. ResourceNumber++;
  699. } while( J <= NumberOfParticipants && Participants[J].ResourceAddress != Participants[J-1].ResourceAddress);
  700. ThreadNumber++;
  701. ResourceNumber--;
  702. }
  703. }
  704. Status = S_OK;
  705. Exit:
  706. EXIT_API();
  707. return Status;
  708. }
  709. VOID
  710. PrintGlobalStatistics (
  711. ULONG64 GlobalsAddress
  712. )
  713. {
  714. ULONG AllocationFailures;
  715. ULONG64 MemoryUsed;
  716. ULONG NodesTrimmed;
  717. ULONG MaxNodesSearched;
  718. ULONG SequenceNumber;
  719. //
  720. // Dump the globals structure
  721. //
  722. InitTypeRead (GlobalsAddress, verifier!_AVRF_DEADLOCK_GLOBALS);
  723. //
  724. // Print some simple statistics
  725. //
  726. dprintf ("Resources: %u\n", (ULONG) ReadField (Resources[0]));
  727. dprintf ("Nodes: %u\n", (ULONG) ReadField (Nodes[0]));
  728. dprintf ("Threads: %u\n", (ULONG) ReadField (Threads[0]));
  729. dprintf ("\n");
  730. MemoryUsed = ReadField (BytesAllocated);
  731. if (MemoryUsed > 1024 * 1024) {
  732. dprintf ("%I64u bytes of kernel pool used.\n", MemoryUsed);
  733. }
  734. AllocationFailures = (ULONG) ReadField (AllocationFailures);
  735. if (AllocationFailures > 0) {
  736. dprintf ("Allocation failures encountered (%u).\n", AllocationFailures);
  737. }
  738. NodesTrimmed = (ULONG) ReadField (NodesTrimmedBasedOnAge);
  739. dprintf ("Nodes trimmed based on age %u.\n", NodesTrimmed);
  740. NodesTrimmed = (ULONG) ReadField (NodesTrimmedBasedOnCount);
  741. dprintf ("Nodes trimmed based on count %u.\n", NodesTrimmed);
  742. dprintf ("Analyze calls %u.\n", (ULONG) ReadField (SequenceNumber));
  743. dprintf ("Maximum nodes searched %u.\n", (ULONG) ReadField (MaxNodesSearched));
  744. }
  745. BOOLEAN
  746. SearchForResource (
  747. ULONG64 GlobalsAddress,
  748. ULONG64 ResourceAddress
  749. )
  750. {
  751. ULONG I;
  752. ULONG64 Bucket;
  753. ULONG64 SizeOfBucket;
  754. BOOLEAN ResourceFound = FALSE;
  755. ULONG64 SizeOfResource;
  756. ULONG FlinkOffset = 0;
  757. ULONG64 Current;
  758. ULONG64 CurrentResource;
  759. ULONG Magic;
  760. SizeOfBucket = GetTypeSize("LIST_ENTRY");
  761. SizeOfResource = GetTypeSize("verifier!_AVRF_DEADLOCK_RESOURCE");
  762. GetFieldOffset("verifier!_AVRF_DEADLOCK_RESOURCE",
  763. "HashChainList",
  764. &FlinkOffset);
  765. if (SizeOfBucket == 0 || SizeOfResource == 0 || FlinkOffset == 0) {
  766. dprintf ("Error: cannot get size for verifier types. \n");
  767. return FALSE;
  768. }
  769. InitTypeRead (GlobalsAddress, verifier!_AVRF_DEADLOCK_GLOBALS);
  770. Bucket = ReadField (ResourceDatabase);
  771. if (Bucket == 0) {
  772. dprintf ("Error: cannot get resource database address. \n");
  773. return FALSE;
  774. }
  775. for (I = 0; I < AVRF_DEADLOCK_HASH_BINS; I += 1) {
  776. // traverse it ...
  777. Current = ReadPvoid(Bucket);
  778. while (Current != Bucket) {
  779. InitTypeRead (Current - FlinkOffset, verifier!_AVRF_DEADLOCK_RESOURCE);
  780. CurrentResource = ReadField (ResourceAddress);
  781. if (CurrentResource == ResourceAddress ||
  782. ResourceAddress == Current - FlinkOffset) {
  783. CurrentResource = Current - FlinkOffset;
  784. ResourceFound = TRUE;
  785. break;
  786. }
  787. Current = ReadPvoid(Current);
  788. if (CheckControlC()) {
  789. dprintf ("\nSearch interrupted ... \n");
  790. return TRUE;
  791. }
  792. }
  793. if (ResourceFound) {
  794. break;
  795. }
  796. dprintf (".");
  797. Bucket += SizeOfBucket;
  798. }
  799. dprintf ("\n");
  800. if (ResourceFound == FALSE) {
  801. dprintf ("No resource correspoding to %p has been found. \n",
  802. ResourceAddress);
  803. }
  804. else {
  805. dprintf ("Found a deadlock verifier resource descriptor @ %p \n",
  806. CurrentResource);
  807. }
  808. return ResourceFound;
  809. }
  810. BOOLEAN
  811. SearchForThread (
  812. ULONG64 GlobalsAddress,
  813. ULONG64 ThreadAddress
  814. )
  815. {
  816. ULONG I;
  817. ULONG64 Bucket;
  818. ULONG64 SizeOfBucket;
  819. BOOLEAN ThreadFound = FALSE;
  820. ULONG64 SizeOfThread;
  821. ULONG FlinkOffset = 0;
  822. ULONG64 Current;
  823. ULONG64 CurrentThread;
  824. SizeOfBucket = GetTypeSize("LIST_ENTRY");
  825. SizeOfThread = GetTypeSize("verifier!_AVRF_DEADLOCK_THREAD");
  826. GetFieldOffset("verifier!_AVRF_DEADLOCK_THREAD",
  827. "ListEntry",
  828. &FlinkOffset);
  829. if (SizeOfBucket == 0 || SizeOfThread == 0 || FlinkOffset == 0) {
  830. dprintf ("Error: cannot get size for verifier types. \n");
  831. return FALSE;
  832. }
  833. InitTypeRead (GlobalsAddress, verifier!_AVRF_DEADLOCK_GLOBALS);
  834. Bucket = ReadField (ThreadDatabase);
  835. if (Bucket == 0) {
  836. dprintf ("Error: cannot get thread database address. \n");
  837. return FALSE;
  838. }
  839. for (I = 0; I < AVRF_DEADLOCK_HASH_BINS; I += 1) {
  840. // traverse it ...
  841. Current = ReadPvoid(Bucket);
  842. while (Current != Bucket) {
  843. InitTypeRead (Current - FlinkOffset, verifier!_AVRF_DEADLOCK_THREAD);
  844. CurrentThread = ReadField (ThreadAddress);
  845. if (CurrentThread == ThreadAddress ||
  846. ThreadAddress == Current - FlinkOffset) {
  847. CurrentThread = Current - FlinkOffset;
  848. ThreadFound = TRUE;
  849. break;
  850. }
  851. Current = ReadPvoid(Current);
  852. if (CheckControlC()) {
  853. dprintf ("\nSearch interrupted ... \n");
  854. return TRUE;
  855. }
  856. }
  857. if (ThreadFound) {
  858. break;
  859. }
  860. dprintf (".");
  861. Bucket += SizeOfBucket;
  862. }
  863. dprintf ("\n");
  864. if (ThreadFound == FALSE) {
  865. dprintf ("No thread correspoding to %p has been found. \n",
  866. ThreadAddress);
  867. }
  868. else {
  869. dprintf ("Found a deadlock verifier thread descriptor @ %p \n",
  870. CurrentThread);
  871. }
  872. return ThreadFound;
  873. }
  874. VOID
  875. DumpResourceStructure (
  876. )
  877. {
  878. }
  879. ULONG
  880. GetNodeLevel (
  881. ULONG64 Node
  882. )
  883. {
  884. ULONG Level = 0;
  885. while (Node != 0) {
  886. Level += 1;
  887. if (Level > 12) {
  888. dprintf ("Level > 12 !!! \n");
  889. break;
  890. }
  891. InitTypeRead (Node, verifier!_AVRF_DEADLOCK_NODE);
  892. Node = ReadField (Parent);
  893. }
  894. return Level;
  895. }
  896. BOOLEAN
  897. AnalyzeResource (
  898. ULONG64 Resource,
  899. BOOLEAN Verbose
  900. )
  901. {
  902. ULONG64 Start;
  903. ULONG64 Current;
  904. ULONG64 Node;
  905. ULONG64 Parent;
  906. ULONG FlinkOffset;
  907. ULONG RootsCount = 0;
  908. ULONG NodesCount = 0;
  909. ULONG Levels[8];
  910. ULONG ResourceFlinkOffset;
  911. ULONG I;
  912. ULONG Level;
  913. ULONG NodeCounter = 0;
  914. ZeroMemory (Levels, sizeof Levels);
  915. GetFieldOffset("verifier!_AVRF_DEADLOCK_NODE",
  916. "ResourceList",
  917. &FlinkOffset);
  918. GetFieldOffset("verifier!_AVRF_DEADLOCK_RESOURCE",
  919. "ResourceList",
  920. &ResourceFlinkOffset);
  921. InitTypeRead (Resource, verifier!_AVRF_DEADLOCK_RESOURCE);
  922. if (! Verbose) {
  923. if (ReadField(NodeCount) < 4) {
  924. return TRUE;
  925. }
  926. dprintf ("Resource (%p) : %I64u %I64u %I64u ",
  927. Resource,
  928. ReadField(Type),
  929. ReadField(NodeCount),
  930. ReadField(RecursionCount));
  931. }
  932. Start = Resource + ResourceFlinkOffset;
  933. Current = ReadPvoid (Start);
  934. while (Start != Current) {
  935. Node = Current - FlinkOffset;
  936. Level = (GetNodeLevel(Node) - 1) % 8;
  937. Levels[Level] += 1;
  938. NodesCount += 1;
  939. if (NodesCount && NodesCount % 1000 == 0) {
  940. dprintf (".");
  941. }
  942. Current = ReadPvoid (Current);
  943. if (CheckControlC()) {
  944. return FALSE;
  945. }
  946. }
  947. dprintf ("[");
  948. for (I = 0; I < 8; I += 1) {
  949. dprintf ("%u ", Levels[I]);
  950. }
  951. dprintf ("]\n");
  952. return TRUE;
  953. }
  954. BOOLEAN
  955. AnalyzeResources (
  956. ULONG64 GlobalsAddress
  957. )
  958. /*++
  959. This routine analyzes all resource to make sure we do not have
  960. zombie nodes laying around.
  961. --*/
  962. {
  963. ULONG I;
  964. ULONG64 Bucket;
  965. ULONG64 SizeOfBucket;
  966. ULONG64 SizeOfResource;
  967. ULONG FlinkOffset = 0;
  968. ULONG64 Current;
  969. ULONG64 CurrentResource;
  970. ULONG Magic;
  971. BOOLEAN Finished;
  972. ULONG ResourceCount = 0;
  973. dprintf ("Analyzing resources (%p) ... \n", GlobalsAddress);
  974. SizeOfBucket = GetTypeSize("LIST_ENTRY");
  975. SizeOfResource = GetTypeSize("verifier!_AVRF_DEADLOCK_RESOURCE");
  976. GetFieldOffset("verifier!_AVRF_DEADLOCK_RESOURCE",
  977. "HashChainList",
  978. &FlinkOffset);
  979. if (SizeOfBucket == 0 || SizeOfResource == 0 || FlinkOffset == 0) {
  980. dprintf ("Error: cannot get size for verifier types. \n");
  981. return FALSE;
  982. }
  983. InitTypeRead (GlobalsAddress, verifier!_AVRF_DEADLOCK_GLOBALS);
  984. Bucket = ReadField (ResourceDatabase);
  985. if (Bucket == 0) {
  986. dprintf ("Error: cannot get resource database address. \n");
  987. return FALSE;
  988. }
  989. for (I = 0; I < AVRF_DEADLOCK_HASH_BINS; I += 1) {
  990. // traverse it ...
  991. Current = ReadPvoid(Bucket);
  992. while (Current != Bucket) {
  993. Finished = AnalyzeResource (Current - FlinkOffset, FALSE);
  994. ResourceCount += 1;
  995. if (ResourceCount % 256 == 0) {
  996. dprintf (".\n");
  997. }
  998. Current = ReadPvoid(Current);
  999. if (CheckControlC() || !Finished) {
  1000. dprintf ("\nSearch interrupted ... \n");
  1001. return TRUE;
  1002. }
  1003. }
  1004. Bucket += SizeOfBucket;
  1005. }
  1006. return TRUE;
  1007. }