Windows NT 4.0 source code leak
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.

609 lines
18 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. locks.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Ramon J San Andres (ramonsa) 5-Nov-1993
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. DECLARE_API( locks )
  16. /*++
  17. Routine Description:
  18. Dump kernel mode resource locks
  19. Arguments:
  20. arg - [-V] [-P] [Address]
  21. Return Value:
  22. None
  23. --*/
  24. {
  25. UCHAR Buffer[80];
  26. LONG ActiveCount;
  27. ULONG ContentionCount;
  28. ULONG Displacement;
  29. BOOLEAN DisplayZero;
  30. ULONG End;
  31. USHORT Flag;
  32. RESOURCE_HASH_ENTRY HashEntry;
  33. ULONG Index;
  34. USHORT NumberOfExclusiveWaiters;
  35. USHORT NumberOfSharedWaiters;
  36. OWNER_ENTRY OwnerEntry;
  37. BOOLEAN Performance;
  38. ULONG PerformanceData;
  39. USHORT TableSize;
  40. RESOURCE_PERFORMANCE_DATA ResourcePerformanceData;
  41. ULONG ResourceHead;
  42. LIST_ENTRY List;
  43. PLIST_ENTRY Next;
  44. ULONG Result;
  45. ULONG ResourceToDump;
  46. PERESOURCE Resource;
  47. ERESOURCE ResourceContents;
  48. PNTDDK_ERESOURCE DdkResource;
  49. NTDDK_ERESOURCE DdkResourceContents;
  50. ULONG i;
  51. ULONG j;
  52. PKTHREAD Thread;
  53. LONG ThreadCount;
  54. UCHAR DdkThreadCount;
  55. UCHAR chSymbol[120];
  56. BOOLEAN Verbose;
  57. PUCHAR s;
  58. ULONG TotalLocks;
  59. ULONG TotalUsedLocks;
  60. ULONG SkippedLocks;
  61. ResourceToDump = 0;
  62. DisplayZero = FALSE;
  63. Performance = FALSE;
  64. Verbose = FALSE;
  65. s = (PSTR)args;
  66. while ( s != NULL && *s ) {
  67. if (*s == '-' || *s == '/') {
  68. while (*++s) {
  69. switch (*s) {
  70. case 'D':
  71. case 'd':
  72. DisplayZero = TRUE;
  73. break;
  74. case 'P':
  75. case 'p':
  76. Performance = TRUE;
  77. break;
  78. case 'V':
  79. case 'v':
  80. Verbose = TRUE;
  81. break;
  82. case ' ':
  83. goto gotBlank;
  84. default:
  85. dprintf( "KD: !locks invalid option flag '-%c'\n", *s );
  86. break;
  87. }
  88. }
  89. } else if (*s != ' ') {
  90. sscanf(s,"%lx",&ResourceToDump);
  91. s = strpbrk( s, " " );
  92. } else {
  93. gotBlank:
  94. s++;
  95. }
  96. }
  97. //
  98. // Dump performance data if requested.
  99. //
  100. if (Performance != FALSE) {
  101. dprintf("**** Dump Resource Performance Data ****\n\n");
  102. PerformanceData = GetExpression("ExpResourcePerformanceData");
  103. if ((PerformanceData == 0) ||
  104. (ReadMemory((DWORD)PerformanceData,
  105. &ResourcePerformanceData,
  106. sizeof(RESOURCE_PERFORMANCE_DATA),
  107. &Result) == FALSE)) {
  108. //
  109. // The target build does not support resource performance data.
  110. //
  111. dprintf("%08lx: No resource performance data available\n", Result);
  112. } else {
  113. //
  114. // Output the summary statistics.
  115. //
  116. dprintf("Total resources initialized : %u\n",
  117. ResourcePerformanceData.TotalResourceCount);
  118. dprintf("Currently active resources : %u\n",
  119. ResourcePerformanceData.ActiveResourceCount);
  120. dprintf("Exclusive resource acquires : %u\n",
  121. ResourcePerformanceData.ExclusiveAcquire);
  122. dprintf("Shared resource acquires (fl) : %u\n",
  123. ResourcePerformanceData.SharedFirstLevel);
  124. dprintf("Shared resource acquires (sl) : %u\n",
  125. ResourcePerformanceData.SharedSecondLevel);
  126. dprintf("Starve resource acquires (fl) : %u\n",
  127. ResourcePerformanceData.StarveFirstLevel);
  128. dprintf("Starve resource acquires (sl) : %u\n",
  129. ResourcePerformanceData.StarveSecondLevel);
  130. dprintf("Shared wait resource acquires : %u\n",
  131. ResourcePerformanceData.WaitForExclusive);
  132. dprintf("Owner table expansions : %u\n",
  133. ResourcePerformanceData.OwnerTableExpands);
  134. dprintf("Maximum table expansion : %u\n\n",
  135. ResourcePerformanceData.MaximumTableExpand);
  136. //
  137. // Dump the inactive resource statistics.
  138. //
  139. dprintf(" Inactive Resource Statistics\n");
  140. dprintf("Contention Number Initialization Address\n\n");
  141. for (Index = 0; Index < RESOURCE_HASH_TABLE_SIZE; Index += 1) {
  142. End = FIELD_OFFSET(RESOURCE_PERFORMANCE_DATA, HashTable) +
  143. PerformanceData + sizeof(LIST_ENTRY) * Index;
  144. Next = ResourcePerformanceData.HashTable[Index].Flink;
  145. while ((ULONG)Next != End) {
  146. if (ReadMemory((DWORD)Next,
  147. &HashEntry,
  148. sizeof(RESOURCE_HASH_ENTRY),
  149. &Result) != FALSE) {
  150. GetSymbol(HashEntry.Address, &Buffer[0], &Displacement);
  151. dprintf("%10d %6d %s",
  152. HashEntry.ContentionCount,
  153. HashEntry.Number,
  154. &Buffer[0]);
  155. if (Displacement != 0) {
  156. dprintf("+0x%x", Displacement);
  157. }
  158. dprintf("\n");
  159. }
  160. Next = HashEntry.ListEntry.Flink;
  161. }
  162. }
  163. //
  164. // Dump the active resource statistics.
  165. //
  166. dprintf("\n Active Resource Statistics\n");
  167. dprintf("Resource Contention Initialization Address\n\n");
  168. //
  169. // Read the resource listhead and check if it is empty.
  170. //
  171. ResourceHead = GetExpression("ExpSystemResourcesList");
  172. if ((ResourceHead == 0) ||
  173. (ReadMemory((DWORD)ResourceHead,
  174. &List,
  175. sizeof(LIST_ENTRY),
  176. &Result) == FALSE)) {
  177. dprintf("%08lx: Unable to get value of ExpSystemResourcesList\n", ResourceHead );
  178. return;
  179. }
  180. Next = List.Flink;
  181. if (Next == NULL) {
  182. dprintf("ExpSystemResourcesList is NULL!\n");
  183. return;
  184. }
  185. //
  186. // Scan the resource list and dump the resource information.
  187. //
  188. while((ULONG)Next != ResourceHead) {
  189. Resource = CONTAINING_RECORD(Next, ERESOURCE, SystemResourcesList);
  190. if (ReadMemory((DWORD)Resource,
  191. &ResourceContents,
  192. sizeof(ERESOURCE),
  193. &Result) == FALSE) {
  194. dprintf("%08lx: Unable to read _ERESOURCE\n", Resource);
  195. continue;
  196. } else {
  197. if ((ResourceContents.ContentionCount != 0) ||
  198. (DisplayZero != FALSE)) {
  199. GetSymbol(ResourceContents.Address,
  200. &Buffer[0],
  201. &Displacement);
  202. dprintf("%08lx %10d %s",
  203. Resource,
  204. ResourceContents.ContentionCount,
  205. &Buffer[0]);
  206. if (Displacement != 0) {
  207. dprintf("+0x%x", Displacement);
  208. }
  209. dprintf("\n");
  210. }
  211. }
  212. Next = ResourceContents.SystemResourcesList.Flink;
  213. }
  214. dprintf("\n");
  215. //
  216. // Dump the active fast mutex statistics.
  217. //
  218. dprintf("\n Active Fast Mutex Statistics\n");
  219. dprintf("Address Contention Fast Mutex Name\n\n");
  220. //
  221. // Dump statistics for static fast mutexes.
  222. //
  223. DumpStaticFastMutex("CmpKcbLock");
  224. DumpStaticFastMutex("FsRtlCreateLockInfo");
  225. DumpStaticFastMutex("MmPageFileCreationLock");
  226. DumpStaticFastMutex("MmSectionCommitMutex");
  227. DumpStaticFastMutex("MmSectionBasedMutex");
  228. DumpStaticFastMutex("ObpRootDirectoryMutex");
  229. DumpStaticFastMutex("PspActiveProcessMutex");
  230. DumpStaticFastMutex("PspProcessLockMutex");
  231. DumpStaticFastMutex("PspProcessSecurityLock");
  232. DumpStaticFastMutex("SepLsaQueueLock");
  233. dprintf("\n");
  234. }
  235. return;
  236. }
  237. //
  238. // Dump remaining lock data.
  239. //
  240. if (ResourceToDump == 0) {
  241. dprintf("**** DUMP OF ALL RESOURCE OBJECTS ****\n");
  242. ResourceHead = GetExpression( "ExpSystemResourcesList" );
  243. if ( !ResourceHead ||
  244. !ReadMemory( (DWORD)ResourceHead,
  245. &List,
  246. sizeof(LIST_ENTRY),
  247. &Result) ) {
  248. dprintf("%08lx: Unable to get value of ExpSystemResourcesList\n", ResourceHead );
  249. return;
  250. }
  251. Next = List.Flink;
  252. if (Next == NULL) {
  253. dprintf("ExpSystemResourcesList is NULL!\n");
  254. return;
  255. }
  256. } else {
  257. Next = NULL;
  258. ResourceHead = 1;
  259. }
  260. TotalLocks = 0;
  261. TotalUsedLocks = 0;
  262. SkippedLocks = 0;
  263. while((ULONG)Next != ResourceHead) {
  264. if (Next != NULL) {
  265. Resource = CONTAINING_RECORD(Next,ERESOURCE,SystemResourcesList);
  266. } else {
  267. Resource = (PERESOURCE)ResourceToDump;
  268. }
  269. if ( !ReadMemory( (DWORD)Resource,
  270. &ResourceContents,
  271. sizeof(ERESOURCE),
  272. &Result) ) {
  273. dprintf("%08lx: Unable to read _ERESOURCE\n", Resource );
  274. break;
  275. }
  276. //
  277. // Detect here if this is an NtDdk resource, and behave
  278. // appropriatelty. If the OwnerThreads is a pointer to the initial
  279. // owner threads array (this must take into account that the LOCAL
  280. // data structure is a copy of what's in the remote machine in a
  281. // different address)
  282. //
  283. DdkResource = (PNTDDK_ERESOURCE)&ResourceContents;
  284. if (DdkResource->OwnerThreads ==
  285. &((PNTDDK_ERESOURCE)Resource)->InitialOwnerThreads[0]) {
  286. if ( !ReadMemory( (DWORD)Resource,
  287. &DdkResourceContents,
  288. sizeof(NTDDK_ERESOURCE),
  289. &Result) ) {
  290. dprintf("%08lx: Unable to read _NTDDK_ERESOURCE\n", Resource );
  291. break;
  292. }
  293. DdkResource = &DdkResourceContents;
  294. ActiveCount = DdkResource->ActiveCount;
  295. ContentionCount = DdkResource->ContentionCount;
  296. Flag = DdkResource->Flag;
  297. NumberOfExclusiveWaiters = DdkResource->NumberOfExclusiveWaiters;
  298. NumberOfSharedWaiters = DdkResource->NumberOfSharedWaiters;
  299. TableSize = DdkResource->TableSize;
  300. } else {
  301. DdkResource = NULL;
  302. ActiveCount = ResourceContents.ActiveCount;
  303. ContentionCount = ResourceContents.ContentionCount;
  304. Flag = ResourceContents.Flag;
  305. NumberOfExclusiveWaiters = ResourceContents.NumberOfExclusiveWaiters;
  306. NumberOfSharedWaiters = ResourceContents.NumberOfSharedWaiters;
  307. TableSize = ResourceContents.OwnerThreads[0].TableSize;
  308. }
  309. TotalLocks++;
  310. if ((ResourceToDump != 0) || Verbose || (ActiveCount != 0)) {
  311. EXPRLastDump = (ULONG)Resource;
  312. if (SkippedLocks) {
  313. dprintf("\n");
  314. SkippedLocks = 0;
  315. }
  316. dprintf("\n");
  317. dumpSymbolicAddress((ULONG)Resource, chSymbol, TRUE);
  318. dprintf("Resource @ %s", chSymbol );
  319. if (ActiveCount == 0) {
  320. dprintf(" Available\n");
  321. } else if (Flag & ResourceOwnedExclusive) {
  322. TotalUsedLocks++;
  323. dprintf(" Exclusively owned\n");
  324. } else {
  325. TotalUsedLocks++;
  326. dprintf(" Shared %u owning threads\n", ActiveCount);
  327. }
  328. if (ContentionCount != 0) {
  329. dprintf(" Contention Count = %u\n", ContentionCount);
  330. }
  331. if (NumberOfSharedWaiters != 0) {
  332. dprintf(" NumberOfSharedWaiters = %u\n", NumberOfSharedWaiters);
  333. }
  334. if (NumberOfExclusiveWaiters != 0) {
  335. dprintf(" NumberOfExclusiveWaiters = %u\n", NumberOfExclusiveWaiters);
  336. }
  337. #ifdef i386
  338. if (DdkResource != NULL) {
  339. if (DdkResource->CreatorBackTraceIndex != 0) {
  340. dprintf(" Created by:\n");
  341. dumpBackTraceIndex( DdkResource->CreatorBackTraceIndex,
  342. " " );
  343. }
  344. if (ActiveCount != 0) {
  345. dprintf(" Owned\n");
  346. }
  347. }
  348. #endif // i386
  349. if (ActiveCount != 0) {
  350. j = 0;
  351. dprintf(" Threads: ");
  352. if (DdkResource == NULL) {
  353. Thread = (PKTHREAD)ResourceContents.OwnerThreads[0].OwnerThread;
  354. ThreadCount = ResourceContents.OwnerThreads[0].OwnerCount;
  355. if (Thread != NULL) {
  356. j++;
  357. dprintf("%08lx-%02x ", Thread, ThreadCount);
  358. }
  359. Thread = (PKTHREAD)ResourceContents.OwnerThreads[1].OwnerThread;
  360. ThreadCount = ResourceContents.OwnerThreads[1].OwnerCount;
  361. if (Thread != NULL) {
  362. j++;
  363. dprintf("%08lx-%02x ", Thread, ThreadCount);
  364. }
  365. }
  366. for (i = 0; i < TableSize; i++) {
  367. if (DdkResource != NULL) {
  368. if ( !ReadMemory( (DWORD)&DdkResource->OwnerThreads[i],
  369. &Thread,
  370. sizeof (Thread),
  371. &Result) ) {
  372. dprintf("\n%08lx: DDK: Unable to read ThreadTable for resource\n",&ResourceContents.OwnerThreads[i] );
  373. break;
  374. }
  375. //
  376. // Ddk resources can only ever be using a single
  377. // table entry.
  378. //
  379. if ( !ReadMemory( (DWORD)&DdkResource->OwnerCounts[i],
  380. &DdkThreadCount,
  381. sizeof (ThreadCount),
  382. &Result) ) {
  383. dprintf("\n%08lx: DDK: Unable to read ThreadCount for resource\n",&DdkResource->OwnerCounts[i]);
  384. break;
  385. ThreadCount = DdkThreadCount;
  386. }
  387. } else {
  388. if ( !ReadMemory( (DWORD)&ResourceContents.OwnerTable[i],
  389. &OwnerEntry,
  390. sizeof (OWNER_ENTRY),
  391. &Result) ) {
  392. dprintf("\n%08lx: Unable to read ThreadCount for resource\n", &Resource->OwnerTable[i]);
  393. break;
  394. }
  395. Thread = (PKTHREAD)OwnerEntry.OwnerThread;
  396. ThreadCount = OwnerEntry.OwnerCount;
  397. }
  398. if ((Thread == NULL) && (ThreadCount == 0)) {
  399. continue;
  400. }
  401. if (j == 4) {
  402. j = 0;
  403. dprintf("\n ");
  404. }
  405. dprintf("%08lx-%02x ", Thread, ThreadCount);
  406. j++;
  407. if ( CheckControlC() ) {
  408. return;
  409. }
  410. }
  411. if (j) {
  412. dprintf("\n");
  413. }
  414. }
  415. } else {
  416. if ((SkippedLocks++ % 32) == 0) {
  417. if (SkippedLocks == 1) {
  418. dprintf("KD: Scanning for held locks." );
  419. } else {
  420. dprintf("." );
  421. }
  422. }
  423. }
  424. if (ResourceToDump != 0) {
  425. break;
  426. }
  427. Next = ResourceContents.SystemResourcesList.Flink;
  428. if ( CheckControlC() ) {
  429. return;
  430. }
  431. }
  432. if (SkippedLocks) {
  433. dprintf("\n");
  434. }
  435. dprintf( "%u total locks", TotalLocks );
  436. if (TotalUsedLocks) {
  437. dprintf( ", %u locks currently held", TotalUsedLocks );
  438. }
  439. dprintf("\n");
  440. return;
  441. }
  442. VOID
  443. DumpStaticFastMutex (
  444. IN PCHAR Name
  445. )
  446. /*++
  447. Routine Description:
  448. This function dumps the contention statistics for a fast mutex.
  449. Arguments:
  450. Name - Supplies a pointer to the symbol name for the fast mutex.
  451. Return Value:
  452. None.
  453. --*/
  454. {
  455. ULONG FastMutex;
  456. FAST_MUTEX FastMutexContents;
  457. ULONG Result;
  458. //
  459. // Get the address of the fast mutex, read the fast mutex contents,
  460. // and dump the contention data.
  461. //
  462. FastMutex = GetExpression(Name);
  463. if ((FastMutex != 0) && (ReadMemory((DWORD)FastMutex,
  464. &FastMutexContents,
  465. sizeof(FAST_MUTEX),
  466. &Result) != FALSE)) {
  467. dprintf("%08lx %10u %s\n",
  468. FastMutex,
  469. FastMutexContents.Contention,
  470. &Name[0]);
  471. }
  472. return;
  473. }