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.

1149 lines
31 KiB

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