Source code of Windows XP (NT5)
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.

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