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.

1120 lines
34 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name:
  4. heappagx.c
  5. Abstract:
  6. This module contains the page heap manager debug extensions.
  7. Author:
  8. Tom McGuire (TomMcg) 06-Jan-1995
  9. Silviu Calinoiu (SilviuC) 22-Feb-2000
  10. Revision History:
  11. --*/
  12. #define DEBUG_PAGE_HEAP 1
  13. #include "precomp.h"
  14. #include "heap.h"
  15. __inline
  16. BOOLEAN
  17. CheckInterrupted(
  18. VOID
  19. )
  20. {
  21. if (CheckControlC()) {
  22. dprintf( "\nInterrupted\n\n" );
  23. return TRUE;
  24. }
  25. return FALSE;
  26. }
  27. __inline
  28. ULONG64
  29. FetchRemotePVOID (
  30. ULONG64 Address
  31. )
  32. {
  33. ULONG64 RemoteValue = 0;
  34. ReadPointer( Address, &RemoteValue);
  35. return RemoteValue;
  36. }
  37. __inline
  38. ULONG
  39. FetchRemoteULONG(
  40. ULONG64 Address
  41. )
  42. {
  43. ULONG RemoteValue = 0;
  44. ReadMemory( Address, &RemoteValue, sizeof( ULONG ), NULL );
  45. return RemoteValue;
  46. }
  47. ULONG
  48. ReturnFieldOffset(
  49. PCHAR TypeName,
  50. PCHAR FieldName);
  51. #define FETCH_REMOTE_FIELD_PTR( StructBase, StructType, FieldName ) \
  52. FetchRemotePVOID((StructBase) + ReturnFieldOffset( #StructType, #FieldName ))
  53. #define FETCH_REMOTE_FIELD_INT( StructBase, StructType, FieldName ) \
  54. FetchRemoteULONG((StructBase) + ReturnFieldOffset( #StructType, #FieldName ))
  55. #define FETCH_REMOTE_FIELD_SIZE_T( StructBase, StructType, FieldName ) \
  56. FetchRemotePVOID((StructBase) + ReturnFieldOffset( #StructType, #FieldName ))
  57. #define DUMP_REMOTE_FIELD_INT( DumpName, StructBase, StructType, FieldName ) \
  58. dprintf( "%s%08X\n", (DumpName), FETCH_REMOTE_FIELD_INT( StructBase, StructType, FieldName ))
  59. #define DUMP_REMOTE_FIELD_PTR( DumpName, StructBase, StructType, FieldName ) \
  60. dprintf( "%s%p\n", (DumpName), FETCH_REMOTE_FIELD_PTR( StructBase, StructType, FieldName ))
  61. VOID
  62. DebugPageHeapLocateFaultAllocationXP(
  63. ULONG64 RemoteHeap,
  64. ULONG64 AddressOfFault
  65. );
  66. VOID
  67. DebugPageHeapReportAllocationXP(
  68. ULONG64 RemoteHeap,
  69. ULONG64 RemoteHeapNode,
  70. PCHAR NodeType,
  71. ULONG64 AddressOfFault
  72. );
  73. BOOLEAN
  74. DebugPageHeapExtensionShowHeapListXP(
  75. VOID
  76. );
  77. VOID
  78. TraceDatabaseDumpXP (
  79. PCSTR Args,
  80. BOOLEAN SortByCountField
  81. );
  82. VOID
  83. TraceDatabaseBlockDumpXP (
  84. ULONG64 Address
  85. );
  86. VOID
  87. FaultInjectionTracesDumpXP (
  88. PCSTR Args
  89. );
  90. /////////////////////////////////////////////////////////////////////
  91. /////////////////////////////////////////////////////////////////////
  92. /////////////////////////////////////////////////////////////////////
  93. VOID DebugPageHeapHelpXP (
  94. )
  95. {
  96. dprintf ("!heap -p Dump all page heaps. \n");
  97. dprintf ("!heap -p -h ADDR Detailed dump of page heap at ADDR. \n");
  98. dprintf ("!heap -p -a ADDR Figure out what heap block is at ADDR. \n");
  99. dprintf ("!heap -p -t [N] Dump N collected traces with heavy heap users.\n");
  100. dprintf ("!heap -p -tc [N] Dump N traces sorted by count usage (eqv. with -t).\n");
  101. dprintf ("!heap -p -ts [N] Dump N traces sorted by size.\n");
  102. dprintf ("!heap -p -fi [N] Dump last N fault injection traces.\n");
  103. dprintf (" \n");
  104. dprintf (" +-----+---------------+--+ \n");
  105. dprintf (" | | | | Normal heap allocated block \n");
  106. dprintf (" +-----+---------------+--+ \n");
  107. dprintf (" ^ ^ ^ \n");
  108. dprintf (" | | 8 suffix bytes filled with 0xA0 \n");
  109. dprintf (" | user allocation (filled with E0 if zeroing not requested) \n");
  110. dprintf (" block header (starts with 0xABCDAAAA and ends with 0xDCBAAAAA).\n");
  111. dprintf (" A `dt DPH_BLOCK_INFORMATION' on header address followed by \n");
  112. dprintf (" a `dds' on the StackTrace field gives the stacktrace of allocation. \n");
  113. dprintf (" \n");
  114. dprintf (" +-----+---------------+--+ \n");
  115. dprintf (" | | | | Normal heap freed block \n");
  116. dprintf (" +-----+---------------+--+ \n");
  117. dprintf (" ^ ^ ^ \n");
  118. dprintf (" | | 8 suffix bytes filled with 0xA0 \n");
  119. dprintf (" | user allocation (filled with F0 bytes) \n");
  120. dprintf (" block header (starts with 0xABCDAAA9 and ends with 0xDCBAAA9). \n");
  121. dprintf (" A `dt DPH_BLOCK_INFORMATION' on header address followed by \n");
  122. dprintf (" a `dds' on the StackTrace field gives the stacktrace of allocation. \n");
  123. dprintf (" \n");
  124. dprintf (" +-----+---------+--+------ \n");
  125. dprintf (" | | | | ... N/A page Page heap \n");
  126. dprintf (" +-----+---------+--+------ allocated block \n");
  127. dprintf (" ^ ^ ^ \n");
  128. dprintf (" | | 0-7 suffix bytes filled with 0xD0 \n");
  129. dprintf (" | user allocation (filled with C0 if zeroing not requested) \n");
  130. dprintf (" block header (starts with 0xABCDBBBB and ends with 0xDCBABBBB).\n");
  131. dprintf (" A `dt DPH_BLOCK_INFORMATION' on header address followed by \n");
  132. dprintf (" a `dds' on the StackTrace field gives the stacktrace of allocation. \n");
  133. dprintf (" \n");
  134. dprintf (" +-----+---------+--+------ \n");
  135. dprintf (" | | | | ... N/A page Page heap \n");
  136. dprintf (" +-----+---------+--+------ freed block \n");
  137. dprintf (" ^ ^ ^ \n");
  138. dprintf (" | | 0-7 suffix bytes filled with 0xD0 \n");
  139. dprintf (" | user allocation (filled with F0 bytes) \n");
  140. dprintf (" block header (starts with 0xABCDBBA and ends with 0xDCBABBBA).\n");
  141. dprintf (" A `dt DPH_BLOCK_INFORMATION' on header address followed by \n");
  142. dprintf (" a `dds' on the StackTrace field gives the stacktrace of allocation. \n");
  143. dprintf (" \n");
  144. }
  145. VOID
  146. DebugPageHeapExtensionFindXP(
  147. PCSTR ArgumentString
  148. )
  149. {
  150. ULONG64 RemoteHeapList;
  151. ULONG64 RemoteHeap;
  152. ULONG64 RemoteVirtualNode;
  153. ULONG64 RemoteVirtualBase;
  154. ULONG64 RemoteVirtualSize;
  155. ULONG64 AddressOfFault;
  156. BOOL Result;
  157. Result = GetExpressionEx (ArgumentString,
  158. &AddressOfFault,
  159. &ArgumentString);
  160. if (Result == FALSE) {
  161. dprintf ("\nFailed to convert `%s' to an address.\n",
  162. ArgumentString);
  163. return;
  164. }
  165. RemoteHeapList = (ULONG64) GetExpression( "NTDLL!RtlpDphHeapListHead" );
  166. RemoteHeap = FetchRemotePVOID( RemoteHeapList );
  167. if (RemoteHeap == 0) {
  168. dprintf( "\nNo page heaps active in process (or bad symbols)\n\n" );
  169. AddressOfFault = 0;
  170. }
  171. if (( AddressOfFault == 0 ) || ( strchr( ArgumentString, '?' ))) {
  172. DebugPageHeapHelpXP();
  173. return;
  174. }
  175. //
  176. // Find the heap that contains the range of virtual addresses that
  177. // contain the AddressOfFault.
  178. //
  179. for (;;) {
  180. //
  181. // The heap header contains a linked list of virtual memory
  182. // allocations.
  183. //
  184. RemoteVirtualNode = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pVirtualStorageListHead );
  185. while (RemoteVirtualNode != 0) {
  186. RemoteVirtualBase = FETCH_REMOTE_FIELD_PTR( RemoteVirtualNode, NTDLL!_DPH_HEAP_BLOCK, pVirtualBlock );
  187. RemoteVirtualSize = FETCH_REMOTE_FIELD_SIZE_T( RemoteVirtualNode, NTDLL!_DPH_HEAP_BLOCK, nVirtualBlockSize );
  188. if (( RemoteVirtualBase == 0 ) || ( RemoteVirtualSize == 0 )) {
  189. dprintf( "\nPAGEHEAP: Heap 0x%p appears to have an invalid\n"
  190. " virtual allocation list\n\n",
  191. RemoteHeap
  192. );
  193. }
  194. if ((AddressOfFault >= RemoteVirtualBase) &&
  195. (AddressOfFault <= RemoteVirtualBase + RemoteVirtualSize )) {
  196. //
  197. // The fault appears to have occurred in the range of this
  198. // heap, so we'll search the busy and free lists for the
  199. // closest match and report it. Then exit.
  200. //
  201. DebugPageHeapLocateFaultAllocationXP( RemoteHeap, AddressOfFault );
  202. return;
  203. }
  204. if (CheckInterrupted()) {
  205. return;
  206. }
  207. RemoteVirtualNode = FETCH_REMOTE_FIELD_PTR( RemoteVirtualNode, NTDLL!_DPH_HEAP_BLOCK, pNextAlloc );
  208. }
  209. //
  210. // Not found in this heap. Continue with next heap or end
  211. // of heap list.
  212. //
  213. if (CheckInterrupted()) {
  214. return;
  215. }
  216. RemoteHeap = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pNextHeapRoot );
  217. if (RemoteHeap == 0) {
  218. dprintf( "\nPAGEHEAP: Could not find a page heap containing\n"
  219. " the virtual address 0x%p\n\n",
  220. AddressOfFault
  221. );
  222. return;
  223. }
  224. }
  225. }
  226. VOID
  227. DebugPageHeapLocateFaultAllocationXP(
  228. ULONG64 RemoteHeap,
  229. ULONG64 AddressOfFault
  230. )
  231. {
  232. ULONG64 ClosestHeapNode;
  233. ULONG64 ClosestDifference;
  234. ULONG64 RemoteHeapNode;
  235. ULONG64 RemoteAllocBase;
  236. ULONG64 RemoteAllocSize;
  237. ULONG RemoteFreeListSize;
  238. ClosestHeapNode = 0;
  239. //
  240. // First search the busy list for the containing allocation, if any.
  241. //
  242. RemoteHeapNode = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pBusyAllocationListHead );
  243. while (RemoteHeapNode != 0) {
  244. RemoteAllocBase = FETCH_REMOTE_FIELD_PTR( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, pVirtualBlock );
  245. RemoteAllocSize = FETCH_REMOTE_FIELD_SIZE_T( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, nVirtualBlockSize );
  246. if ((AddressOfFault >= RemoteAllocBase) &&
  247. (AddressOfFault < RemoteAllocBase + RemoteAllocSize)) {
  248. //
  249. // The fault appears to have occurred in this allocation's
  250. // memory (which includes the NO_ACCESS page beyond the user
  251. // portion of the allocation).
  252. //
  253. DebugPageHeapReportAllocationXP( RemoteHeap, RemoteHeapNode, "allocated", AddressOfFault );
  254. return;
  255. }
  256. if (CheckInterrupted()) {
  257. return;
  258. }
  259. RemoteHeapNode = FETCH_REMOTE_FIELD_PTR( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, pNextAlloc );
  260. }
  261. //
  262. // Failed to find containing allocation on busy list, so search free.
  263. //
  264. RemoteHeapNode = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pFreeAllocationListHead );
  265. while (RemoteHeapNode != 0) {
  266. RemoteAllocBase = FETCH_REMOTE_FIELD_PTR( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, pVirtualBlock );
  267. RemoteAllocSize = FETCH_REMOTE_FIELD_INT( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, nVirtualBlockSize );
  268. if ((AddressOfFault >= RemoteAllocBase) &&
  269. (AddressOfFault < RemoteAllocBase + RemoteAllocSize)) {
  270. //
  271. // The fault appears to have occurred in this freed alloc's
  272. // memory.
  273. //
  274. DebugPageHeapReportAllocationXP( RemoteHeap, RemoteHeapNode, "freed", AddressOfFault );
  275. return;
  276. }
  277. if (CheckInterrupted()) {
  278. return;
  279. }
  280. RemoteHeapNode = FETCH_REMOTE_FIELD_PTR( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, pNextAlloc );
  281. }
  282. //
  283. // Failed to find containing allocation in free list, but we wouldn't
  284. // have gotten this far if the debug heap did not contain the virtual
  285. // address range of the fault. So, report it as a wild pointer that
  286. // could have been freed memory.
  287. //
  288. RemoteFreeListSize = FETCH_REMOTE_FIELD_INT( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nFreeAllocations );
  289. dprintf( "\nPAGEHEAP: %p references memory contained in the heap %p,\n"
  290. " but does not reference an existing allocated or\n"
  291. " recently freed heap block. It is possible that\n"
  292. " the memory at %p could previously have been\n"
  293. " allocated and freed, but it must have been freed\n"
  294. " prior to the most recent %d frees.\n\n",
  295. AddressOfFault,
  296. RemoteHeap,
  297. AddressOfFault,
  298. RemoteFreeListSize
  299. );
  300. }
  301. VOID
  302. DebugPageHeapReportAllocationXP(
  303. ULONG64 RemoteHeap,
  304. ULONG64 RemoteHeapNode,
  305. PCHAR NodeType,
  306. ULONG64 AddressOfFault
  307. )
  308. {
  309. ULONG64 RemoteUserBase;
  310. ULONG64 RemoteUserSize;
  311. ULONG64 EndOfBlock;
  312. ULONG64 PastTheBlock;
  313. ULONG64 BeforeTheBlock;
  314. RemoteUserBase = FETCH_REMOTE_FIELD_PTR( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, pUserAllocation );
  315. RemoteUserSize = FETCH_REMOTE_FIELD_SIZE_T( RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, nUserRequestedSize );
  316. EndOfBlock = RemoteUserBase + RemoteUserSize - 1;
  317. if (AddressOfFault > EndOfBlock) {
  318. PastTheBlock = AddressOfFault - EndOfBlock;
  319. dprintf( "\nPAGEHEAP: %p is %p bytes beyond the end of %s heap block at\n"
  320. " %p of 0x%x bytes",
  321. AddressOfFault,
  322. PastTheBlock,
  323. NodeType,
  324. RemoteUserBase,
  325. RemoteUserSize
  326. );
  327. }
  328. else if (AddressOfFault >= RemoteUserBase) {
  329. dprintf( "\nPAGEHEAP: %p references %s heap block at\n"
  330. " %p of 0x%x bytes",
  331. AddressOfFault,
  332. NodeType,
  333. RemoteUserBase,
  334. RemoteUserSize
  335. );
  336. }
  337. else {
  338. BeforeTheBlock = (PCHAR) RemoteUserBase - (PCHAR) AddressOfFault;
  339. dprintf( "\nPAGEHEAP: %p is %p bytes before the %s heap block at\n"
  340. " %p of 0x%x bytes",
  341. AddressOfFault,
  342. BeforeTheBlock,
  343. NodeType,
  344. RemoteUserBase,
  345. RemoteUserSize
  346. );
  347. }
  348. {
  349. ULONG64 Trace;
  350. Trace = FETCH_REMOTE_FIELD_PTR (RemoteHeapNode, NTDLL!_DPH_HEAP_BLOCK, StackTrace);
  351. dprintf ("\n\n");
  352. TraceDatabaseBlockDumpXP (Trace);
  353. }
  354. }
  355. #define FORMAT_TYPE_BUSY_LIST 0
  356. #define FORMAT_TYPE_FREE_LIST 1
  357. #define FORMAT_TYPE_VIRT_LIST 2
  358. BOOLEAN
  359. DebugPageHeapDumpThisListXP(
  360. ULONG64 RemoteList,
  361. PCH ListName,
  362. ULONG FormatType
  363. )
  364. {
  365. ULONG64 RemoteNode;
  366. ULONG64 RemoteBase;
  367. ULONG64 RemoteSize;
  368. ULONG64 RemoteUser;
  369. ULONG64 RemoteUsiz;
  370. ULONG RemoteFlag;
  371. ULONG64 RemoteValu;
  372. RemoteNode = RemoteList;
  373. dprintf( "\n%s:\n", ListName );
  374. switch (FormatType) {
  375. case FORMAT_TYPE_BUSY_LIST:
  376. dprintf( "UserAddr UserSize VirtAddr VirtSize UserFlag UserValu\n" );
  377. break;
  378. case FORMAT_TYPE_FREE_LIST:
  379. dprintf( "UserAddr UserSize VirtAddr VirtSize\n" );
  380. break;
  381. }
  382. while (RemoteNode) {
  383. RemoteBase = FETCH_REMOTE_FIELD_PTR( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, pVirtualBlock );
  384. RemoteSize = FETCH_REMOTE_FIELD_SIZE_T( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, nVirtualBlockSize );
  385. RemoteUser = FETCH_REMOTE_FIELD_PTR( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, pUserAllocation );
  386. RemoteUsiz = FETCH_REMOTE_FIELD_SIZE_T( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, nUserRequestedSize );
  387. RemoteFlag = FETCH_REMOTE_FIELD_INT( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, UserFlags );
  388. RemoteValu = FETCH_REMOTE_FIELD_PTR( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, UserValue );
  389. RemoteNode = FETCH_REMOTE_FIELD_PTR( RemoteNode, NTDLL!_DPH_HEAP_BLOCK, pNextAlloc );
  390. switch (FormatType) {
  391. case FORMAT_TYPE_BUSY_LIST:
  392. dprintf(( RemoteFlag || RemoteValu ) ?
  393. "%p %08X %p %08X %08X %p\n" :
  394. "%p %08X %p %08X\n",
  395. RemoteUser,
  396. RemoteUsiz,
  397. RemoteBase,
  398. RemoteSize,
  399. RemoteFlag,
  400. RemoteValu
  401. );
  402. break;
  403. case FORMAT_TYPE_FREE_LIST:
  404. dprintf( "%p %08X %p %08X\n",
  405. RemoteUser,
  406. RemoteUsiz,
  407. RemoteBase,
  408. RemoteSize
  409. );
  410. break;
  411. case FORMAT_TYPE_VIRT_LIST:
  412. dprintf( "%p - %p (%08X)\n",
  413. RemoteBase,
  414. (PCH)RemoteBase + RemoteSize,
  415. RemoteSize
  416. );
  417. break;
  418. }
  419. if (CheckInterrupted()) {
  420. return FALSE;
  421. }
  422. }
  423. return TRUE;
  424. }
  425. BOOLEAN
  426. DebugPageHeapDumpThisHeapXP(
  427. ULONG64 RemoteHeap
  428. )
  429. {
  430. ULONG64 RemoteNode;
  431. dprintf( "\nDPH Heap at %p:\n\n", RemoteHeap );
  432. DUMP_REMOTE_FIELD_INT( "Signature: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Signature );
  433. DUMP_REMOTE_FIELD_INT( "HeapFlags: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, HeapFlags );
  434. DUMP_REMOTE_FIELD_INT( "ExtraFlags: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, ExtraFlags );
  435. DUMP_REMOTE_FIELD_INT( "NormalHeap: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, NormalHeap );
  436. DUMP_REMOTE_FIELD_INT( "VirtualRanges: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nVirtualStorageRanges );
  437. DUMP_REMOTE_FIELD_PTR( "VirtualCommit: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nVirtualStorageBytes );
  438. DUMP_REMOTE_FIELD_INT( "BusyAllocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nBusyAllocations );
  439. DUMP_REMOTE_FIELD_PTR( "BusyVirtual: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nBusyAllocationBytesCommitted );
  440. DUMP_REMOTE_FIELD_PTR( "BusyReadWrite: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nBusyAllocationBytesAccessible );
  441. DUMP_REMOTE_FIELD_INT( "FreeAllocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nFreeAllocations );
  442. DUMP_REMOTE_FIELD_PTR( "FreeVirtual: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nFreeAllocationBytesCommitted );
  443. DUMP_REMOTE_FIELD_INT( "AvailAllocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nAvailableAllocations );
  444. DUMP_REMOTE_FIELD_PTR( "AvailVirtual: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nAvailableAllocationBytesCommitted );
  445. DUMP_REMOTE_FIELD_INT( "NodePools: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nNodePools );
  446. DUMP_REMOTE_FIELD_PTR( "NodeVirtual: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nNodePoolBytes );
  447. DUMP_REMOTE_FIELD_INT( "AvailNodes: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, nUnusedNodes );
  448. DUMP_REMOTE_FIELD_INT( "Seed: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Seed );
  449. dprintf (" --- Counters --- \n");
  450. DUMP_REMOTE_FIELD_INT( "Size < 1K: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[0] );
  451. DUMP_REMOTE_FIELD_INT( "Size < 4K: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[1] );
  452. DUMP_REMOTE_FIELD_INT( "Size >= 4K: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[2] );
  453. DUMP_REMOTE_FIELD_INT( "W/o alloc info: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[3] );
  454. DUMP_REMOTE_FIELD_INT( "Total allocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[4] );
  455. DUMP_REMOTE_FIELD_INT( "Total reallocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[5] );
  456. DUMP_REMOTE_FIELD_INT( "Total frees: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[6] );
  457. DUMP_REMOTE_FIELD_INT( "Normal allocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[7] );
  458. DUMP_REMOTE_FIELD_INT( "Normal reallocs: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[8] );
  459. DUMP_REMOTE_FIELD_INT( "Normal frees: ", RemoteHeap, NTDLL!_DPH_HEAP_ROOT, Counter[9] );
  460. {
  461. ULONG64 Trace;
  462. dprintf ("\n");
  463. Trace = FETCH_REMOTE_FIELD_PTR (RemoteHeap, NTDLL!_DPH_HEAP_ROOT, CreateStackTrace);
  464. TraceDatabaseBlockDumpXP (Trace);
  465. }
  466. if (! DebugPageHeapDumpThisListXP(
  467. FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pVirtualStorageListHead ),
  468. "VirtualList",
  469. FORMAT_TYPE_VIRT_LIST )) {
  470. return FALSE;
  471. }
  472. if (! DebugPageHeapDumpThisListXP(
  473. FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pNodePoolListHead ),
  474. "NodePoolList",
  475. FORMAT_TYPE_VIRT_LIST )) {
  476. return FALSE;
  477. }
  478. if (! DebugPageHeapDumpThisListXP(
  479. FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pAvailableAllocationListHead ),
  480. "AvailableList",
  481. FORMAT_TYPE_VIRT_LIST )) {
  482. return FALSE;
  483. }
  484. if (! DebugPageHeapDumpThisListXP(
  485. FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pFreeAllocationListHead ),
  486. "FreeList",
  487. FORMAT_TYPE_FREE_LIST )) {
  488. return FALSE;
  489. }
  490. if (! DebugPageHeapDumpThisListXP(
  491. FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pBusyAllocationListHead ),
  492. "BusyList",
  493. FORMAT_TYPE_BUSY_LIST )) {
  494. return FALSE;
  495. }
  496. dprintf( "\n" );
  497. return TRUE;
  498. }
  499. VOID
  500. DebugPageHeapExtensionDumpXP(
  501. PCSTR ArgumentString
  502. )
  503. {
  504. ULONG64 RemoteHeapList;
  505. ULONG64 RemoteHeap;
  506. ULONG64 RemoteHeapToDump;
  507. BOOLEAN AnyDumps = FALSE;
  508. BOOL Result;
  509. Result = GetExpressionEx (ArgumentString,
  510. &RemoteHeapToDump,
  511. &ArgumentString);
  512. if (Result == FALSE) {
  513. dprintf ("\nFailed to convert `%s' to an address.\n",
  514. ArgumentString);
  515. return;
  516. }
  517. RemoteHeapList = (ULONG64) GetExpression( "NTDLL!RtlpDphHeapListHead" );
  518. RemoteHeap = FetchRemotePVOID( RemoteHeapList );
  519. if (( RemoteHeap == 0 ) ||
  520. ( RemoteHeapToDump == 0 ) ||
  521. ( strchr( ArgumentString, '?' ))) {
  522. DebugPageHeapHelpXP();
  523. DebugPageHeapExtensionShowHeapListXP();
  524. return;
  525. }
  526. while (RemoteHeap != 0) {
  527. if ((((LONG_PTR)RemoteHeapToDump & 0xFFFF0000 ) == ((LONG_PTR)RemoteHeap & 0xFFFF0000 )) ||
  528. ((LONG_PTR)RemoteHeapToDump == -1 )) {
  529. AnyDumps = TRUE;
  530. if (! DebugPageHeapDumpThisHeapXP( RemoteHeap ))
  531. return;
  532. }
  533. if (CheckInterrupted()) {
  534. return;
  535. }
  536. RemoteHeap = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pNextHeapRoot );
  537. }
  538. if (! AnyDumps) {
  539. dprintf( "\nPage heap \"0x%p\" not found in process\n\n", RemoteHeapToDump );
  540. DebugPageHeapExtensionShowHeapListXP();
  541. }
  542. }
  543. BOOLEAN
  544. DebugPageHeapExtensionShowHeapListXP(
  545. VOID
  546. )
  547. {
  548. ULONG64 RemoteHeapList = (ULONG64)GetExpression( "NTDLL!RtlpDphHeapListHead" );
  549. ULONG64 RemoteHeap = FetchRemotePVOID( RemoteHeapList );
  550. ULONG64 NormalHeap;
  551. ULONG HeapFlags;
  552. if (RemoteHeap == 0) {
  553. dprintf( "\nNo page heaps active in process (or bad symbols)\n" );
  554. return FALSE;
  555. }
  556. else {
  557. dprintf( "\nPage heaps active in process:\n\n" );
  558. do {
  559. NormalHeap = FETCH_REMOTE_FIELD_PTR (RemoteHeap, NTDLL!_DPH_HEAP_ROOT, NormalHeap);
  560. HeapFlags = (ULONG) FETCH_REMOTE_FIELD_INT (RemoteHeap, NTDLL!_DPH_HEAP_ROOT, ExtraFlags);
  561. dprintf (" %p (%p, flags %X)\n", RemoteHeap, NormalHeap, HeapFlags);
  562. RemoteHeap = FETCH_REMOTE_FIELD_PTR( RemoteHeap, NTDLL!_DPH_HEAP_ROOT, pNextHeapRoot );
  563. } while (RemoteHeap);
  564. dprintf( "\n" );
  565. return TRUE;
  566. }
  567. }
  568. BOOLEAN
  569. DebugPageHeapIsActiveXP(
  570. VOID
  571. )
  572. {
  573. ULONG64 RemoteHeapList = (ULONG64)GetExpression( "NTDLL!RtlpDphHeapListHead" );
  574. ULONG64 RemoteHeap = FetchRemotePVOID( RemoteHeapList );
  575. if (RemoteHeap == 0) {
  576. return FALSE;
  577. }
  578. else {
  579. return TRUE;
  580. }
  581. }
  582. VOID
  583. DebugPageHeapExtensionXP(
  584. PCSTR ArgumentString
  585. )
  586. {
  587. PCSTR Current;
  588. //
  589. // Is help requested?
  590. //
  591. if (strstr (ArgumentString, "?") != NULL) {
  592. DebugPageHeapHelpXP ();
  593. }
  594. //
  595. // If page heap not active then return immediately.
  596. //
  597. if (! DebugPageHeapIsActiveXP()) {
  598. dprintf ("Page heap is not active for this process. \n");
  599. return;
  600. }
  601. //
  602. // Parse command line
  603. //
  604. if ((Current = strstr (ArgumentString, "-h")) != NULL) {
  605. DebugPageHeapExtensionDumpXP (Current + strlen("-h"));
  606. }
  607. else if ((Current = strstr (ArgumentString, "-a")) != NULL) {
  608. DebugPageHeapExtensionFindXP (Current + strlen("-a"));
  609. }
  610. else if ((Current = strstr (ArgumentString, "-tc")) != NULL) {
  611. TraceDatabaseDumpXP (Current + strlen("-tc"), TRUE);
  612. }
  613. else if ((Current = strstr (ArgumentString, "-ts")) != NULL) {
  614. TraceDatabaseDumpXP (Current + strlen("-ts"), FALSE);
  615. }
  616. else if ((Current = strstr (ArgumentString, "-t")) != NULL) {
  617. TraceDatabaseDumpXP (Current + strlen("-t"), TRUE);
  618. }
  619. else if ((Current = strstr (ArgumentString, "-fi")) != NULL) {
  620. FaultInjectionTracesDumpXP (Current + strlen("-fi"));
  621. }
  622. else {
  623. DebugPageHeapExtensionShowHeapListXP ();
  624. }
  625. return;
  626. }
  627. /////////////////////////////////////////////////////////////////////
  628. ////////////////////////////////////////////////////// Trace database
  629. /////////////////////////////////////////////////////////////////////
  630. typedef struct {
  631. ULONG64 Address;
  632. ULONG64 Count;
  633. ULONG64 Size;
  634. } TRACE, *PTRACE;
  635. VOID
  636. TraceDatabaseDumpXP (
  637. PCSTR Args,
  638. BOOLEAN SortByCountField
  639. )
  640. {
  641. ULONG64 Database;
  642. ULONG I, J, Min, TraceIndex;
  643. PTRACE Trace;
  644. ULONG64 TracesToDisplay = 0;
  645. ULONG64 MaximumSize;
  646. ULONG64 CurrentSize;
  647. ULONG64 NoOfTraces;
  648. ULONG64 NoOfHits;
  649. ULONG NoOfBuckets;
  650. ULONG PvoidSize;
  651. if (Args) {
  652. TracesToDisplay = GetExpression(Args);
  653. if (TracesToDisplay == 0) {
  654. TracesToDisplay = 4;
  655. }
  656. }
  657. Database = (ULONG64) GetExpression ("NTDLL!RtlpDphTraceDatabaseXP" );
  658. Database = FetchRemotePVOID (Database);
  659. MaximumSize = FETCH_REMOTE_FIELD_PTR(Database, NTDLL!_RTL_TRACE_DATABASE, MaximumSize);
  660. CurrentSize = FETCH_REMOTE_FIELD_PTR(Database, NTDLL!_RTL_TRACE_DATABASE, CurrentSize);
  661. NoOfBuckets = FETCH_REMOTE_FIELD_INT(Database, NTDLL!_RTL_TRACE_DATABASE, NoOfBuckets);
  662. NoOfTraces = FETCH_REMOTE_FIELD_PTR(Database, NTDLL!_RTL_TRACE_DATABASE, NoOfTraces);
  663. NoOfHits = FETCH_REMOTE_FIELD_PTR(Database, NTDLL!_RTL_TRACE_DATABASE, NoOfHits);
  664. PvoidSize = IsPtr64() ? 8 : 4;
  665. dprintf ("MaximumSize: %p \n", MaximumSize);
  666. dprintf ("CurentSize: %p \n", CurrentSize);
  667. dprintf ("NoOfBuckets: %u \n", NoOfBuckets);
  668. dprintf ("NoOfTraces: %p \n", NoOfTraces);
  669. dprintf ("NoOfHits: %p \n", NoOfHits);
  670. //
  671. // Dump hash counters.
  672. //
  673. dprintf ("HashCounters:");
  674. for (I = 0; I < 16; I += 1) {
  675. CHAR FieldName[16];
  676. sprintf (FieldName, "HashCounter[%u]", I);
  677. dprintf (" %u", FetchRemoteULONG (
  678. Database + ReturnFieldOffset("NTDLL!_RTL_TRACE_DATABASE", FieldName)));
  679. }
  680. dprintf ("\n");
  681. if (NoOfTraces < TracesToDisplay) {
  682. TracesToDisplay = NoOfTraces;
  683. }
  684. Trace = (PTRACE) malloc (sizeof(TRACE) * (ULONG)NoOfTraces);
  685. if (Trace == NULL) {
  686. dprintf ("Error: cannot allocate trace database debug structure.\n");
  687. return;
  688. }
  689. //
  690. // Read all the traces from the hash table.
  691. //
  692. for (I = 0, TraceIndex = 0; I < NoOfBuckets; I += 1) {
  693. ULONG64 Current;
  694. Current = FETCH_REMOTE_FIELD_PTR(Database, NTDLL!_RTL_TRACE_DATABASE, Buckets);
  695. Current += I * PvoidSize;
  696. Current = FetchRemotePVOID (Current);
  697. while (Current != 0) {
  698. if (TraceIndex >= NoOfTraces) {
  699. dprintf ("Internal error: TraceIndex >= NoOfTraces \n");
  700. return;
  701. }
  702. Trace[TraceIndex].Address = Current;
  703. Trace[TraceIndex].Count = FETCH_REMOTE_FIELD_PTR (Current, NTDLL!_RTL_TRACE_BLOCK, UserCount);
  704. Trace[TraceIndex].Size = FETCH_REMOTE_FIELD_PTR (Current, NTDLL!_RTL_TRACE_BLOCK, UserSize);
  705. TraceIndex += 1;
  706. Current = FETCH_REMOTE_FIELD_PTR (Current, NTDLL!_RTL_TRACE_BLOCK, Next);
  707. }
  708. }
  709. //
  710. // Sort the traces just read based on Count field.
  711. //
  712. for (I = 0; I < NoOfTraces; I += 1) {
  713. for (J = I, Min = I; J < NoOfTraces; J += 1) {
  714. if (SortByCountField) {
  715. if (Trace[J].Count > Trace[Min].Count) {
  716. Min = J;
  717. }
  718. }
  719. else {
  720. if (Trace[J].Size > Trace[Min].Size) {
  721. Min = J;
  722. }
  723. }
  724. }
  725. if (Min != I) {
  726. ULONG64 Address;
  727. ULONG64 Count;
  728. ULONG64 Size;
  729. Address = Trace[I].Address;
  730. Count = Trace[I].Count;
  731. Size = Trace[I].Size;
  732. Trace[I].Address = Trace[Min].Address;
  733. Trace[I].Count = Trace[Min].Count;
  734. Trace[I].Size = Trace[Min].Size;
  735. Trace[Min].Address = Address;
  736. Trace[Min].Count = Count;
  737. Trace[Min].Size = Size;
  738. }
  739. }
  740. #if 0
  741. for (I = 1; I < NoOfTraces; I += 1) {
  742. if (Trace[I].Size > Trace[I-1].Size) {
  743. dprintf (".");
  744. }
  745. }
  746. #endif
  747. dprintf ("\n");
  748. //
  749. // Print first N
  750. //
  751. for (I = 0; I < TracesToDisplay; I += 1) {
  752. dprintf ("\n");
  753. TraceDatabaseBlockDumpXP (Trace[I].Address);
  754. if (CheckControlC()) {
  755. dprintf ("Interrupted \n");
  756. break;
  757. }
  758. }
  759. dprintf ("\n");
  760. free (Trace);
  761. }
  762. VOID
  763. TraceDatabaseBlockDumpXP (
  764. ULONG64 Address
  765. )
  766. {
  767. ULONG64 TraceAddress;
  768. ULONG64 ReturnAddress;
  769. CHAR SymbolName[ 1024 ];
  770. ULONG64 Displacement;
  771. ULONG I;
  772. ULONG BlockSize;
  773. ULONG PvoidSize;
  774. if (Address == 0) {
  775. dprintf (" No trace\n");
  776. return;
  777. }
  778. PvoidSize = IsPtr64() ? 8 : 4;
  779. BlockSize = FETCH_REMOTE_FIELD_INT(Address, NTDLL!_RTL_TRACE_BLOCK, Size);
  780. dprintf (" Trace @ %p: %p bytes, %u blocks (heap @ %p) \n",
  781. Address,
  782. FETCH_REMOTE_FIELD_PTR(Address, NTDLL!_RTL_TRACE_BLOCK, UserSize),
  783. FETCH_REMOTE_FIELD_PTR(Address, NTDLL!_RTL_TRACE_BLOCK, UserCount),
  784. FETCH_REMOTE_FIELD_PTR(Address, NTDLL!_RTL_TRACE_BLOCK, UserContext));
  785. dprintf (" [%x, %u, %u] \n",
  786. FETCH_REMOTE_FIELD_INT(Address, NTDLL!_RTL_TRACE_BLOCK, Magic),
  787. FETCH_REMOTE_FIELD_INT(Address, NTDLL!_RTL_TRACE_BLOCK, Count),
  788. FETCH_REMOTE_FIELD_INT(Address, NTDLL!_RTL_TRACE_BLOCK, Size));
  789. for (I = 0; I < BlockSize; I += 1) {
  790. TraceAddress = FETCH_REMOTE_FIELD_PTR (Address, NTDLL!_RTL_TRACE_BLOCK, Trace);
  791. ReturnAddress = FetchRemotePVOID (TraceAddress + I * PvoidSize);
  792. GetSymbol (ReturnAddress, SymbolName, &Displacement);
  793. dprintf (" %p %s+0x%p\n",
  794. ReturnAddress,
  795. SymbolName,
  796. Displacement);
  797. }
  798. }
  799. /////////////////////////////////////////////////////////////////////
  800. ////////////////////////////////////////////// Fault injection traces
  801. /////////////////////////////////////////////////////////////////////
  802. VOID
  803. FaultInjectionTracesDumpXP (
  804. PCSTR Args
  805. )
  806. {
  807. ULONG64 TracesToDisplay = 0;
  808. ULONG64 TraceAddress;
  809. ULONG64 IndexAddress;
  810. ULONG Index;
  811. ULONG I;
  812. const ULONG NO_OF_FAULT_INJECTION_TRACES = 128;
  813. ULONG PvoidSize;
  814. ULONG64 TraceBlock;
  815. ULONG TracesFound = 0;
  816. BOOLEAN Interrupted = FALSE;
  817. ULONG64 FlagsAddress;
  818. ULONG Flags;
  819. if (Args) {
  820. TracesToDisplay = GetExpression(Args);
  821. if (TracesToDisplay == 0) {
  822. TracesToDisplay = 4;
  823. }
  824. }
  825. PvoidSize = IsPtr64() ? 8 : 4;
  826. TraceAddress = (ULONG64) GetExpression ("NTDLL!RtlpDphFaultStacks");
  827. IndexAddress = (ULONG64) GetExpression ("NTDLL!RtlpDphFaultStacksIndex");
  828. FlagsAddress = (ULONG64) GetExpression ("NTDLL!RtlpDphGlobalFlags");
  829. Flags = FetchRemoteULONG (FlagsAddress);
  830. if (! (Flags & PAGE_HEAP_USE_FAULT_INJECTION)) {
  831. dprintf ("Fault injection is not enabled for this process. \n");
  832. dprintf ("Use `pageheap /enable PROGRAM /fault RATE' to enable it. \n");
  833. return;
  834. }
  835. Index = FetchRemoteULONG (IndexAddress);
  836. for (I = 0; I < NO_OF_FAULT_INJECTION_TRACES; I += 1) {
  837. Index -= 1;
  838. Index &= (NO_OF_FAULT_INJECTION_TRACES - 1);
  839. TraceBlock = FetchRemotePVOID (TraceAddress + Index * PvoidSize);
  840. if (TraceBlock != 0) {
  841. TracesFound += 1;
  842. dprintf ("\n");
  843. TraceDatabaseBlockDumpXP (TraceBlock);
  844. if (TracesFound >= TracesToDisplay) {
  845. break;
  846. }
  847. }
  848. if (CheckControlC()) {
  849. Interrupted = TRUE;
  850. dprintf ("Interrupted \n");
  851. break;
  852. }
  853. }
  854. if (Interrupted == FALSE && TracesFound == 0) {
  855. dprintf ("No fault injection traces found. \n");
  856. }
  857. }