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.

2413 lines
85 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. heap.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. #include "heap.h"
  15. #pragma hdrstop
  16. ULONG PageSize;
  17. //
  18. // Page heap extension function (defined in heappagx.c).
  19. //
  20. VOID
  21. PageHeapExtension(
  22. IN PCSTR lpArgumentString
  23. );
  24. VOID
  25. DebugPageHeapExtensionXP(
  26. IN PCSTR lpArgumentString
  27. );
  28. BOOL
  29. GetPageSize()
  30. {
  31. KDDEBUGGER_DATA64 kdd;
  32. if (GetDebuggerData('GBDK', &kdd, sizeof(kdd))) {
  33. //
  34. // Kernel target
  35. //
  36. PageSize = (ULONG) kdd.MmPageSize;
  37. return TRUE;
  38. } else {
  39. //
  40. // User maode
  41. //
  42. SYSTEM_BASIC_INFORMATION sysInfo;
  43. if (!NtQuerySystemInformation( SystemBasicInformation,
  44. &sysInfo,
  45. sizeof(sysInfo),
  46. NULL)) {
  47. PageSize = sysInfo.PageSize;
  48. return TRUE;
  49. }
  50. }
  51. return FALSE;
  52. }
  53. /*
  54. #if defined(TARGET_i386)
  55. #define STACK_TRACE_DATABASE_SUPPORT 1
  56. #elif defined(TARGET_ALPHA)
  57. #define STACK_TRACE_DATABASE_SUPPORT 0
  58. #elif i386
  59. #define STACK_TRACE_DATABASE_SUPPORT 1
  60. #else
  61. #define STACK_TRACE_DATABASE_SUPPORT 0
  62. #endif
  63. */
  64. #define STACK_TRACE_DATABASE_SUPPORT 0
  65. #if 0
  66. // BUGBUG This was X86 specific := HOST_i386
  67. ULONG
  68. xRtlCompareMemoryUlong(
  69. PVOID Source,
  70. ULONG Length,
  71. ULONG Pattern
  72. )
  73. {
  74. ULONG CountLongs;
  75. PULONG p = (PULONG)Source;
  76. PCHAR p1, p2;
  77. if (((ULONG)p & (sizeof( ULONG )-1)) ||
  78. (Length & (sizeof( ULONG )-1))
  79. ) {
  80. return( 0 );
  81. }
  82. CountLongs = Length / sizeof( ULONG );
  83. while (CountLongs--) {
  84. if (*p++ != Pattern) {
  85. p1 = (PCHAR)(p - 1);
  86. p2 = (PCHAR)&Pattern;
  87. Length = p1 - (PCHAR)Source;
  88. while (*p1++ == *p2++) {
  89. if (p1 > (PCHAR)p) {
  90. break;
  91. }
  92. Length++;
  93. }
  94. }
  95. }
  96. return( Length );
  97. }
  98. #define RtlCompareMemoryUlong xRtlCompareMemoryUlong
  99. #define RtlCompareMemory memcmp
  100. #endif
  101. #define STOP_ON_ALLOC 1
  102. #define STOP_ON_REALLOC 2
  103. #define STOP_ON_FREE 3
  104. typedef struct _HEAP_STOP_ON_TAG {
  105. union {
  106. ULONG HeapAndTagIndex;
  107. struct {
  108. USHORT TagIndex;
  109. USHORT HeapIndex;
  110. };
  111. };
  112. } HEAP_STOP_ON_TAG, *PHEAP_STOP_ON_TAG;
  113. typedef struct _HEAP_STATE {
  114. BOOLEAN ShowHelp;
  115. BOOLEAN ExitDumpLoop;
  116. BOOLEAN ComputeSummary;
  117. BOOLEAN ValidateHeap;
  118. BOOLEAN DumpHeapEntries;
  119. BOOLEAN DumpHeapTags;
  120. BOOLEAN DumpHeapPseudoTags;
  121. BOOLEAN DumpGlobalTags;
  122. BOOLEAN DumpHeapSegments;
  123. BOOLEAN DumpHeapFreeLists;
  124. BOOLEAN DumpStackBackTrace;
  125. BOOLEAN SetStopOnBreakPoint;
  126. BOOLEAN RemoveStopOnBreakPoint;
  127. BOOLEAN EnableHeapChecking;
  128. BOOLEAN EnableHeapValidateOnCall;
  129. BOOLEAN DisableHeapChecking;
  130. BOOLEAN DisableHeapValidateOnCall;
  131. BOOLEAN ToggleAPICallTracing;
  132. ULONG64 HeapToDump;
  133. ULONG64 HeapEntryToDump;
  134. ULONG64 ReservedSize;
  135. ULONG64 CommittedSize;
  136. ULONG64 AllocatedSize;
  137. ULONG64 FreeSize;
  138. ULONG64 OverheadSize;
  139. ULONG NumberOfHeaps;
  140. ULONG HeapIndex;
  141. PULONG64 HeapsList;
  142. ULONG StopOnOperation;
  143. ULONG64 StopOnAddress;
  144. HEAP_STOP_ON_TAG StopOnTag;
  145. WCHAR StopOnTagName[ 24 ];
  146. ULONG FreeListCounts[ HEAP_MAXIMUM_FREELISTS ];
  147. ULONG64 TotalFreeSize;
  148. ULONG64 HeapAddress;
  149. ULONG64 Heap; // HEAP
  150. ULONG SegmentNumber;
  151. ULONG64 SegmentAddress;
  152. ULONG64 Segments[ HEAP_MAXIMUM_SEGMENTS ]; // Ptr to HEAP_SEGMENT
  153. } HEAP_STATE, *PHEAP_STATE;
  154. BOOL
  155. ConvertTagNameToIndex(
  156. IN PHEAP_STATE State
  157. );
  158. BOOL
  159. GetHeapTagEntry(
  160. IN ULONG64 Heap,
  161. IN USHORT TagIndex,
  162. OUT PULONG64 TagEntry
  163. );
  164. VOID
  165. WalkHEAP(
  166. IN PHEAP_STATE State
  167. );
  168. VOID
  169. WalkHEAP_SEGMENT(
  170. IN PHEAP_STATE State
  171. );
  172. BOOL
  173. ValidateHeapHeader(
  174. IN ULONG64 HeapAddress
  175. // IN PHEAP Heap
  176. );
  177. BOOL
  178. ValidateHeapEntry(
  179. IN PHEAP_STATE State,
  180. IN ULONG64 PrevEntryAddress,
  181. IN ULONG64 PrevEntry,
  182. IN ULONG64 EntryAddress,
  183. IN ULONG64 Entry
  184. );
  185. VOID
  186. DumpHeapEntry(
  187. IN PHEAP_STATE State,
  188. IN ULONG64 EntryAddress,
  189. IN ULONG64 Entry
  190. );
  191. #if STACK_TRACE_DATABASE_SUPPORT
  192. VOID
  193. DumpStackBackTraceIndex(
  194. IN PHEAP_STATE State,
  195. IN USHORT BackTraceIndex
  196. );
  197. #endif // STACK_TRACE_DATABASE_SUPPORT
  198. BOOLEAN HeapExtInitialized;
  199. ULONG64 pNtGlobalFlag;
  200. ULONG64 pRtlpHeapInvalidBreakPoint;
  201. ULONG64 pRtlpHeapInvalidBadAddress;
  202. ULONG64 pRtlpGlobalTagHeap;
  203. //HEAP MyLocalRtlpGlobalTagHeap;
  204. #if STACK_TRACE_DATABASE_SUPPORT
  205. ULONG64 pRtlpStackTraceDataBase;// PSTACK_TRACE_DATABASE *
  206. ULONG64 RtlpStackTraceDataBase; // PSTACK_TRACE_DATABASE
  207. STACK_TRACE_DATABASE StackTraceDataBase;
  208. BOOLEAN HaveCopyOfStackTraceDataBase;
  209. #endif // STACK_TRACE_DATABASE_SUPPORT
  210. ULONG64 pRtlpHeapStopOn; // PHEAP_STOP_ON_VALUES
  211. BOOLEAN RtlpHeapInvalidBreakPoint;
  212. ULONG HeapEntryTypeSize = 8;
  213. DECLARE_API( heap )
  214. /*++
  215. Routine Description:
  216. Dump user mode heap (Kernel debugging)
  217. If an address if not given or an address of 0 is given, then the
  218. process heap is dumped. If the address is -1, then all the heaps of
  219. the process are dumped. If detail is specified, it defines how much
  220. detail is shown. A detail of 0, just shows the summary information
  221. for each heap. A detail of 1, shows the summary information, plus
  222. the location and size of all the committed and uncommitted regions.
  223. A detail of 3 shows the allocated and free blocks contained in each
  224. committed region. A detail of 4 includes all of the above plus
  225. a dump of the free lists.
  226. Arguments:
  227. args - [address [detail]]
  228. Return Value:
  229. None
  230. --*/
  231. {
  232. BOOL b, GotHeapsList, ArgumentsSpecified;
  233. ULONG64 pHeapsList;
  234. ULONG PtrSize;
  235. ULONG NtGlobalFlag;
  236. LPSTR p;
  237. ULONG i;
  238. ULONG DashBArgumentState;
  239. ULONG64 AddressToDump;
  240. HEAP_STATE State;
  241. UCHAR ArgumentBuffer[ 16 ];
  242. ULONG TagIndex;
  243. ULONG64 pTagEntry; // PHEAP_TAG_ENTRY
  244. ULONG64 TagEntry; // HEAP_TAG_ENTRY
  245. ULONG64 pPseudoTagEntry; // PHEAP_PSEUDO_TAG_ENTRY
  246. // HEAP_PSEUDO_TAG_ENTRY PseudoTagEntry;
  247. BOOLEAN HeapHeaderModified;
  248. ULONG LocalHeapSignature;
  249. ULONG64 RtlpHeapInvalidBadAddress;
  250. ULONG AlOffset, FlagOffset, TagEntrySize, pseudoTagEntrySize;
  251. ULONG64 AlignRound;
  252. ULONG64 SystemRangeStart = GetExpression("NT!MmSystemRangeStart");
  253. ULONG64 ProcessPeb;
  254. PCSTR Current;
  255. //
  256. // Parse the command line arguments for heap options
  257. // that don't require to building the process heap list
  258. // (i.e pageheap, leak detection, search a block)
  259. //
  260. for (Current = args; *Current != '\0'; Current++) {
  261. if (*Current == '-') {
  262. Current++;
  263. switch (*Current) {
  264. case 'p':
  265. if (g_TargetBuild > 2600)
  266. {
  267. PageHeapExtension( ++Current );
  268. } else
  269. {
  270. DebugPageHeapExtensionXP( ++Current );
  271. }
  272. return S_OK;
  273. case 'l':
  274. case 'L':
  275. HeapDetectLeaks();
  276. return S_OK;
  277. case 'x':
  278. case 'X':
  279. HeapFindBlock( args );
  280. return S_OK;
  281. case 's':
  282. case 'S':
  283. HeapStat(++Current);
  284. return S_OK;
  285. }
  286. }
  287. }
  288. // BUGBUG - not initializing the signature, as we have no local copy
  289. // MyLocalRtlpGlobalTagHeap.Signature = 0;
  290. LocalHeapSignature = 0;
  291. #if STACK_TRACE_DATABASE_SUPPORT
  292. HaveCopyOfStackTraceDataBase = FALSE;
  293. #endif // STACK_TRACE_DATABASE_SUPPORT
  294. memset( &State, 0, FIELD_OFFSET( HEAP_STATE, FreeListCounts ) );
  295. AddressToDump = (ULONG)-1;
  296. ArgumentsSpecified = FALSE;
  297. p = (LPSTR)args;
  298. if (p != NULL)
  299. while (*p) {
  300. if (*p == '-') {
  301. ArgumentsSpecified = TRUE;
  302. p += 1;
  303. while (*p && *p != ' ') {
  304. switch (*p) {
  305. case 'v':
  306. case 'V':
  307. State.ValidateHeap = TRUE;
  308. break;
  309. case 'a':
  310. case 'A':
  311. State.DumpHeapEntries = TRUE;
  312. State.DumpHeapFreeLists = TRUE;
  313. State.DumpHeapSegments = TRUE;
  314. break;
  315. case 'h':
  316. case 'H':
  317. State.DumpHeapEntries = TRUE;
  318. break;
  319. case 'f':
  320. case 'F':
  321. State.DumpHeapFreeLists = TRUE;
  322. break;
  323. case 'm':
  324. case 'M':
  325. State.DumpHeapSegments = TRUE;
  326. break;
  327. case 't':
  328. State.DumpHeapTags = TRUE;
  329. break;
  330. case 'T':
  331. State.DumpHeapPseudoTags = TRUE;
  332. break;
  333. case 'g':
  334. case 'G':
  335. State.DumpGlobalTags = TRUE;
  336. break;
  337. case 'k':
  338. case 'K':
  339. State.DumpStackBackTrace = TRUE;
  340. break;
  341. case 's':
  342. case 'S':
  343. State.ComputeSummary = TRUE;
  344. break;
  345. case 'd':
  346. State.DisableHeapChecking = TRUE;
  347. break;
  348. case 'D':
  349. State.DisableHeapValidateOnCall = TRUE;
  350. break;
  351. case 'e':
  352. State.EnableHeapChecking = TRUE;
  353. break;
  354. case 'E':
  355. State.EnableHeapValidateOnCall = TRUE;
  356. break;
  357. case 'B':
  358. State.RemoveStopOnBreakPoint = TRUE;
  359. DashBArgumentState = 0;
  360. State.StopOnOperation = 0;
  361. State.StopOnAddress = 0;
  362. State.StopOnTag.HeapIndex = 0;
  363. State.StopOnTag.TagIndex = 0;
  364. State.StopOnTagName[ 0 ] = UNICODE_NULL;
  365. break;
  366. case 'b':
  367. State.SetStopOnBreakPoint = TRUE;
  368. DashBArgumentState = 0;
  369. State.StopOnOperation = 0;
  370. State.StopOnAddress = 0;
  371. State.StopOnTag.HeapIndex = 0;
  372. State.StopOnTag.TagIndex = 0;
  373. State.StopOnTagName[ 0 ] = UNICODE_NULL;
  374. break;
  375. default:
  376. dprintf( "HEAPEXT: !heap invalid option flag '-%c'\n", *p );
  377. case '?':
  378. State.ShowHelp = TRUE;
  379. break;
  380. }
  381. p += 1;
  382. }
  383. }
  384. else
  385. if (*p != ' ') {
  386. if (State.SetStopOnBreakPoint) {
  387. switch (DashBArgumentState) {
  388. case 0:
  389. DashBArgumentState += 1;
  390. if (sscanf( p, "%s", ArgumentBuffer ) == 1) {
  391. if (!_stricmp( ArgumentBuffer, "alloc" )) {
  392. State.StopOnOperation = STOP_ON_ALLOC;
  393. }
  394. else
  395. if (!_stricmp( ArgumentBuffer, "realloc" )) {
  396. State.StopOnOperation = STOP_ON_REALLOC;
  397. }
  398. else
  399. if (!_stricmp( ArgumentBuffer, "free" )) {
  400. State.StopOnOperation = STOP_ON_FREE;
  401. }
  402. }
  403. if (State.StopOnOperation == 0) {
  404. dprintf( "HEAPEXT: Invalid first argument to -b switch.\n" );
  405. State.ShowHelp = TRUE;
  406. }
  407. break;
  408. case 1:
  409. if (sscanf( p, "%ws", &State.StopOnTagName ) != 1) {
  410. State.StopOnTagName[ 0 ] = UNICODE_NULL;
  411. dprintf( "HEAPEXT: Invalid second argument to -b switch.\n" );
  412. State.ShowHelp = TRUE;
  413. }
  414. break;
  415. default:
  416. dprintf( "HEAPEXT: Too many parameters specified to -b switch\n" );
  417. State.ShowHelp = TRUE;
  418. break;
  419. }
  420. }
  421. else
  422. if (State.RemoveStopOnBreakPoint) {
  423. switch (DashBArgumentState) {
  424. case 0:
  425. DashBArgumentState += 1;
  426. if (sscanf( p, "%s", ArgumentBuffer ) == 1) {
  427. if (!_stricmp( ArgumentBuffer, "alloc" )) {
  428. State.StopOnOperation = STOP_ON_ALLOC;
  429. }
  430. else
  431. if (!_stricmp( ArgumentBuffer, "realloc" )) {
  432. State.StopOnOperation = STOP_ON_REALLOC;
  433. }
  434. else
  435. if (!_stricmp( ArgumentBuffer, "free" )) {
  436. State.StopOnOperation = STOP_ON_FREE;
  437. }
  438. }
  439. break;
  440. default:
  441. dprintf( "HEAPEXT: Too many parameters specified to -B switch\n" );
  442. State.ShowHelp = TRUE;
  443. break;
  444. }
  445. }
  446. else {
  447. ArgumentsSpecified = TRUE;
  448. AddressToDump = GetExpression(p);
  449. }
  450. if ((p = strpbrk( p, " " )) == NULL) {
  451. p = "";
  452. }
  453. }
  454. else {
  455. p++;
  456. }
  457. }
  458. if (State.ShowHelp) {
  459. dprintf( "usage: !heap [address] [-? ] [-v] [[-a] | [-h] [-f] [-m]] [-t] [-s]\n" );
  460. dprintf( " [-d | -D | -e | -E]\n" );
  461. dprintf( " [-b [alloc | realloc | free] [tag]]\n" );
  462. dprintf( " [-B [alloc | realloc | free]]\n" );
  463. dprintf( " address - specifies either a heap number (1-n), or a heap address.\n" );
  464. dprintf( " Zero specifies all heaps in the process.\n" );
  465. dprintf( " -1 is the default and specifies the process heap.\n" );
  466. dprintf( " -? displays this help message.\n" );
  467. dprintf( " -v validates the specified heap(s).\n" );
  468. dprintf( " -a displays all the information for the specified heap(s).\n" );
  469. dprintf( " This can take a long time.\n" );
  470. dprintf( " -h displays all the entries for the specified heap(s).\n" );
  471. dprintf( " -f displays all the free list entries for the specified heap(s).\n" );
  472. dprintf( " -l detects leaked heap blocks.\n" );
  473. dprintf( " -x search the heap block containing the address.\n" );
  474. dprintf( " -x -v search the whole process virtual space for given address .\n" );
  475. dprintf( " -k displays any associated stack back trace for each entry (x86 only).\n" );
  476. dprintf( " -m displays all the segment entries for the specified heap(s).\n" );
  477. dprintf( " -t displays the tag information for the specified heap(s).\n" );
  478. dprintf( " -T displays the pseudo tag information for the specified heap(s).\n" );
  479. dprintf( " -g displays the global tag information generated by tag by DLL\n" );
  480. dprintf( " -s displays summary information for the specified heap(s).\n" );
  481. dprintf( " -e enables heap checking for the specified heap(s).\n" );
  482. dprintf( " -d disables heap checking for the specified heap(s).\n" );
  483. dprintf( " -E enables validate on call for the specified heap(s).\n" );
  484. dprintf( " -D disables validate on call for the specified heap(s).\n" );
  485. dprintf( " -b creates a conditional breakpoint in the heap manager.\n" );
  486. dprintf( " alloc | realloc | free specifies which action to stop.\n" );
  487. dprintf( " address either specifies the address of a block to stop on.\n" );
  488. dprintf( " or a heap, in which case the tag argument is required,\n" );
  489. dprintf( " and is the tag name within the heap specified by address.\n" );
  490. dprintf( " -B removes a conditional breakpoint in the heap manager.\n" );
  491. dprintf( " if the type is not specified then all breakpoints are removed.\n" );
  492. dprintf (" -p -? extensive page heap related help. \n");
  493. dprintf (" -p Dump all page heaps. \n");
  494. dprintf (" -p -h ADDR Detailed dump of page heap at ADDR. \n");
  495. dprintf (" -p -a ADDR Figure out what heap block is at ADDR. \n");
  496. dprintf (" -p -fi [N] Dump last N fault injection traces.\n");
  497. return S_OK;
  498. }
  499. i = (ULONG)State.EnableHeapChecking + (ULONG)State.EnableHeapValidateOnCall +
  500. (ULONG)State.DisableHeapChecking + (ULONG)State.DisableHeapValidateOnCall +
  501. (ULONG)State.ToggleAPICallTracing;
  502. if (i > 1) {
  503. dprintf( "HEAPEXT: -d, -D, -e and -E flags are mutually exclusive\n" );
  504. return E_INVALIDARG;
  505. }
  506. if (State.SetStopOnBreakPoint || State.RemoveStopOnBreakPoint) {
  507. if (pRtlpHeapStopOn == 0) {
  508. dprintf( "HEAPEXT: Unable to %s heap breakpoint due to missing or invalid NTDLL symbols.\n",
  509. State.SetStopOnBreakPoint ? "set" : "remove"
  510. );
  511. return E_INVALIDARG;
  512. }
  513. if (State.HeapToDump == 0) {
  514. dprintf( "HEAPEXT: Must specify either heap index or heap address to -b command.\n" );
  515. return E_INVALIDARG;
  516. }
  517. }
  518. //
  519. // Ok, so this is a !heap command for NT heap manager.
  520. //
  521. if (!HeapExtInitialized) {
  522. pNtGlobalFlag = GetExpression( "NTDLL!NtGlobalFlag" );
  523. if (pNtGlobalFlag == 0 ||
  524. !ReadMemory( pNtGlobalFlag,
  525. &NtGlobalFlag,
  526. sizeof( NtGlobalFlag ),
  527. NULL ) )
  528. {
  529. dprintf( "HEAPEXT: Unable to get address of NTDLL!NtGlobalFlag.\n" );
  530. return E_INVALIDARG;
  531. }
  532. pRtlpHeapInvalidBreakPoint = GetExpression( "NTDLL!RtlpHeapInvalidBreakPoint" );
  533. if (pRtlpHeapInvalidBreakPoint == 0) {
  534. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpHeapInvalidBreakPoint.\n" );
  535. }
  536. pRtlpHeapInvalidBadAddress = GetExpression( "NTDLL!RtlpHeapInvalidBadAddress" );
  537. if (pRtlpHeapInvalidBadAddress == 0) {
  538. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpHeapInvalidBadAddress.\n" );
  539. }
  540. pRtlpGlobalTagHeap = GetExpression( "NTDLL!RtlpGlobalTagHeap" );
  541. if (pRtlpGlobalTagHeap == 0) {
  542. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpGlobalTagHeap.\n" );
  543. }
  544. if (!ReadPointer( pRtlpGlobalTagHeap,&pRtlpGlobalTagHeap)) {
  545. dprintf( "HEAPEXT: Unable to get address of *NTDLL!RtlpGlobalTagHeap.\n" );
  546. }
  547. pRtlpHeapStopOn = GetExpression( "NTDLL!RtlpHeapStopOn" );
  548. if (pRtlpHeapStopOn == 0) {
  549. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpHeapStopOn\n" );
  550. }
  551. #if STACK_TRACE_DATABASE_SUPPORT
  552. pRtlpStackTraceDataBase = GetExpression( "NTDLL!RtlpStackTraceDataBase" );
  553. if (pRtlpStackTraceDataBase == 0) {
  554. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpStackTraceDataBase\n" );
  555. }
  556. #endif // STACK_TRACE_DATABASE_SUPPORT
  557. HeapExtInitialized = TRUE;
  558. }
  559. if (!GetPageSize()) {
  560. dprintf("Unable to get PageSize.\n");
  561. return E_INVALIDARG;
  562. }
  563. if (!ArgumentsSpecified) {
  564. if ((NtGlobalFlag & (FLG_HEAP_ENABLE_TAIL_CHECK |
  565. FLG_HEAP_ENABLE_FREE_CHECK |
  566. FLG_HEAP_VALIDATE_PARAMETERS |
  567. FLG_HEAP_VALIDATE_ALL |
  568. FLG_HEAP_ENABLE_TAGGING |
  569. FLG_USER_STACK_TRACE_DB |
  570. FLG_HEAP_DISABLE_COALESCING
  571. )
  572. ) != 0
  573. ) {
  574. dprintf( "NtGlobalFlag enables following debugging aids for new heaps:" );
  575. if (NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) {
  576. dprintf( " tail checking\n" );
  577. }
  578. if (NtGlobalFlag & FLG_HEAP_ENABLE_FREE_CHECK) {
  579. dprintf( " free checking\n" );
  580. }
  581. if (NtGlobalFlag & FLG_HEAP_VALIDATE_PARAMETERS) {
  582. dprintf( " validate parameters\n" );
  583. }
  584. if (NtGlobalFlag & FLG_HEAP_VALIDATE_ALL) {
  585. dprintf( " validate on call\n" );
  586. }
  587. if (NtGlobalFlag & FLG_HEAP_ENABLE_TAGGING) {
  588. dprintf( " heap tagging\n" );
  589. }
  590. if (NtGlobalFlag & FLG_USER_STACK_TRACE_DB) {
  591. dprintf( " stack back traces\n" );
  592. }
  593. if (NtGlobalFlag & FLG_HEAP_DISABLE_COALESCING) {
  594. dprintf( " disable coalescing of free blocks\n" );
  595. }
  596. }
  597. }
  598. {
  599. INIT_API();
  600. }
  601. GetPebAddress( 0, &ProcessPeb);
  602. if (AddressToDump == (ULONG64)-1) {
  603. GetFieldValue(ProcessPeb, "nt!_PEB", "ProcessHeaps", AddressToDump);
  604. }
  605. PtrSize = IsPtr64() ? 8 : 4;
  606. HeapEntryTypeSize = GetTypeSize("nt!_HEAP_ENTRY");
  607. GetFieldOffset("nt!_HEAP", "AlignRound", &AlOffset);
  608. GetFieldOffset("nt!_HEAP", "Flags", &FlagOffset);
  609. TagEntrySize = GetTypeSize( "nt!_HEAP_TAG_ENTRY");
  610. pseudoTagEntrySize = GetTypeSize( "nt!_HEAP_PSEUDO_TAG_ENTRY");
  611. GotHeapsList = FALSE;
  612. GetFieldValue(ProcessPeb, "nt!_PEB", "NumberOfHeaps", State.NumberOfHeaps);
  613. GetFieldValue(ProcessPeb, "nt!_PEB", "ProcessHeaps", pHeapsList);
  614. if (State.NumberOfHeaps == 0) {
  615. dprintf( "No heaps to display.\n" );
  616. }
  617. else if (!pHeapsList) {
  618. dprintf( "Unable to get address of ProcessHeaps array\n" );
  619. }
  620. else {
  621. State.HeapsList = malloc( State.NumberOfHeaps * sizeof(ULONG64) ); // To Keep PHEAP
  622. if (State.HeapsList == NULL) {
  623. dprintf( "Unable to allocate memory to hold ProcessHeaps array\n" );
  624. }
  625. else {
  626. ULONG iHeap;
  627. //
  628. // Read the array of heap pointers
  629. //
  630. GotHeapsList = TRUE;
  631. for (iHeap=0;iHeap<State.NumberOfHeaps; iHeap++) {
  632. if (!ReadPointer( pHeapsList + iHeap*PtrSize,
  633. &State.HeapsList[iHeap] )
  634. ) {
  635. dprintf( "%08p: Unable to read ProcessHeaps array\n", pHeapsList );
  636. GotHeapsList = FALSE ;
  637. break;
  638. }
  639. }
  640. }
  641. }
  642. if (GotHeapsList) {
  643. retryArgs:
  644. if (!ArgumentsSpecified) {
  645. if (pRtlpHeapInvalidBreakPoint != 0) {
  646. b = ReadMemory( pRtlpHeapInvalidBreakPoint,
  647. &RtlpHeapInvalidBreakPoint,
  648. sizeof( RtlpHeapInvalidBreakPoint ),
  649. NULL
  650. );
  651. if (b && RtlpHeapInvalidBreakPoint) {
  652. RtlpHeapInvalidBadAddress = 0;
  653. if (pRtlpHeapInvalidBadAddress != 0) {
  654. b = ReadPointer(pRtlpHeapInvalidBadAddress,
  655. &RtlpHeapInvalidBadAddress);
  656. if (b) {
  657. AddressToDump = RtlpHeapInvalidBadAddress;
  658. }
  659. }
  660. dprintf( "Stop inside heap manager...validating heap address 0x%p\n", AddressToDump );
  661. State.ValidateHeap = TRUE;
  662. State.DumpStackBackTrace = TRUE;
  663. ArgumentsSpecified = TRUE;
  664. goto retryArgs;
  665. }
  666. }
  667. }
  668. else
  669. if (AddressToDump != 0) {
  670. for (State.HeapIndex=0;
  671. State.HeapIndex<State.NumberOfHeaps;
  672. State.HeapIndex++
  673. ) {
  674. if (AddressToDump-1 == State.HeapIndex ||
  675. AddressToDump == State.HeapsList[ State.HeapIndex ]
  676. ) {
  677. State.HeapToDump = State.HeapsList[ State.HeapIndex ];
  678. break;
  679. }
  680. }
  681. if (State.HeapToDump == 0) {
  682. if (AddressToDump >= SystemRangeStart) {
  683. State.HeapToDump = AddressToDump;
  684. }
  685. else {
  686. State.HeapToDump = (ULONG64)-1;
  687. }
  688. }
  689. }
  690. State.HeapIndex = 0;
  691. }
  692. else {
  693. if (!ArgumentsSpecified || AddressToDump < 0x10000) {
  694. dprintf( "You must specify the actual heap address since\n" );
  695. dprintf( "array of process heaps is inaccessable\n" );
  696. State.ExitDumpLoop = TRUE;
  697. }
  698. else {
  699. State.HeapToDump = AddressToDump;
  700. }
  701. }
  702. if (State.DumpGlobalTags) {
  703. dprintf( "Global Tags defined for each DLL that makes an untagged allocation.\n" );
  704. if (LocalHeapSignature != HEAP_SIGNATURE) {
  705. b = GetFieldValue( pRtlpGlobalTagHeap,
  706. "nt!_HEAP",
  707. "Signature",
  708. LocalHeapSignature);
  709. if (b) {
  710. dprintf( "HEAPEXT: Unable to read RtlpGlobalTagHeap\n" );
  711. if (State.HeapsList != NULL) {
  712. free( State.HeapsList );
  713. }
  714. EXIT_API();
  715. return E_INVALIDARG;
  716. }
  717. }
  718. GetFieldValue(pRtlpGlobalTagHeap, "nt!_HEAP", "TagEntries", pTagEntry);
  719. if (pTagEntry == 0) {
  720. dprintf( " no global tags currently defined.\n" );
  721. }
  722. else {
  723. ULONG NextAvailableTagIndex;
  724. GetFieldValue(pRtlpGlobalTagHeap, "nt!_HEAP", "NextAvailableTagIndex", NextAvailableTagIndex);
  725. dprintf( " Tag Name Allocs Frees Diff Allocated\n" );
  726. for (TagIndex=1; TagIndex<NextAvailableTagIndex; TagIndex++) {
  727. pTagEntry += TagEntrySize;
  728. b = (BOOL) InitTypeRead( pTagEntry, nt!_HEAP_TAG_ENTRY);
  729. if (b) {
  730. dprintf( "%04x: unable to read nt!_HEAP_TAG_ENTRY at %p\n", TagIndex, pTagEntry );
  731. break;
  732. }
  733. else
  734. if ((ULONG)ReadField(Allocs) != 0 ||
  735. (ULONG)ReadField(Frees) != 0 ||
  736. (ULONG)ReadField(Size) != 0
  737. )
  738. {
  739. WCHAR TagName[50];
  740. GetFieldValue(pTagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  741. dprintf( "%04x: %-20.20ws %8d %8d %6d %8d\n",
  742. (ULONG)ReadField(TagIndex),
  743. TagName,
  744. (ULONG)ReadField(Allocs),
  745. (ULONG)ReadField(Frees),
  746. (ULONG)ReadField(Allocs) - (ULONG)ReadField(Frees),
  747. (ULONG)ReadField(Size) << HEAP_GRANULARITY_SHIFT
  748. );
  749. }
  750. }
  751. }
  752. }
  753. //
  754. // Walk the list of heaps
  755. //
  756. while (!State.ExitDumpLoop &&
  757. !CheckControlC() &&
  758. (!GotHeapsList || (State.HeapIndex < State.NumberOfHeaps ))
  759. ) {
  760. ULONG Flags;
  761. WCHAR TagName[ 24 ];
  762. memset( &State.FreeListCounts, 0, sizeof( State.FreeListCounts ) );
  763. State.TotalFreeSize = 0;
  764. if (!GotHeapsList) {
  765. State.HeapAddress = State.HeapToDump;
  766. State.ExitDumpLoop = TRUE;
  767. }
  768. else {
  769. State.HeapAddress = State.HeapsList[ State.HeapIndex ];
  770. }
  771. State.Heap = State.HeapAddress;
  772. b = (BOOL) InitTypeRead( (State.HeapAddress), nt!_HEAP);
  773. if (State.HeapIndex == 0) {
  774. dprintf( "Index Address Name Debugging options enabled\n" );
  775. }
  776. dprintf( "%3u: %08p ", State.HeapIndex + 1, State.HeapAddress );
  777. Flags = (ULONG) ReadField(Flags);
  778. if (b) {
  779. dprintf( " - heap headers inaccessable, skipping\n" );
  780. }
  781. else
  782. if (!ArgumentsSpecified) {
  783. if (!GetHeapTagEntry( State.HeapAddress, 0, &TagEntry )) {
  784. TagName[ 0 ] = UNICODE_NULL;
  785. } else {
  786. GetFieldValue(TagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  787. }
  788. dprintf( " %-14.14ws", TagName );
  789. if (Flags & HEAP_TAIL_CHECKING_ENABLED) {
  790. dprintf( " tail checking" );
  791. }
  792. if (Flags & HEAP_FREE_CHECKING_ENABLED) {
  793. dprintf( " free checking" );
  794. }
  795. if (Flags & HEAP_VALIDATE_PARAMETERS_ENABLED) {
  796. dprintf( " validate parameters" );
  797. }
  798. if (Flags & HEAP_VALIDATE_ALL_ENABLED) {
  799. dprintf( " validate on call" );
  800. }
  801. dprintf( "\n" );
  802. }
  803. else
  804. if (State.HeapAddress == State.HeapToDump ||
  805. State.HeapToDump == 0 ||
  806. State.HeapToDump == (ULONG64)-1
  807. ) {
  808. ULONG Off;
  809. ULONG64 LastValidEntry;
  810. GetFieldOffset("nt!_HEAP", "Segments", &Off);
  811. dprintf( "\n" );
  812. for (i=0; i<HEAP_MAXIMUM_SEGMENTS; i++) {
  813. ReadPointer(State.HeapAddress + Off + i*PtrSize,
  814. &State.Segments[i]);
  815. if (State.Segments[ i ] != 0) {
  816. b = (BOOL) InitTypeRead(State.Segments[ i ], nt!_HEAP_SEGMENT);
  817. if (b) {
  818. dprintf( " Unable to read _HEAP_SEGMENT structure at %p\n", State.Segments[ i ] );
  819. }
  820. else {
  821. LastValidEntry = ReadField(LastValidEntry);
  822. dprintf( " Segment at %p to %p (%08x bytes committed)\n",
  823. i == 0 ? State.HeapAddress : State.Segments[ i ],
  824. LastValidEntry,
  825. (LastValidEntry -
  826. (i == 0 ? State.HeapAddress : State.Segments[ i ])-
  827. (ReadField(NumberOfUnCommittedPages) * PageSize)
  828. ));
  829. if (State.HeapToDump == (ULONG)-1) {
  830. if (AddressToDump >= State.Segments[ i ] &&
  831. AddressToDump < LastValidEntry
  832. ) {
  833. State.HeapToDump = State.HeapAddress;
  834. if (State.SetStopOnBreakPoint || State.RemoveStopOnBreakPoint) {
  835. State.StopOnAddress = AddressToDump;
  836. }
  837. else {
  838. State.HeapEntryToDump = AddressToDump;
  839. }
  840. }
  841. }
  842. }
  843. }
  844. }
  845. if (State.HeapToDump == (ULONG64)-1) {
  846. State.HeapIndex += 1;
  847. continue;
  848. }
  849. if (State.SetStopOnBreakPoint || State.RemoveStopOnBreakPoint) {
  850. ULONG64 pul;
  851. ULONG AllocOff;
  852. PSTR TypeHSOV = "nt!_HEAP_STOP_ON_VALUES";
  853. switch( State.StopOnOperation) {
  854. case STOP_ON_ALLOC:
  855. if (State.StopOnTagName[0] == UNICODE_NULL) {
  856. GetFieldOffset(TypeHSOV,"AllocAddress", &AllocOff);
  857. pul = pRtlpHeapStopOn + AllocOff;;
  858. }
  859. else {
  860. GetFieldOffset(TypeHSOV,"AllocTag.HeapAndTagIndex", &AllocOff);
  861. pul = pRtlpHeapStopOn + AllocOff;;
  862. }
  863. break;
  864. case STOP_ON_REALLOC:
  865. if (State.StopOnTagName[0] == UNICODE_NULL) {
  866. GetFieldOffset(TypeHSOV,"ReAllocAddress", &AllocOff);
  867. pul = pRtlpHeapStopOn + AllocOff;;
  868. }
  869. else {
  870. GetFieldOffset(TypeHSOV,"ReAllocTag.HeapAndTagIndex", &AllocOff);
  871. pul = pRtlpHeapStopOn + AllocOff;;
  872. }
  873. break;
  874. case STOP_ON_FREE:
  875. if (State.StopOnTagName[0] == UNICODE_NULL) {
  876. GetFieldOffset(TypeHSOV,"FreeAddress", &AllocOff);
  877. pul = pRtlpHeapStopOn + AllocOff;;
  878. }
  879. else {
  880. GetFieldOffset(TypeHSOV,"FreeTag.HeapAndTagIndex", &AllocOff);
  881. pul = pRtlpHeapStopOn + AllocOff;;
  882. }
  883. break;
  884. default:
  885. pul = 0;
  886. break;
  887. }
  888. if (pul != 0) {
  889. if (State.StopOnTagName[0] == UNICODE_NULL) {
  890. if (State.RemoveStopOnBreakPoint) {
  891. State.StopOnAddress = 0;
  892. }
  893. b = WriteMemory( pul,
  894. &State.StopOnAddress,
  895. PtrSize,
  896. NULL
  897. );
  898. }
  899. else {
  900. if (!ConvertTagNameToIndex( &State )) {
  901. dprintf( "HEAPEXT: Unable to convert tag name %ws to an index\n", State.StopOnTagName );
  902. b = TRUE;
  903. }
  904. else {
  905. b = WriteMemory( pul,
  906. &State.StopOnTag.HeapAndTagIndex,
  907. sizeof( State.StopOnTag.HeapAndTagIndex ),
  908. NULL
  909. );
  910. }
  911. }
  912. if (!b) {
  913. dprintf( "HEAPEXT: Unable to set heap breakpoint - write memory to %x failed\n", pul );
  914. }
  915. else {
  916. if (State.SetStopOnBreakPoint) {
  917. if (State.StopOnTagName[0] == UNICODE_NULL) {
  918. dprintf( "HEAPEXT: Enabled heap breakpoint for %s of block %x\n",
  919. State.StopOnOperation == STOP_ON_ALLOC ? "Alloc" :
  920. State.StopOnOperation == STOP_ON_REALLOC ? "ReAlloc" :
  921. "Free",
  922. State.StopOnAddress
  923. );
  924. }
  925. else {
  926. dprintf( "HEAPEXT: Enabled heap breakpoint for %s of block with tag %ws\n",
  927. State.StopOnOperation == STOP_ON_ALLOC ? "Alloc" :
  928. State.StopOnOperation == STOP_ON_REALLOC ? "ReAlloc" :
  929. "Free",
  930. State.StopOnTagName
  931. );
  932. }
  933. }
  934. else {
  935. dprintf( "HEAPEXT: Disabled heap breakpoint for %s\n",
  936. State.StopOnOperation == STOP_ON_ALLOC ? "Alloc" :
  937. State.StopOnOperation == STOP_ON_REALLOC ? "ReAlloc" :
  938. "Free"
  939. );
  940. }
  941. }
  942. }
  943. }
  944. if (State.ValidateHeap) {
  945. ValidateHeapHeader( State.HeapAddress );
  946. }
  947. HeapHeaderModified = FALSE;
  948. GetFieldValue(State.HeapAddress, "nt!_HEAP", "AlignRound", AlignRound);
  949. if (State.EnableHeapChecking || State.EnableHeapValidateOnCall) {
  950. if (!(Flags & HEAP_TAIL_CHECKING_ENABLED)) {
  951. AlignRound += CHECK_HEAP_TAIL_SIZE;
  952. b = WriteMemory( (State.HeapAddress + AlOffset),
  953. &AlignRound,
  954. sizeof( AlignRound ),
  955. NULL
  956. );
  957. }
  958. else {
  959. b = TRUE;
  960. }
  961. if (b) {
  962. HeapHeaderModified = TRUE;
  963. Flags |= HEAP_VALIDATE_PARAMETERS_ENABLED |
  964. HEAP_TAIL_CHECKING_ENABLED |
  965. HEAP_FREE_CHECKING_ENABLED;
  966. if (State.EnableHeapValidateOnCall) {
  967. Flags |= HEAP_VALIDATE_ALL_ENABLED;
  968. }
  969. b = WriteMemory( (State.HeapAddress + FlagOffset),
  970. (LPCVOID)&Flags,
  971. sizeof( Flags ),
  972. NULL
  973. );
  974. }
  975. if (!b) {
  976. dprintf( "HEAPEXT: Unable to enable heap checking for heap %p\n", State.HeapAddress );
  977. InitTypeRead( (State.HeapAddress), nt!_HEAP);
  978. }
  979. else {
  980. if (State.EnableHeapValidateOnCall) {
  981. dprintf( "HEAPEXT: Enabled validate on call heap checking for heap %p\n", State.HeapAddress );
  982. }
  983. else {
  984. dprintf( "HEAPEXT: Enabled heap checking for heap %p\n", State.HeapAddress );
  985. }
  986. }
  987. }
  988. else
  989. if (State.DisableHeapChecking || State.DisableHeapValidateOnCall) {
  990. if (State.DisableHeapValidateOnCall) {
  991. if (Flags & HEAP_VALIDATE_ALL_ENABLED) {
  992. Flags &= ~HEAP_VALIDATE_ALL_ENABLED;
  993. b = WriteMemory( State.HeapAddress + FlagOffset,
  994. (LPCVOID)&Flags,
  995. sizeof( Flags ),
  996. NULL
  997. );
  998. }
  999. else {
  1000. b = TRUE;
  1001. }
  1002. }
  1003. else {
  1004. if (Flags & HEAP_TAIL_CHECKING_ENABLED) {
  1005. HeapHeaderModified = TRUE;
  1006. AlignRound -= CHECK_HEAP_TAIL_SIZE;
  1007. b = WriteMemory( State.HeapAddress + AlOffset,
  1008. (LPCVOID)&AlignRound,
  1009. sizeof( AlignRound ),
  1010. NULL
  1011. );
  1012. }
  1013. else {
  1014. b = TRUE;
  1015. }
  1016. if (b) {
  1017. Flags &= ~(HEAP_VALIDATE_PARAMETERS_ENABLED |
  1018. HEAP_VALIDATE_ALL_ENABLED |
  1019. HEAP_TAIL_CHECKING_ENABLED |
  1020. HEAP_FREE_CHECKING_ENABLED
  1021. );
  1022. b = WriteMemory( State.HeapAddress + FlagOffset,
  1023. (LPCVOID)&Flags,
  1024. sizeof( Flags ),
  1025. NULL
  1026. );
  1027. }
  1028. }
  1029. if (!b) {
  1030. dprintf( "HEAPEXT: Unable to disable heap checking for heap %p\n", State.HeapAddress );
  1031. InitTypeRead( (State.HeapAddress), nt!_HEAP);
  1032. }
  1033. else {
  1034. if (State.DisableHeapValidateOnCall) {
  1035. dprintf( "HEAPEXT: Disabled validate on call heap checking for heap %p\n", State.HeapAddress );
  1036. }
  1037. else {
  1038. dprintf( "HEAPEXT: Disabled heap checking for heap %p\n", State.HeapAddress );
  1039. }
  1040. }
  1041. }
  1042. else
  1043. if (State.ToggleAPICallTracing) {
  1044. Flags ^= HEAP_CREATE_ENABLE_TRACING;
  1045. b = WriteMemory( State.HeapAddress + FlagOffset,
  1046. (LPCVOID)&Flags,
  1047. sizeof( Flags ),
  1048. NULL
  1049. );
  1050. if (!b) {
  1051. dprintf( "HEAPEXT: Unable to toggle API call tracing for heap %p\n", State.HeapAddress );
  1052. InitTypeRead( (State.HeapAddress), nt!_HEAP);
  1053. }
  1054. else {
  1055. HeapHeaderModified = TRUE;
  1056. if (Flags & HEAP_CREATE_ENABLE_TRACING) {
  1057. dprintf( "HEAPEXT: Enabled API call tracing for heap %p\n", State.HeapAddress );
  1058. }
  1059. else {
  1060. dprintf( "HEAPEXT: Disabled API call tracing for heap %p\n", State.HeapAddress );
  1061. }
  1062. }
  1063. }
  1064. else
  1065. if (State.DumpHeapTags) {
  1066. GetFieldValue(State.HeapAddress, "nt!_HEAP", "TagEntries", pTagEntry);
  1067. if (pTagEntry == 0) {
  1068. dprintf( " no tags currently defined for this heap.\n" );
  1069. }
  1070. else {
  1071. ULONG NextAvailableTagIndex;
  1072. GetFieldValue(State.HeapAddress, "nt!_HEAP", "NextAvailableTagIndex", NextAvailableTagIndex);
  1073. dprintf( " Tag Name Allocs Frees Diff Allocated\n" );
  1074. for (TagIndex=1; TagIndex<NextAvailableTagIndex; TagIndex++) {
  1075. pTagEntry += TagEntrySize;
  1076. b = (BOOL) InitTypeRead( pTagEntry, nt!_HEAP_TAG_ENTRY);
  1077. if (b) {
  1078. dprintf( "%04x: unable to read nt!_HEAP_TAG_ENTRY at %p\n", TagIndex, pTagEntry );
  1079. }
  1080. else
  1081. if ((ULONG)ReadField(Allocs) != 0 ||
  1082. (ULONG)ReadField(Frees) != 0 ||
  1083. (ULONG)ReadField(Size) != 0
  1084. ) {
  1085. GetFieldValue(pTagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  1086. dprintf( "%04x: %-20.20ws %8d %8d %6d %8d\n",
  1087. (ULONG)ReadField(TagIndex),
  1088. TagName,
  1089. (ULONG)ReadField(Allocs),
  1090. (ULONG)ReadField(Frees),
  1091. (ULONG)ReadField(Allocs) - (ULONG)ReadField(Frees),
  1092. (ULONG)ReadField(Size) << HEAP_GRANULARITY_SHIFT
  1093. );
  1094. }
  1095. }
  1096. }
  1097. }
  1098. else
  1099. if (State.DumpHeapPseudoTags) {
  1100. GetFieldValue(State.HeapAddress, "nt!_HEAP", "PseudoTagEntries", pPseudoTagEntry);
  1101. if (pPseudoTagEntry == 0) {
  1102. dprintf( " no pseudo tags currently defined for this heap.\n" );
  1103. }
  1104. else {
  1105. dprintf( " Tag Name Allocs Frees Diff Allocated\n" );
  1106. for (TagIndex=1; TagIndex<HEAP_NUMBER_OF_PSEUDO_TAG; TagIndex++) {
  1107. pPseudoTagEntry += pseudoTagEntrySize;
  1108. b = (BOOL) InitTypeRead( pPseudoTagEntry, nt!_HEAP_PSEUDO_TAG_ENTRY);
  1109. if (b) {
  1110. dprintf( "%04x: unable to read HEAP_PSEUDO_TAG_ENTRY at %p\n", TagIndex, pPseudoTagEntry );
  1111. }
  1112. else
  1113. if ((ULONG)ReadField(Allocs) != 0 ||
  1114. (ULONG)ReadField(Frees) != 0 ||
  1115. (ULONG)ReadField(Size) != 0
  1116. ) {
  1117. if (TagIndex == 0) {
  1118. dprintf( "%04x: Objects>%4u",
  1119. TagIndex | HEAP_PSEUDO_TAG_FLAG,
  1120. HEAP_MAXIMUM_FREELISTS << HEAP_GRANULARITY_SHIFT
  1121. );
  1122. }
  1123. else
  1124. if (TagIndex < HEAP_MAXIMUM_FREELISTS) {
  1125. dprintf( "%04x: Objects=%4u",
  1126. TagIndex | HEAP_PSEUDO_TAG_FLAG,
  1127. TagIndex << HEAP_GRANULARITY_SHIFT
  1128. );
  1129. }
  1130. else {
  1131. dprintf( "%04x: VirtualAlloc", TagIndex | HEAP_PSEUDO_TAG_FLAG );
  1132. }
  1133. dprintf( " %8d %8d %6d %8d\n",
  1134. (ULONG)ReadField(Allocs),
  1135. (ULONG)ReadField(Frees),
  1136. (ULONG)ReadField(Allocs) - (ULONG)ReadField(Frees),
  1137. (ULONG)ReadField(Size) << HEAP_GRANULARITY_SHIFT
  1138. );
  1139. }
  1140. }
  1141. }
  1142. }
  1143. // BUGBUG - Cannot write whole struct - change to write specific fields only
  1144. //
  1145. /*
  1146. if (HeapHeaderModified && (State.Heap.HeaderValidateCopy != NULL)) {
  1147. b = WriteMemory( (ULONG_PTR)State.Heap.HeaderValidateCopy,
  1148. &State.Heap,
  1149. sizeof( State.Heap ),
  1150. NULL
  1151. );
  1152. if (!b) {
  1153. dprintf( "HEAPEXT: Unable to update header validation copy at %p\n", State.Heap.HeaderValidateCopy );
  1154. }
  1155. }*/
  1156. if (State.HeapEntryToDump != 0 ||
  1157. State.DumpHeapEntries ||
  1158. State.DumpHeapSegments ||
  1159. State.DumpHeapFreeLists
  1160. ) {
  1161. WalkHEAP( &State );
  1162. }
  1163. }
  1164. else {
  1165. dprintf( "\n" );
  1166. }
  1167. State.HeapIndex += 1;
  1168. }
  1169. if (State.HeapsList != NULL) {
  1170. free( State.HeapsList );
  1171. }
  1172. EXIT_API();
  1173. return S_OK;
  1174. }
  1175. BOOL
  1176. ConvertTagNameToIndex(
  1177. IN PHEAP_STATE State
  1178. )
  1179. {
  1180. ULONG TagIndex;
  1181. ULONG64 pTagEntry; // PHEAP_TAG_ENTRY
  1182. ULONG64 pPseudoTagEntry;
  1183. BOOL b;
  1184. PWSTR s;
  1185. WCHAR TagName[ 24 ];
  1186. ULONG NextAvailableTagIndex, TagEntrySize;
  1187. if (State->RemoveStopOnBreakPoint) {
  1188. State->StopOnTag.HeapAndTagIndex = 0;
  1189. return TRUE;
  1190. }
  1191. if (!_wcsnicmp( State->StopOnTagName, L"Objects", 7 )) {
  1192. GetFieldValue(State->Heap, "nt!_HEAP", "PseudoTagEntries", pPseudoTagEntry);
  1193. if (pPseudoTagEntry == 0) {
  1194. return FALSE;
  1195. }
  1196. s = &State->StopOnTagName[ 7 ];
  1197. if (*s == L'>') {
  1198. GetFieldValue(State->Heap, "nt!_HEAP", "ProcessHeapsListIndex", State->StopOnTag.HeapIndex);
  1199. State->StopOnTag.TagIndex = HEAP_PSEUDO_TAG_FLAG;
  1200. return TRUE;
  1201. }
  1202. else
  1203. if (*s == L'=') {
  1204. while (*++s == L' ') ;
  1205. State->StopOnTag.TagIndex = (USHORT)_wtoi( s );
  1206. if (State->StopOnTag.TagIndex > 0 &&
  1207. State->StopOnTag.TagIndex < (HEAP_MAXIMUM_FREELISTS >> HEAP_GRANULARITY_SHIFT)
  1208. ) {
  1209. GetFieldValue(State->Heap, "nt!_HEAP", "ProcessHeapsListIndex", State->StopOnTag.HeapIndex);
  1210. State->StopOnTag.TagIndex = (State->StopOnTag.TagIndex >> HEAP_GRANULARITY_SHIFT) |
  1211. HEAP_PSEUDO_TAG_FLAG;
  1212. return TRUE;
  1213. }
  1214. }
  1215. }
  1216. GetFieldValue(State->Heap, "nt!_HEAP", "TagEntries", pTagEntry);
  1217. if (pTagEntry == 0) {
  1218. return FALSE;
  1219. }
  1220. GetFieldValue(State->HeapAddress, "nt!_HEAP", "NextAvailableTagIndex", NextAvailableTagIndex);
  1221. TagEntrySize = GetTypeSize("nt!_HEAP_TAG_ENTRY");
  1222. for (TagIndex=1; TagIndex<NextAvailableTagIndex; TagIndex++) {
  1223. pTagEntry += TagEntrySize;
  1224. b = GetFieldValue( pTagEntry,"nt!_HEAP_TAG_ENTRY","TagName",TagName);
  1225. if (!b && !_wcsicmp( State->StopOnTagName, TagName )) {
  1226. GetFieldValue( pTagEntry,"nt!_HEAP_TAG_ENTRY","TagIndex",State->StopOnTag.TagIndex);
  1227. return TRUE;
  1228. }
  1229. }
  1230. return FALSE;
  1231. }
  1232. BOOL
  1233. GetHeapTagEntry(
  1234. IN ULONG64 Heap,
  1235. IN USHORT TagIndex,
  1236. OUT PULONG64 TagEntry
  1237. )
  1238. {
  1239. BOOL b;
  1240. ULONG64 pTagEntries;// PHEAP_TAG_ENTRY
  1241. ULONG NextAvailableTagIndex;
  1242. ULONG64 pPseudoTagEntries; // PHEAP_PSEUDO_TAG_ENTRY
  1243. b = FALSE;
  1244. if (TagIndex & HEAP_PSEUDO_TAG_FLAG) {
  1245. TagIndex &= ~HEAP_PSEUDO_TAG_FLAG;
  1246. GetFieldValue(Heap, "nt!_HEAP", "PseudoTagEntries", pPseudoTagEntries);
  1247. if (pPseudoTagEntries == 0) {
  1248. return FALSE;
  1249. }
  1250. // BUGBUG - Cannot copy name
  1251. /*
  1252. if (TagIndex == 0) {
  1253. swprintf( TagEntry->TagName, L"Objects>%4u",
  1254. HEAP_MAXIMUM_FREELISTS << HEAP_GRANULARITY_SHIFT
  1255. );
  1256. }
  1257. else
  1258. if (TagIndex < HEAP_MAXIMUM_FREELISTS) {
  1259. swprintf( TagEntry->TagName, L"Objects=%4u", TagIndex << HEAP_GRANULARITY_SHIFT );
  1260. }
  1261. else {
  1262. swprintf( TagEntry->TagName, L"VirtualAlloc" );
  1263. }
  1264. TagEntry->TagIndex = TagIndex;
  1265. TagEntry->CreatorBackTraceIndex = 0;*/
  1266. *TagEntry = pPseudoTagEntries + TagIndex * GetTypeSize("nt!_HEAP_PSEUDO_TAG_ENTRY");
  1267. b = !InitTypeRead(*TagEntry, nt!_HEAP_TAG_ENTRY);
  1268. }
  1269. else
  1270. if (TagIndex & HEAP_GLOBAL_TAG) {
  1271. if (GetFieldValue(pRtlpGlobalTagHeap, "nt!_HEAP", "NextAvailableTagIndex",NextAvailableTagIndex)) {
  1272. return FALSE;
  1273. }
  1274. TagIndex &= ~HEAP_GLOBAL_TAG;
  1275. if (TagIndex < NextAvailableTagIndex) {
  1276. GetFieldValue(pRtlpGlobalTagHeap, "nt!_HEAP", "TagEntries", pTagEntries);
  1277. if (pTagEntries == 0) {
  1278. return FALSE;
  1279. }
  1280. *TagEntry = pTagEntries;
  1281. b = ! (BOOL) InitTypeRead(pTagEntries, nt!_HEAP_TAG_ENTRY);
  1282. }
  1283. }
  1284. else {
  1285. if (GetFieldValue(Heap, "nt!_HEAP", "NextAvailableTagIndex",NextAvailableTagIndex)) {
  1286. return FALSE;
  1287. }
  1288. if (TagIndex < NextAvailableTagIndex) {
  1289. GetFieldValue(Heap, "nt!_HEAP", "TagEntries", pTagEntries);
  1290. if (pTagEntries == 0) {
  1291. return FALSE;
  1292. }
  1293. *TagEntry = pTagEntries;
  1294. b = ! (BOOL) InitTypeRead(pTagEntries, nt!_HEAP_TAG_ENTRY);
  1295. }
  1296. }
  1297. return b;
  1298. }
  1299. VOID
  1300. WalkHEAP(
  1301. IN PHEAP_STATE State
  1302. )
  1303. {
  1304. BOOL b;
  1305. ULONG64 FreeListHead;
  1306. ULONG i;
  1307. ULONG64 Head, Next;
  1308. // HEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocEntry;
  1309. ULONG64 TagEntry; // HEAP_TAG_ENTRY
  1310. ULONG64 FreeEntryAddress;
  1311. ULONG64 FreeEntry; // HEAP_FREE_ENTRY
  1312. ULONG64 UCRSegment, UnusedUnCommittedRanges;
  1313. ULONG64 CapturedUCRSegment; // HEAP_UCR_SEGMENT
  1314. ULONG AlignRound, Offset, ListSize, FreeListOffset;
  1315. GetFieldOffset("nt!_HEAP", "VirtualAllocdBlocks", &Offset);
  1316. if (InitTypeRead(State->HeapAddress, nt!_HEAP)) {
  1317. return;
  1318. }
  1319. AlignRound = (ULONG)ReadField(AlignRound) - GetTypeSize( "nt!_HEAP_ENTRY" );
  1320. if ((ULONG)ReadField(Flags) & HEAP_TAIL_CHECKING_ENABLED) {
  1321. AlignRound -= CHECK_HEAP_TAIL_SIZE;
  1322. }
  1323. dprintf( " Flags: %08x\n", (ULONG)ReadField(Flags) );
  1324. dprintf( " ForceFlags: %08x\n", (ULONG)ReadField(ForceFlags) );
  1325. dprintf( " Granularity: %u bytes\n", AlignRound + 1 );
  1326. dprintf( " Segment Reserve: %08x\n", (ULONG)ReadField(SegmentReserve) );
  1327. dprintf( " Segment Commit: %08x\n", (ULONG)ReadField(SegmentCommit) );
  1328. dprintf( " DeCommit Block Thres:%08x\n", (ULONG)ReadField(DeCommitFreeBlockThreshold) );
  1329. dprintf( " DeCommit Total Thres:%08x\n", (ULONG)ReadField(DeCommitTotalFreeThreshold) );
  1330. dprintf( " Total Free Size: %08x\n", (ULONG)ReadField(TotalFreeSize) );
  1331. dprintf( " Max. Allocation Size:%08x\n", (ULONG)ReadField(MaximumAllocationSize) );
  1332. dprintf( " Lock Variable at: %08x\n", (ULONG)ReadField(LockVariable) );
  1333. dprintf( " Next TagIndex: %04x\n", (ULONG)ReadField(NextAvailableTagIndex) );
  1334. dprintf( " Maximum TagIndex: %04x\n", (ULONG)ReadField(MaximumTagIndex) );
  1335. dprintf( " Tag Entries: %08x\n", (ULONG)ReadField(TagEntries) );
  1336. dprintf( " PsuedoTag Entries: %08x\n", (ULONG)ReadField(PseudoTagEntries) );
  1337. dprintf( " Virtual Alloc List: %08p\n", State->HeapAddress + Offset);
  1338. UCRSegment = ReadField(UCRSegments);
  1339. UnusedUnCommittedRanges = ReadField(UnusedUnCommittedRanges);
  1340. Head = State->HeapAddress + Offset;
  1341. Next = ReadField(VirtualAllocdBlocks.Flink);
  1342. while (Next != Head) {
  1343. ULONG Flags, TagIndex;
  1344. if (InitTypeRead( Next, nt!_HEAP_VIRTUAL_ALLOC_ENTRY)) {
  1345. dprintf( " Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at %p\n", Next );
  1346. break;
  1347. }
  1348. if (State->DumpHeapEntries) {
  1349. dprintf( " %08p: %08x [%02x] - busy (%x)",
  1350. Next,
  1351. (ULONG)ReadField(CommitSize),
  1352. (ULONG)ReadField(CommitSize) - (ULONG)ReadField(BusyBlock.Size),
  1353. Flags = (ULONG)ReadField(BusyBlock.Flags)
  1354. );
  1355. if ((ULONG)ReadField(BusyBlock.Flags) & HEAP_ENTRY_FILL_PATTERN) {
  1356. dprintf( ", tail fill" );
  1357. }
  1358. if ((ULONG)ReadField(ExtraStuff.Settable)) {
  1359. dprintf( " (Handle %08x)", (ULONG)ReadField(ExtraStuff.Settable) );
  1360. }
  1361. if (TagIndex = (ULONG)ReadField(ExtraStuff.TagIndex)) {
  1362. WCHAR TagName[32];
  1363. if (GetHeapTagEntry( State->Heap, (USHORT) (TagIndex), &TagEntry )) {
  1364. GetFieldValue(TagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  1365. dprintf( " (%ws)", TagName );
  1366. }
  1367. else {
  1368. dprintf( " (Tag %x)", (TagIndex) );
  1369. }
  1370. }
  1371. if ((Flags) & HEAP_ENTRY_SETTABLE_FLAGS) {
  1372. dprintf( ", user flags (%x)", ((Flags) & HEAP_ENTRY_SETTABLE_FLAGS) >> 5 );
  1373. }
  1374. dprintf( "\n" );
  1375. #if STACK_TRACE_DATABASE_SUPPORT
  1376. DumpStackBackTraceIndex( State, (ULONG)ReadField(ExtraStuff.AllocatorBackTraceIndex) );
  1377. #endif // STACK_TRACE_DATABASE_SUPPORT
  1378. }
  1379. if (ReadField(Entry.Flink) == Next) {
  1380. dprintf( " **** List is hosed\n");
  1381. break;
  1382. }
  1383. Next = ReadField(Entry.Flink);
  1384. }
  1385. dprintf( " UCR FreeList: %p\n", UnusedUnCommittedRanges );
  1386. while (UCRSegment != 0) {
  1387. b = (BOOL) InitTypeRead( UCRSegment, nt!_HEAP_UCR_SEGMENT);
  1388. if (b) {
  1389. dprintf( " Unable to read _HEAP_UCR_SEGMENT structure at %08p\n", UCRSegment );
  1390. break;
  1391. }
  1392. else {
  1393. dprintf( " UCRSegment - %08p: %08I64x . %08I64x\n",
  1394. UCRSegment,
  1395. ReadField(CommittedSize),
  1396. ReadField(ReservedSize)
  1397. );
  1398. }
  1399. if (State->ComputeSummary) {
  1400. State->OverheadSize += ReadField(CommittedSize);
  1401. }
  1402. UCRSegment = ReadField(Next);
  1403. }
  1404. InitTypeRead(State->HeapAddress, nt!_HEAP);
  1405. dprintf( " FreeList Usage: %08x %08x %08x %08x\n",
  1406. (ULONG)ReadField(u.FreeListsInUseUlong[0]),
  1407. (ULONG)ReadField(u.FreeListsInUseUlong[1]),
  1408. (ULONG)ReadField(u.FreeListsInUseUlong[2]),
  1409. (ULONG)ReadField(u.FreeListsInUseUlong[3])
  1410. );
  1411. if (State->ComputeSummary) {
  1412. State->OverheadSize += GetTypeSize( "nt!_HEAP" );
  1413. dprintf( "Committed Allocated Free OverHead\n" );
  1414. dprintf( "% 8x % 8x % 8x % 8x\r",
  1415. State->CommittedSize,
  1416. State->AllocatedSize,
  1417. State->FreeSize,
  1418. State->OverheadSize
  1419. );
  1420. }
  1421. GetFieldOffset ("nt!_HEAP", "FreeLists", &Offset);
  1422. ListSize = GetTypeSize("nt!_LIST_ENTRY");
  1423. GetFieldOffset ("nt!_HEAP_FREE_ENTRY", "FreeList", &FreeListOffset);
  1424. for (i=0; i<HEAP_MAXIMUM_FREELISTS; i++) {
  1425. ULONG64 Flink, Blink;
  1426. FreeListHead = State->HeapAddress + Offset + ListSize * i;
  1427. GetFieldValue(FreeListHead, "nt!_LIST_ENTRY", "Flink", Flink);
  1428. GetFieldValue(FreeListHead, "nt!_LIST_ENTRY", "Blink", Blink);
  1429. if (Flink != Blink ||
  1430. Flink != FreeListHead
  1431. ) {
  1432. ULONG Count = 0;
  1433. dprintf( " FreeList[ %02x ] at %08p: %08p . %08p ",
  1434. i,
  1435. FreeListHead,
  1436. Blink,
  1437. Flink
  1438. );
  1439. if (State->DumpHeapFreeLists) {
  1440. dprintf("\n");
  1441. }
  1442. Next = Flink;
  1443. while (Next != FreeListHead) {
  1444. Count++;
  1445. FreeEntryAddress = Next - FreeListOffset;
  1446. b = (BOOL) InitTypeRead ( FreeEntryAddress, nt!_HEAP_FREE_ENTRY);
  1447. if (b) {
  1448. dprintf( " Unable to read nt!_HEAP_FREE_ENTRY structure at %08p\n", FreeEntryAddress );
  1449. break;
  1450. }
  1451. if (State->DumpHeapFreeLists) {
  1452. dprintf( " %08x: %05x . %05x [%02x] - free\n",
  1453. FreeEntryAddress,
  1454. (ULONG)ReadField(PreviousSize) << HEAP_GRANULARITY_SHIFT,
  1455. (ULONG)ReadField(Size) << HEAP_GRANULARITY_SHIFT,
  1456. (ULONG)ReadField(Flags)
  1457. );
  1458. }
  1459. Next = ReadField(FreeList.Flink);
  1460. if (CheckControlC()) {
  1461. return;
  1462. }
  1463. }
  1464. if (!State->DumpHeapFreeLists) {
  1465. dprintf( " (%ld block%c)\n",
  1466. Count,
  1467. (Count == 1 ? ' ' : 's')
  1468. );
  1469. }
  1470. }
  1471. }
  1472. for (i=0; i<HEAP_MAXIMUM_SEGMENTS; i++) {
  1473. if (State->Segments[ i ] != 0) {
  1474. State->SegmentNumber = i;
  1475. State->SegmentAddress = State->Segments[ i ];
  1476. WalkHEAP_SEGMENT( State );
  1477. }
  1478. if (State->ExitDumpLoop || CheckControlC()) {
  1479. break;
  1480. }
  1481. }
  1482. if (State->HeapAddress == State->HeapToDump) {
  1483. State->ExitDumpLoop = TRUE;
  1484. }
  1485. return;
  1486. }
  1487. VOID
  1488. WalkHEAP_SEGMENT(
  1489. IN PHEAP_STATE State
  1490. )
  1491. {
  1492. ULONG64 Segment; // PHEAP_SEGMENT
  1493. BOOL b;
  1494. BOOLEAN DumpEntry;
  1495. ULONG64 EntryAddress, PrevEntryAddress, NextEntryAddress; // PHEAP_ENTRY
  1496. ULONG64 Entry, PrevEntry;
  1497. ULONG64 UnCommittedRanges; // PHEAP_UNCOMMMTTED_RANGE
  1498. ULONG64 UnCommittedRangeStart, UnCommittedRange, UnCommittedRangeEnd;
  1499. ULONG64 BaseAddress, LastValidEntry;
  1500. ULONG NumberOfUnCommittedPages, NumberOfPages;
  1501. ULONG EntryOffset;
  1502. Segment = State->Segments[ State->SegmentNumber ];
  1503. if (State->ComputeSummary) {
  1504. State->OverheadSize += GetTypeSize( "nt!_HEAP_SEGMENT" );
  1505. dprintf( "% 8x % 8x % 8x % 8x\r",
  1506. State->CommittedSize,
  1507. State->AllocatedSize,
  1508. State->FreeSize,
  1509. State->OverheadSize
  1510. );
  1511. }
  1512. InitTypeRead(Segment, nt!_HEAP_SEGMENT);
  1513. if (State->DumpHeapSegments) {
  1514. dprintf( " Segment%02u at %08x:\n", State->SegmentNumber, State->SegmentAddress );
  1515. dprintf( " Flags: %08x\n", (ULONG)ReadField(Flags) );
  1516. dprintf( " Base: %08p\n",
  1517. BaseAddress = ReadField(BaseAddress) );
  1518. dprintf( " First Entry: %08x\n", (ULONG)ReadField(FirstEntry) );
  1519. dprintf( " Last Entry: %08p\n",
  1520. LastValidEntry = ReadField(LastValidEntry) );
  1521. dprintf( " Total Pages: %08x\n",
  1522. NumberOfPages = (ULONG)ReadField(NumberOfPages) );
  1523. dprintf( " Total UnCommit: %08x\n",
  1524. NumberOfUnCommittedPages = (ULONG)ReadField(NumberOfUnCommittedPages) );
  1525. dprintf( " Largest UnCommit:%08x\n", (ULONG)ReadField(LargestUnCommittedRange) );
  1526. dprintf( " UnCommitted Ranges: (%u)\n", (ULONG)ReadField(NumberOfUnCommittedRanges) );
  1527. }
  1528. UnCommittedRangeStart = UnCommittedRanges = ReadField(UnCommittedRanges);
  1529. while (UnCommittedRanges != 0) {
  1530. b = (BOOL) InitTypeRead( UnCommittedRanges, nt!_HEAP_UNCOMMMTTED_RANGE);
  1531. if (b) {
  1532. dprintf( " unable to read uncommited range structure at %p\n",
  1533. UnCommittedRanges
  1534. );
  1535. return;
  1536. }
  1537. if (State->DumpHeapSegments) {
  1538. dprintf( " %08I64x: %08x\n", ReadField(Address), (ULONG) ReadField(Size) );
  1539. }
  1540. UnCommittedRanges = ReadField(Next);
  1541. if (CheckControlC()) {
  1542. break;
  1543. }
  1544. }
  1545. if (State->DumpHeapSegments) {
  1546. dprintf( "\n" );
  1547. }
  1548. if (!GetPageSize()) {
  1549. dprintf("Unable to get PageSize.\n");
  1550. return;
  1551. }
  1552. State->CommittedSize += ( NumberOfPages -
  1553. NumberOfUnCommittedPages
  1554. ) * PageSize;
  1555. if (State->ComputeSummary) {
  1556. dprintf( "% 8x % 8x % 8x % 8x\r",
  1557. State->CommittedSize,
  1558. State->AllocatedSize,
  1559. State->FreeSize,
  1560. State->OverheadSize
  1561. );
  1562. }
  1563. if (State->DumpHeapEntries) {
  1564. dprintf( " Heap entries for Segment%02u in Heap %p\n", State->SegmentNumber, State->HeapAddress );
  1565. }
  1566. UnCommittedRangeEnd = UnCommittedRanges;
  1567. UnCommittedRanges = UnCommittedRangeStart;
  1568. if (BaseAddress == State->HeapAddress) {
  1569. GetFieldOffset("nt!_HEAP", "Entry", &EntryOffset);
  1570. EntryAddress = State->HeapAddress + EntryOffset;
  1571. }
  1572. else {
  1573. GetFieldOffset("nt!_HEAP_SEGMENT", "Entry", &EntryOffset);
  1574. EntryAddress = State->Segments[ State->SegmentNumber ] + EntryOffset;
  1575. }
  1576. PrevEntryAddress = 0;
  1577. while (EntryAddress < LastValidEntry) {
  1578. ULONG Flags, Size, UnusedBytes;
  1579. b = (BOOL) InitTypeRead(EntryAddress, nt!_HEAP_ENTRY);
  1580. if (b) {
  1581. dprintf( " unable to read heap entry at %08p\n", EntryAddress );
  1582. break;
  1583. }
  1584. NextEntryAddress = EntryAddress + (Size = (ULONG) ReadField(Size) * HeapEntryTypeSize);
  1585. Flags = (ULONG) ReadField(Flags);
  1586. UnusedBytes = (ULONG) ReadField(UnusedBytes);
  1587. if (State->DumpHeapEntries) {
  1588. DumpEntry = TRUE;
  1589. }
  1590. else
  1591. if (PrevEntryAddress != 0 &&
  1592. (State->HeapEntryToDump == PrevEntryAddress ||
  1593. (State->HeapEntryToDump > PrevEntryAddress &&
  1594. State->HeapEntryToDump <= NextEntryAddress
  1595. )
  1596. )
  1597. ) {
  1598. DumpEntry = TRUE;
  1599. }
  1600. else {
  1601. DumpEntry = FALSE;
  1602. }
  1603. if (DumpEntry) {
  1604. DumpHeapEntry( State, EntryAddress, EntryAddress );
  1605. }
  1606. if (!(Flags & HEAP_ENTRY_BUSY)) {
  1607. State->TotalFreeSize += Size;
  1608. }
  1609. if (State->ComputeSummary) {
  1610. if (Flags & HEAP_ENTRY_BUSY) {
  1611. State->AllocatedSize += (ULONG64) Size << HEAP_GRANULARITY_SHIFT;
  1612. State->AllocatedSize -= UnusedBytes;
  1613. State->OverheadSize += UnusedBytes;
  1614. }
  1615. else {
  1616. State->FreeSize += (ULONG64) Size << HEAP_GRANULARITY_SHIFT;
  1617. }
  1618. }
  1619. if (State->ValidateHeap) {
  1620. if (!ValidateHeapEntry( State,
  1621. PrevEntryAddress,
  1622. PrevEntryAddress,
  1623. EntryAddress,
  1624. EntryAddress
  1625. )
  1626. ) {
  1627. if (State->DumpHeapEntries) {
  1628. break;
  1629. }
  1630. }
  1631. }
  1632. if (Size == 0 || CheckControlC()) {
  1633. break;
  1634. }
  1635. PrevEntryAddress = EntryAddress;
  1636. // PrevEntry = Entry;
  1637. EntryAddress = NextEntryAddress;
  1638. if (Flags & HEAP_ENTRY_LAST_ENTRY) {
  1639. if (State->ComputeSummary) {
  1640. dprintf( "% 8x % 8x % 8x % 8x\r",
  1641. State->CommittedSize,
  1642. State->AllocatedSize,
  1643. State->FreeSize,
  1644. State->OverheadSize
  1645. );
  1646. }
  1647. InitTypeRead(UnCommittedRanges, nt!_HEAP_UNCOMMMTTED_RANGE);
  1648. if (EntryAddress == ReadField(Address)) {
  1649. Size = (ULONG) ReadField(Size);
  1650. if (DumpEntry) {
  1651. dprintf( " %p: %08x - uncommitted bytes.\n",
  1652. EntryAddress,
  1653. Size
  1654. );
  1655. }
  1656. PrevEntryAddress = 0;
  1657. EntryAddress += Size;
  1658. UnCommittedRanges = ReadField(Next);;
  1659. }
  1660. else {
  1661. break;
  1662. }
  1663. }
  1664. }
  1665. if (State->ComputeSummary) {
  1666. dprintf( "% 8x % 8x % 8x % 8x\r",
  1667. State->CommittedSize,
  1668. State->AllocatedSize,
  1669. State->FreeSize,
  1670. State->OverheadSize
  1671. );
  1672. }
  1673. return;
  1674. }
  1675. struct {
  1676. BOOL HaveOffset;
  1677. ULONG Offset;
  1678. LPSTR Description;
  1679. } FieldOffsets[] = {
  1680. 0, 0, "Entry",
  1681. 0, 0, "Signature",
  1682. 0, 0, "Flags",
  1683. 0, 0, "ForceFlags",
  1684. 0, 0, "VirtualMemoryThreshold",
  1685. 0, 0, "SegmentReserve",
  1686. 0, 0, "SegmentCommit",
  1687. 0, 0, "DeCommitFreeBlockThreshold",
  1688. 0, 0, "DeCommitTotalFreeThreshold",
  1689. 0, 0, "TotalFreeSize",
  1690. 0, 0, "MaximumAllocationSize",
  1691. 0, 0, "ProcessHeapsListIndex",
  1692. 0, 0, "HeaderValidateLength",
  1693. 0, 0, "HeaderValidateCopy",
  1694. 0, 0, "NextAvailableTagIndex",
  1695. 0, 0, "MaximumTagIndex",
  1696. 0, 0, "TagEntries",
  1697. 0, 0, "UCRSegments",
  1698. 0, 0, "UnusedUnCommittedRanges",
  1699. 0, 0, "AlignRound",
  1700. 0, 0, "AlignMask",
  1701. 0, 0, "VirtualAllocdBlocks",
  1702. 0, 0, "Segments",
  1703. 0, 0, "FreeListsInUse",
  1704. 0, 0, "FreeListsInUseTerminate",
  1705. 0, 0, "AllocatorBackTraceIndex",
  1706. 0, 0, "Reserved1",
  1707. 0, 0, "PseudoTagEntries",
  1708. 0, 0, "FreeLists",
  1709. 0, 0, "LockVariable",
  1710. // 1, GetTypeSize("HEAP"), "Uncommitted Ranges",
  1711. 0, 0xFFFF, NULL
  1712. };
  1713. BOOL
  1714. ValidateHeapHeader(
  1715. IN ULONG64 HeapAddress
  1716. )
  1717. {
  1718. PVOID CurrentHeaderValidate;
  1719. PVOID PreviousHeaderValidate;
  1720. ULONG i, n, nEqual;
  1721. ULONG64 HeaderValidateCopy;
  1722. ULONG64 HeapSignature;
  1723. BOOL b;
  1724. if (InitTypeRead(HeapAddress, nt!_HEAP)) {
  1725. return FALSE;
  1726. }
  1727. HeapSignature = ReadField(Signature);
  1728. if ( (ULONG)HeapSignature != HEAP_SIGNATURE ) {
  1729. dprintf( "Heap at %p contains invalid signature %I64X.\n",
  1730. HeapAddress,
  1731. HeapSignature );
  1732. return FALSE;
  1733. }
  1734. n = (ULONG) ReadField(HeaderValidateLength);
  1735. if (n == 0 || (HeaderValidateCopy = ReadField(HeaderValidateCopy)) == 0) {
  1736. return TRUE;
  1737. }
  1738. b = FALSE;
  1739. CurrentHeaderValidate = malloc( n );
  1740. if (CurrentHeaderValidate != NULL) {
  1741. PreviousHeaderValidate = malloc( n );
  1742. if (PreviousHeaderValidate != NULL) {
  1743. b = ReadMemory( HeapAddress,
  1744. CurrentHeaderValidate,
  1745. n,
  1746. NULL
  1747. );
  1748. if (b) {
  1749. b = ReadMemory( (HeaderValidateCopy),
  1750. PreviousHeaderValidate,
  1751. n,
  1752. NULL
  1753. );
  1754. if (b) {
  1755. nEqual = (ULONG)RtlCompareMemory( CurrentHeaderValidate,
  1756. PreviousHeaderValidate,
  1757. n
  1758. );
  1759. if (nEqual != n) {
  1760. dprintf( "HEAPEXT: Heap %p - headers modified (%p is %x instead of %x)\n",
  1761. HeapAddress,
  1762. HeapAddress + nEqual,
  1763. *(PULONG)((PCHAR)CurrentHeaderValidate + nEqual),
  1764. *(PULONG)((PCHAR)PreviousHeaderValidate + nEqual)
  1765. );
  1766. for (i=0; FieldOffsets[ i ].Description != NULL; i++) {
  1767. if (!FieldOffsets[i].HaveOffset) {
  1768. GetFieldOffset("nt!_HEAP", FieldOffsets[i].Description, &FieldOffsets[i].Offset);
  1769. FieldOffsets[i].HaveOffset = TRUE;
  1770. }
  1771. if (nEqual >= FieldOffsets[ i ].Offset &&
  1772. nEqual < FieldOffsets[ i+1 ].Offset
  1773. ) {
  1774. dprintf( " This is located in the %s field of the heap header.\n",
  1775. FieldOffsets[ i ].Description
  1776. );
  1777. }
  1778. }
  1779. b = FALSE;
  1780. }
  1781. }
  1782. else {
  1783. dprintf( "HEAPEXT: Unable to read copy of heap headers.\n" );
  1784. }
  1785. }
  1786. else {
  1787. dprintf( "HEAPEXT: Unable to read heap headers.\n" );
  1788. }
  1789. }
  1790. else {
  1791. dprintf( "HEAPEXT: Unable to allocate memory for heap header copy.\n" );
  1792. }
  1793. }
  1794. else {
  1795. dprintf( "HEAPEXT: Unable to allocate memory for heap header.\n" );
  1796. }
  1797. return b;
  1798. }
  1799. UCHAR CheckHeapFillPattern[ 20 ] = {
  1800. CHECK_HEAP_TAIL_FILL,
  1801. CHECK_HEAP_TAIL_FILL,
  1802. CHECK_HEAP_TAIL_FILL,
  1803. CHECK_HEAP_TAIL_FILL,
  1804. CHECK_HEAP_TAIL_FILL,
  1805. CHECK_HEAP_TAIL_FILL,
  1806. CHECK_HEAP_TAIL_FILL,
  1807. CHECK_HEAP_TAIL_FILL
  1808. };
  1809. BOOL
  1810. ValidateHeapEntry(
  1811. IN PHEAP_STATE State,
  1812. IN ULONG64 PrevEntryAddress,
  1813. IN ULONG64 PrevEntry,
  1814. IN ULONG64 EntryAddress,
  1815. IN ULONG64 Entry
  1816. )
  1817. {
  1818. UCHAR EntryTail[ 20 ]; // CHECK_HEAP_TAIL_SIZE
  1819. ULONG FreeFill[ 256 ];
  1820. ULONG64 FreeAddress;
  1821. ULONG tSize, cb, cbEqual;
  1822. BOOL b;
  1823. ULONG PreviousSize, Flags, Size, UnusedBytes, SmallTagIndex;
  1824. ULONG SizeOfEntry;
  1825. SizeOfEntry = GetTypeSize("nt!_HEAP_ENTRY");
  1826. InitTypeRead(EntryAddress, nt!_HEAP_ENTRY);
  1827. (PreviousSize = (ULONG) ReadField(PreviousSize));
  1828. (Size = (ULONG) ReadField(Size));
  1829. (Flags = (ULONG) ReadField(Flags));
  1830. UnusedBytes = (ULONG) ReadField(UnusedBytes);
  1831. SmallTagIndex = (ULONG) ReadField(SmallTagIndex);
  1832. InitTypeRead(PrevEntryAddress, nt!_HEAP_ENTRY);
  1833. if (PrevEntryAddress == 0 && PreviousSize != 0) {
  1834. dprintf( " PreviousSize field is non-zero when it should be zero to mark first entry\n" );
  1835. return FALSE;
  1836. }
  1837. if (PrevEntryAddress != 0 && PreviousSize != (ULONG) ReadField(Size)) {
  1838. dprintf( " PreviousSize field does not match size in previous entry\n" );
  1839. return FALSE;
  1840. }
  1841. if (Flags & HEAP_ENTRY_BUSY) {
  1842. if (Flags & HEAP_ENTRY_FILL_PATTERN) {
  1843. tSize = (Size << HEAP_GRANULARITY_SHIFT) - UnusedBytes;
  1844. b = ReadMemory( (EntryAddress+ HeapEntryTypeSize + tSize),
  1845. EntryTail,
  1846. sizeof( EntryTail ),
  1847. NULL
  1848. );
  1849. if (b) {
  1850. cbEqual = (ULONG)RtlCompareMemory( EntryTail,
  1851. CheckHeapFillPattern,
  1852. CHECK_HEAP_TAIL_SIZE
  1853. );
  1854. if (cbEqual != CHECK_HEAP_TAIL_SIZE) {
  1855. dprintf( " Heap block at %p modified at %p past requested size of %x (%x * 8 - %x)\n",
  1856. EntryAddress,
  1857. EntryAddress + HeapEntryTypeSize + tSize + cbEqual,
  1858. tSize, Size, UnusedBytes
  1859. );
  1860. return FALSE;
  1861. }
  1862. }
  1863. else {
  1864. dprintf( " Unable to read tail of heap block at %p\n", EntryAddress );
  1865. return FALSE;
  1866. }
  1867. }
  1868. }
  1869. else {
  1870. if (Flags & HEAP_ENTRY_FILL_PATTERN) {
  1871. tSize = (Size - 2) << HEAP_GRANULARITY_SHIFT;
  1872. if (Flags & HEAP_ENTRY_EXTRA_PRESENT &&
  1873. tSize > GetTypeSize( "nt!_HEAP_FREE_ENTRY_EXTRA" )
  1874. ) {
  1875. tSize -= GetTypeSize( "nt!_HEAP_FREE_ENTRY_EXTRA" );
  1876. }
  1877. FreeAddress = EntryAddress + GetTypeSize("nt!_HEAP_FREE_ENTRY");
  1878. while (tSize != 0) {
  1879. if (tSize > sizeof( FreeFill )) {
  1880. cb = sizeof( FreeFill );
  1881. }
  1882. else {
  1883. cb = tSize;
  1884. }
  1885. b = ReadMemory( FreeAddress,
  1886. FreeFill,
  1887. cb,
  1888. NULL
  1889. );
  1890. if (b) {
  1891. cbEqual = (ULONG)RtlCompareMemoryUlong( FreeFill, cb, FREE_HEAP_FILL );
  1892. if (cbEqual != cb) { \
  1893. dprintf( " Free Heap block %p modified at %p after it was freed\n",
  1894. EntryAddress,
  1895. FreeAddress + cbEqual
  1896. );
  1897. return FALSE;
  1898. }
  1899. }
  1900. else {
  1901. dprintf( " Unable to portion of free heap block at %p\n", EntryAddress );
  1902. return FALSE;
  1903. }
  1904. tSize -= cb;
  1905. }
  1906. }
  1907. }
  1908. return TRUE;
  1909. }
  1910. VOID
  1911. DumpHeapEntry(
  1912. IN PHEAP_STATE State,
  1913. IN ULONG64 EntryAddress,
  1914. IN ULONG64 Entry
  1915. )
  1916. {
  1917. BOOL b;
  1918. WCHAR TagName[32];
  1919. // HEAP_ENTRY_EXTRA EntryExtra;
  1920. ULONG64 TagEntry; // HEAP_TAG_ENTRY
  1921. // HEAP_FREE_ENTRY_EXTRA FreeExtra;
  1922. ULONG64 p;
  1923. USHORT BackTraceIndex;
  1924. ULONG PreviousSize, Size, Flags, UnusedBytes, SmallTagIndex;
  1925. ULONG SizeOfEntry;
  1926. SizeOfEntry = GetTypeSize("nt!_HEAP_ENTRY");
  1927. InitTypeRead(EntryAddress, nt!_HEAP_ENTRY);
  1928. dprintf( " %p: %05x . %05x [%02x]",
  1929. EntryAddress,
  1930. (PreviousSize = (ULONG) ReadField(PreviousSize)) << HEAP_GRANULARITY_SHIFT,
  1931. (Size = (ULONG) ReadField(Size)) << HEAP_GRANULARITY_SHIFT,
  1932. (Flags = (ULONG) ReadField(Flags))
  1933. );
  1934. BackTraceIndex = 0;
  1935. UnusedBytes = (ULONG) ReadField(UnusedBytes);
  1936. SmallTagIndex = (ULONG) ReadField(SmallTagIndex);
  1937. if (Flags & HEAP_ENTRY_BUSY) {
  1938. dprintf( " - busy (%x)",
  1939. (Size << HEAP_GRANULARITY_SHIFT) - UnusedBytes
  1940. );
  1941. if (Flags & HEAP_ENTRY_FILL_PATTERN) {
  1942. dprintf( ", tail fill" );
  1943. }
  1944. if (Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1945. p = EntryAddress + SizeOfEntry * (Size - 1);
  1946. b = (BOOL) InitTypeRead( p, nt!_HEAP_ENTRY_EXTRA);
  1947. if (b) {
  1948. dprintf( " - unable to read heap entry extra at %p", p );
  1949. }
  1950. else {
  1951. BackTraceIndex = (USHORT)ReadField(AllocatorBackTraceIndex);
  1952. if ((ULONG)ReadField(Settable)) {
  1953. dprintf( " (Handle %08x)", (ULONG)ReadField(Settable) );
  1954. }
  1955. if ((ULONG)ReadField(TagIndex)) {
  1956. if (GetHeapTagEntry( State->Heap, (USHORT)ReadField(TagIndex), &TagEntry )) {
  1957. GetFieldValue(TagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  1958. dprintf( " (%ws)", TagName );
  1959. }
  1960. else {
  1961. dprintf( " (Tag %x)", (ULONG)ReadField(TagIndex) );
  1962. }
  1963. }
  1964. }
  1965. }
  1966. else
  1967. if (SmallTagIndex) {
  1968. if (GetHeapTagEntry( State->Heap, (USHORT) SmallTagIndex, &TagEntry )) {
  1969. GetFieldValue(TagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  1970. dprintf( " (%ws)", TagName );
  1971. }
  1972. else {
  1973. dprintf( " (Tag %x)", SmallTagIndex );
  1974. }
  1975. }
  1976. if (Flags & HEAP_ENTRY_SETTABLE_FLAGS) {
  1977. dprintf( ", user flags (%x)", (Flags & HEAP_ENTRY_SETTABLE_FLAGS) >> 5 );
  1978. }
  1979. dprintf( "\n" );
  1980. }
  1981. else {
  1982. if (Flags & HEAP_ENTRY_FILL_PATTERN) {
  1983. dprintf( " free fill" );
  1984. }
  1985. if (Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1986. p = (EntryAddress + SizeOfEntry * (Size - 1));
  1987. b = (BOOL) InitTypeRead( p, nt!_HEAP_ENTRY_EXTRA);
  1988. if (b) {
  1989. dprintf( " - unable to read heap free extra at %p", p );
  1990. }
  1991. else {
  1992. BackTraceIndex = (USHORT)ReadField(FreeBackTraceIndex);
  1993. if (GetHeapTagEntry( State->Heap, (USHORT)ReadField(TagIndex), &TagEntry )) {
  1994. GetFieldValue(TagEntry, "nt!_HEAP_TAG_ENTRY", "TagName", TagName);
  1995. dprintf( " (%ws)", TagName );
  1996. }
  1997. else {
  1998. dprintf( " (Tag %x at %p)", (ULONG)ReadField(TagIndex), p );
  1999. }
  2000. }
  2001. }
  2002. dprintf( "\n" );
  2003. }
  2004. #if STACK_TRACE_DATABASE_SUPPORT
  2005. DumpStackBackTraceIndex( State, BackTraceIndex );
  2006. #endif // STACK_TRACE_DATABASE_SUPPORT
  2007. return;
  2008. }
  2009. #if STACK_TRACE_DATABASE_SUPPORT && 0
  2010. VOID
  2011. DumpStackBackTraceIndex(
  2012. IN PHEAP_STATE State,
  2013. IN USHORT BackTraceIndex
  2014. )
  2015. {
  2016. BOOL b;
  2017. PRTL_STACK_TRACE_ENTRY pBackTraceEntry;
  2018. RTL_STACK_TRACE_ENTRY BackTraceEntry;
  2019. ULONG i;
  2020. CHAR Symbol[ 1024 ];
  2021. ULONG_PTR Displacement;
  2022. ULONG NumberOfEntriesAdded;
  2023. PRTL_STACK_TRACE_ENTRY *EntryIndexArray; // Indexed by [-1 .. -NumberOfEntriesAdded]
  2024. if (State->DumpStackBackTrace &&
  2025. BackTraceIndex != 0 &&
  2026. pRtlpStackTraceDataBase != NULL
  2027. ) {
  2028. if (!HaveCopyOfStackTraceDataBase) {
  2029. b = ReadMemory( (ULONG_PTR)pRtlpStackTraceDataBase,
  2030. &RtlpStackTraceDataBase,
  2031. sizeof( RtlpStackTraceDataBase ),
  2032. NULL
  2033. );
  2034. if (!b || RtlpStackTraceDataBase == NULL) {
  2035. State->DumpStackBackTrace = FALSE;
  2036. return;
  2037. }
  2038. b = ReadMemory( (ULONG_PTR)RtlpStackTraceDataBase,
  2039. &StackTraceDataBase,
  2040. sizeof( StackTraceDataBase ),
  2041. NULL
  2042. );
  2043. if (!b) {
  2044. State->DumpStackBackTrace = FALSE;
  2045. return;
  2046. }
  2047. HaveCopyOfStackTraceDataBase = TRUE;
  2048. }
  2049. if (BackTraceIndex < StackTraceDataBase.NumberOfEntriesAdded) {
  2050. b = ReadMemory( (ULONG_PTR)(StackTraceDataBase.EntryIndexArray - BackTraceIndex),
  2051. &pBackTraceEntry,
  2052. sizeof( pBackTraceEntry ),
  2053. NULL
  2054. );
  2055. if (!b) {
  2056. dprintf( " unable to read stack back trace index (%x) entry at %p\n",
  2057. BackTraceIndex,
  2058. (StackTraceDataBase.EntryIndexArray - BackTraceIndex)
  2059. );
  2060. return;
  2061. }
  2062. b = ReadMemory( (ULONG_PTR)pBackTraceEntry,
  2063. &BackTraceEntry,
  2064. sizeof( BackTraceEntry ),
  2065. NULL
  2066. );
  2067. if (!b) {
  2068. dprintf( " unable to read stack back trace entry at %p\n",
  2069. BackTraceIndex,
  2070. pBackTraceEntry
  2071. );
  2072. return;
  2073. }
  2074. dprintf( " Stack trace (%u) at %x:\n", BackTraceIndex, pBackTraceEntry );
  2075. for (i=0; i<BackTraceEntry.Depth; i++) {
  2076. GetSymbol( (LPVOID)BackTraceEntry.BackTrace[ i ],
  2077. Symbol,
  2078. &Displacement
  2079. );
  2080. dprintf( " %08x: %s", BackTraceEntry.BackTrace[ i ], Symbol );
  2081. if (Displacement != 0) {
  2082. dprintf( "+0x%p", Displacement );
  2083. }
  2084. dprintf( "\n" );
  2085. }
  2086. }
  2087. }
  2088. }
  2089. #endif // STACK_TRACE_DATABASE_SUPPORT
  2090. #if 0
  2091. int
  2092. __cdecl
  2093. _wtoi(
  2094. const wchar_t *nptr
  2095. )
  2096. {
  2097. NTSTATUS Status;
  2098. ULONG Value;
  2099. UNICODE_STRING UnicodeString;
  2100. RtlInitUnicodeString( &UnicodeString, nptr );
  2101. Status = RtlUnicodeStringToInteger( &UnicodeString, 10, &Value );
  2102. if (NT_SUCCESS( Status )) {
  2103. return (int)Value;
  2104. }
  2105. else {
  2106. return 0;
  2107. }
  2108. }
  2109. #endif