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.

2348 lines
70 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. heaputil.cpp
  5. Revision History:
  6. ivanbrug oct 2000 created
  7. --*/
  8. #include <wmiexts.h>
  9. #include <utilfun.h>
  10. #include <malloc.h>
  11. /*
  12. #if defined(_WIN64)
  13. #define HEAP_GRANULARITY_SHIFT 4 // Log2( HEAP_GRANULARITY )
  14. #else
  15. #define HEAP_GRANULARITY_SHIFT 3 // Log2( HEAP_GRANULARITY )
  16. #endif
  17. #define HEAP_ENTRY_BUSY 0x01
  18. #define HEAP_ENTRY_EXTRA_PRESENT 0x02
  19. #define HEAP_ENTRY_FILL_PATTERN 0x04
  20. #define HEAP_ENTRY_VIRTUAL_ALLOC 0x08
  21. #define HEAP_ENTRY_LAST_ENTRY 0x10
  22. #define HEAP_ENTRY_SETTABLE_FLAG1 0x20
  23. #define HEAP_ENTRY_SETTABLE_FLAG2 0x40
  24. #define HEAP_ENTRY_SETTABLE_FLAG3 0x80
  25. #define HEAP_ENTRY_SETTABLE_FLAGS 0xE0
  26. typedef struct _HEAP_ENTRY {
  27. //
  28. // This field gives the size of the current block in allocation
  29. // granularity units. (i.e. Size << HEAP_GRANULARITY_SHIFT
  30. // equals the size in bytes).
  31. //
  32. // Except if this is part of a virtual alloc block then this
  33. // value is the difference between the commit size in the virtual
  34. // alloc entry and the what the user asked for.
  35. //
  36. USHORT Size;
  37. //
  38. // This field gives the size of the previous block in allocation
  39. // granularity units. (i.e. PreviousSize << HEAP_GRANULARITY_SHIFT
  40. // equals the size of the previous block in bytes).
  41. //
  42. USHORT PreviousSize;
  43. //
  44. // This field contains the index into the segment that controls
  45. // the memory for this block.
  46. //
  47. UCHAR SegmentIndex;
  48. //
  49. // This field contains various flag bits associated with this block.
  50. // Currently these are:
  51. //
  52. // 0x01 - HEAP_ENTRY_BUSY
  53. // 0x02 - HEAP_ENTRY_EXTRA_PRESENT
  54. // 0x04 - HEAP_ENTRY_FILL_PATTERN
  55. // 0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
  56. // 0x10 - HEAP_ENTRY_LAST_ENTRY
  57. // 0x20 - HEAP_ENTRY_SETTABLE_FLAG1
  58. // 0x40 - HEAP_ENTRY_SETTABLE_FLAG2
  59. // 0x80 - HEAP_ENTRY_SETTABLE_FLAG3
  60. //
  61. UCHAR Flags;
  62. //
  63. // This field contains the number of unused bytes at the end of this
  64. // block that were not actually allocated. Used to compute exact
  65. // size requested prior to rounding requested size to allocation
  66. // granularity. Also used for tail checking purposes.
  67. //
  68. UCHAR UnusedBytes;
  69. //
  70. // Small (8 bit) tag indexes can go here.
  71. //
  72. UCHAR SmallTagIndex;
  73. #if defined(_WIN64)
  74. ULONGLONG Reserved1;
  75. #endif
  76. } HEAP_ENTRY, *PHEAP_ENTRY;
  77. typedef struct _HEAP_UNCOMMMTTED_RANGE {
  78. struct _HEAP_UNCOMMMTTED_RANGE *Next;
  79. ULONG_PTR Address;
  80. SIZE_T Size;
  81. ULONG filler;
  82. } HEAP_UNCOMMMTTED_RANGE, *PHEAP_UNCOMMMTTED_RANGE;
  83. typedef struct _HEAP_SEGMENT {
  84. HEAP_ENTRY Entry;
  85. ULONG Signature;
  86. ULONG Flags;
  87. struct _HEAP *Heap;
  88. SIZE_T LargestUnCommittedRange;
  89. PVOID BaseAddress;
  90. ULONG NumberOfPages;
  91. PHEAP_ENTRY FirstEntry;
  92. PHEAP_ENTRY LastValidEntry;
  93. ULONG NumberOfUnCommittedPages;
  94. ULONG NumberOfUnCommittedRanges;
  95. PHEAP_UNCOMMMTTED_RANGE UnCommittedRanges;
  96. USHORT AllocatorBackTraceIndex;
  97. USHORT Reserved;
  98. PHEAP_ENTRY LastEntryInSegment;
  99. } HEAP_SEGMENT, *PHEAP_SEGMENT;
  100. */
  101. typedef ULONG_PTR ERESOURCE_THREAD;
  102. typedef ERESOURCE_THREAD *PERESOURCE_THREAD;
  103. typedef struct _OWNER_ENTRY {
  104. ERESOURCE_THREAD OwnerThread;
  105. union {
  106. LONG OwnerCount;
  107. ULONG TableSize;
  108. };
  109. } OWNER_ENTRY, *POWNER_ENTRY;
  110. typedef void * PKSEMAPHORE;
  111. typedef void * PKEVENT;
  112. typedef struct _ERESOURCE {
  113. LIST_ENTRY SystemResourcesList;
  114. POWNER_ENTRY OwnerTable;
  115. SHORT ActiveCount;
  116. USHORT Flag;
  117. PKSEMAPHORE SharedWaiters;
  118. PKEVENT ExclusiveWaiters;
  119. OWNER_ENTRY OwnerThreads[2];
  120. ULONG ContentionCount;
  121. USHORT NumberOfSharedWaiters;
  122. USHORT NumberOfExclusiveWaiters;
  123. union {
  124. PVOID Address;
  125. ULONG_PTR CreatorBackTraceIndex;
  126. };
  127. KSPIN_LOCK SpinLock;
  128. } ERESOURCE, *PERESOURCE;
  129. //typedef void * PRTL_TRACE_BLOCK;
  130. #include "heap.h"
  131. #include "heappagi.h"
  132. #define HE_VERBOSITY_FLAGS 1
  133. #define HE_VERBOSITY_NUMERIC 2
  134. #define HE_VERBOSITY_VTABLE 4
  135. #if defined(_X86_)
  136. #ifndef PAGE_SIZE
  137. #define PAGE_SIZE 0x1000
  138. #endif
  139. #define USER_ALIGNMENT 8
  140. #elif defined(_IA64_)
  141. #ifndef PAGE_SIZE
  142. #define PAGE_SIZE 0x2000
  143. #endif
  144. #define USER_ALIGNMENT 16
  145. #elif defined(_AMD64_)
  146. #ifndef PAGE_SIZE
  147. #define PAGE_SIZE 0x1000
  148. #endif
  149. #define USER_ALIGNMENT 16
  150. #else
  151. #error // platform not defined
  152. #endif
  153. //
  154. //
  155. //
  156. //
  157. //
  158. typedef DWORD (__stdcall * fnCallBack)(ULONG_PTR pParam1,ULONG_PTR pParam2);
  159. DWORD g_UsedInHeap = 0;
  160. void
  161. PrintHeapEntry(HEAP_ENTRY * pEntry,void * pAddr)
  162. {
  163. BYTE varEntry[sizeof(HEAP_ENTRY)+2*sizeof(void *)];
  164. LIST_ENTRY * pListEntry = (LIST_ENTRY *)((HEAP_ENTRY *)varEntry+1);
  165. DWORD PrintSize = 0;
  166. BOOL bIsPossiblePageHeap = FALSE;
  167. if (pEntry->Flags & HEAP_ENTRY_BUSY)
  168. {
  169. // re-read the entry, to get if it's on the LookAside
  170. if (ReadMemory((MEMORY_ADDRESS)pAddr,varEntry,sizeof(varEntry),NULL))
  171. {
  172. #ifdef WIN64
  173. if (0xf0f0f0f0f0f0f0f0 == (ULONG_PTR)pListEntry->Blink )
  174. #else
  175. if (0xf0f0f0f0 == (ULONG_PTR)pListEntry->Blink )
  176. #endif
  177. {
  178. PrintSize = 0xf7eef7ee;
  179. }
  180. else
  181. {
  182. PrintSize = (pEntry->Size<<HEAP_GRANULARITY_SHIFT)-pEntry->UnusedBytes;
  183. g_UsedInHeap += PrintSize;
  184. }
  185. DWORD Sign = *((DWORD *)pListEntry);
  186. //dprintf("Sign %08x\n",Sign);
  187. if (0xabcdaaaa == Sign)
  188. {
  189. bIsPossiblePageHeap = TRUE;
  190. }
  191. }
  192. else
  193. {
  194. PrintSize = (pEntry->Size<<HEAP_GRANULARITY_SHIFT)-pEntry->UnusedBytes;
  195. g_UsedInHeap += PrintSize;
  196. }
  197. }
  198. else
  199. {
  200. PrintSize = 0xf7eef7ee;
  201. }
  202. dprintf(" %p: %04x . %04x [%02x] - (%x)\n",
  203. pAddr,pEntry->Size,pEntry->PreviousSize,pEntry->Flags,PrintSize);
  204. if (bIsPossiblePageHeap)
  205. {
  206. //dprintf("Possible %p\n",(MEMORY_ADDRESS)((BYTE*)pAddr+sizeof(HEAP_ENTRY)+sizeof(DPH_BLOCK_INFORMATION)));
  207. GetVTable((MEMORY_ADDRESS)((BYTE*)pAddr+sizeof(HEAP_ENTRY)+sizeof(DPH_BLOCK_INFORMATION)));
  208. }
  209. else
  210. GetVTable((MEMORY_ADDRESS)((BYTE*)pAddr+sizeof(HEAP_ENTRY)));
  211. };
  212. //
  213. //
  214. // print the HEAP_ENTRY structure
  215. //
  216. DECLARE_API(he) {
  217. INIT_API();
  218. DEFINE_CPP_VAR( HEAP_ENTRY, varHEAP_ENTRY);
  219. HEAP_ENTRY * pEntry = GET_CPP_VAR_PTR( HEAP_ENTRY , varHEAP_ENTRY );
  220. memset(pEntry,0xfe,sizeof(HEAP_ENTRY));
  221. MEMORY_ADDRESS pByte = GetExpression(args);
  222. if (pByte)
  223. {
  224. if (ReadMemory((MEMORY_ADDRESS)pByte,pEntry ,sizeof(HEAP_ENTRY),NULL))
  225. {
  226. PrintHeapEntry(pEntry,(void *)pByte);
  227. }
  228. else
  229. {
  230. dprintf("RM %p\n",pByte);
  231. }
  232. } else {
  233. dprintf("invalid HEAP_ENTRY address %s\n",args);
  234. }
  235. }
  236. //
  237. // HEAP_ENTRY list
  238. // finds the beginning of the "list" of HEAP_ENTRYs
  239. //
  240. DECLARE_API(heb) {
  241. INIT_API();
  242. MEMORY_ADDRESS pEntry = GetExpression(args);
  243. if (pEntry){
  244. HEAP_ENTRY HeapEntry;
  245. ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0);
  246. PrintHeapEntry(&HeapEntry,(void *)pEntry);
  247. while (HeapEntry.PreviousSize)
  248. {
  249. pEntry = (MEMORY_ADDRESS)((HEAP_ENTRY*)pEntry - HeapEntry.PreviousSize);
  250. if (ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0))
  251. {
  252. PrintHeapEntry(&HeapEntry,(void *)pEntry);
  253. }
  254. else
  255. {
  256. dprintf("RM %p\n",pEntry);
  257. break;
  258. }
  259. if (CheckControlC())
  260. break;
  261. }
  262. dprintf(" begin %08x\n",pEntry);
  263. } else {
  264. dprintf("invalid address %s\n",args);
  265. };
  266. }
  267. //
  268. //
  269. // HEAP_ENTRY forward
  270. //
  271. //////////////////////////////////////////////////////
  272. DECLARE_API(hef) {
  273. INIT_API();
  274. DWORD BeginNum=0;
  275. MEMORY_ADDRESS pEntry = GetExpression(args);
  276. if (pEntry)
  277. {
  278. HEAP_ENTRY HeapEntry;
  279. ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0);
  280. PrintHeapEntry(&HeapEntry,(void *)pEntry);
  281. while (!(HeapEntry.Flags & HEAP_ENTRY_LAST_ENTRY))
  282. {
  283. pEntry = (MEMORY_ADDRESS)((HEAP_ENTRY*)pEntry + HeapEntry.Size);
  284. if (ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0))
  285. {
  286. PrintHeapEntry(&HeapEntry,(void *)pEntry);
  287. }
  288. else
  289. {
  290. dprintf("RM %p\n",pEntry);
  291. break;
  292. }
  293. if (CheckControlC())
  294. break;
  295. }
  296. dprintf(" end %08x\n",pEntry);
  297. } else {
  298. dprintf("invalid address %s\n",args);
  299. };
  300. }
  301. DWORD EnumEntries(HEAP_ENTRY * pEntry,DWORD * pSize,fnCallBack CallBack,ULONG_PTR Addr){
  302. DWORD i=0;
  303. HEAP_ENTRY HeapEntry;
  304. DWORD Size=0;
  305. ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0);
  306. if (CallBack)
  307. {
  308. CallBack((ULONG_PTR)pEntry,Addr);
  309. }
  310. else
  311. {
  312. PrintHeapEntry(&HeapEntry,pEntry);
  313. };
  314. while (!(HeapEntry.Flags & HEAP_ENTRY_LAST_ENTRY))
  315. {
  316. if (0 == HeapEntry.Size)
  317. {
  318. dprintf("HEAP_ENTRY %p with zero Size\n",pEntry);
  319. break;
  320. }
  321. pEntry = (HEAP_ENTRY*)pEntry + HeapEntry.Size;
  322. if (ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0))
  323. {
  324. if (CallBack)
  325. {
  326. CallBack((ULONG_PTR)pEntry,Addr);
  327. }
  328. else
  329. {
  330. PrintHeapEntry(&HeapEntry,pEntry);
  331. };
  332. }
  333. else
  334. {
  335. dprintf("RM %p\n",pEntry);
  336. break;
  337. }
  338. i++;
  339. Size += ((HeapEntry.Size<<HEAP_GRANULARITY_SHIFT)-HeapEntry.UnusedBytes);
  340. if (CheckControlC())
  341. break;
  342. }
  343. if (pSize){
  344. *pSize = Size;
  345. }
  346. return i;
  347. }
  348. void
  349. PrintHEAP_SEGMENT(HEAP_SEGMENT * pSeg_OOP,
  350. fnCallBack CallBack,
  351. ULONG_PTR Addr)
  352. {
  353. DEFINE_CPP_VAR( HEAP_SEGMENT, varHEAP_SEGMENT);
  354. HEAP_SEGMENT * pSeg = GET_CPP_VAR_PTR( HEAP_SEGMENT , varHEAP_SEGMENT );
  355. BOOL bRet = ReadMemory((MEMORY_ADDRESS)pSeg_OOP,pSeg ,sizeof(HEAP_SEGMENT),0);
  356. if (bRet)
  357. {
  358. if (!CallBack)
  359. dprintf(" Flags %08x HEAP %p\n",pSeg->Flags,pSeg->Heap);
  360. //SIZE_T LargestUnCommittedRange;
  361. //PVOID BaseAddress;
  362. //ULONG NumberOfPages;
  363. //PHEAP_ENTRY FirstEntry;
  364. //PHEAP_ENTRY LastValidEntry;
  365. //ULONG NumberOfUnCommittedPages;
  366. DWORD unComm = pSeg->NumberOfUnCommittedRanges;
  367. //PHEAP_UNCOMMMTTED_RANGE UnCommittedRanges;
  368. //USHORT AllocatorBackTraceIndex;
  369. //USHORT Reserved;
  370. //PHEAP_ENTRY LastEntryInSegment;
  371. HEAP_UNCOMMMTTED_RANGE UncRange;
  372. HEAP_UNCOMMMTTED_RANGE * pUncRange = pSeg->UnCommittedRanges;
  373. HEAP_ENTRY ** pCommRange = (HEAP_ENTRY **)_alloca(sizeof(HEAP_ENTRY *)*(unComm+1));
  374. DWORD Size=0;
  375. DWORD Num=0;
  376. pCommRange[0] = (HEAP_ENTRY *)pSeg->FirstEntry;
  377. Num = EnumEntries(pCommRange[0],&Size,CallBack,Addr);
  378. if (!CallBack)
  379. dprintf(" - %p Size %p entries %d \n",pCommRange[0],Size,Num);
  380. for (DWORD i=0; i<unComm; i++)
  381. {
  382. bRet = ReadMemory((MEMORY_ADDRESS)pUncRange,&UncRange,sizeof(UncRange),NULL);
  383. if (bRet)
  384. {
  385. pUncRange = UncRange.Next;
  386. pCommRange[1+i] = (HEAP_ENTRY *)(UncRange.Address + UncRange.Size);
  387. if (NULL == pUncRange)
  388. {
  389. if ((ULONG_PTR)pCommRange[1+i] == (ULONG_PTR)pSeg->LastValidEntry)
  390. break;
  391. }
  392. Num = EnumEntries(pCommRange[1+i],&Size,CallBack,Addr);
  393. if (!CallBack)
  394. dprintf(" - %p Size %p entries %d\n",pCommRange[1+i],Size,Num);
  395. }
  396. else
  397. {
  398. dprintf("RM %p\n",pUncRange);
  399. }
  400. }
  401. } else {
  402. dprintf("RM %p\n",pSeg_OOP);
  403. }
  404. }
  405. //
  406. //
  407. // Dump the HEAP_SEGMENT
  408. //
  409. DECLARE_API(hs) {
  410. INIT_API();
  411. MEMORY_ADDRESS pByte = 0;
  412. pByte = GetExpression(args);
  413. if (pByte)
  414. {
  415. PrintHEAP_SEGMENT((HEAP_SEGMENT *)pByte,NULL,NULL);
  416. }
  417. else
  418. {
  419. dprintf("invalid address %s\n",args);
  420. }
  421. }
  422. //
  423. // Define heap lookaside list allocation functions.
  424. //
  425. struct SLIST_HEADER_
  426. {
  427. SLIST_HEADER_ * Next;
  428. ULONG_PTR Align;
  429. };
  430. typedef struct _HEAP_LOOKASIDE {
  431. SLIST_HEADER_ ListHead;
  432. USHORT Depth;
  433. USHORT MaximumDepth;
  434. ULONG TotalAllocates;
  435. ULONG AllocateMisses;
  436. ULONG TotalFrees;
  437. ULONG FreeMisses;
  438. ULONG LastTotalAllocates;
  439. ULONG LastAllocateMisses;
  440. ULONG Counters[2];
  441. #ifdef _IA64_
  442. DWORD Pad[3];
  443. #else
  444. DWORD Pad;
  445. #endif
  446. } HEAP_LOOKASIDE, *PHEAP_LOOKASIDE;
  447. void Dump_LookAside(ULONG_PTR pLookAside_OOP)
  448. {
  449. DWORD dwSize = sizeof(HEAP_LOOKASIDE) * HEAP_MAXIMUM_FREELISTS ;
  450. BYTE * pData = new BYTE[dwSize];
  451. if (pData)
  452. {
  453. if (ReadMemory(pLookAside_OOP,pData,dwSize,NULL))
  454. {
  455. DWORD i;
  456. HEAP_LOOKASIDE * pLookasideArray = (HEAP_LOOKASIDE *)pData;
  457. BYTE varHEAP_ENTRY[sizeof(HEAP_ENTRY)+sizeof(SLIST_HEADER_)];
  458. HEAP_ENTRY * pEntry = GET_CPP_VAR_PTR( HEAP_ENTRY , varHEAP_ENTRY );
  459. SLIST_HEADER_ * pSListEntry = (SLIST_HEADER_ *)(pEntry+1);
  460. char Fill[8];
  461. memset(Fill,0xf0,8);
  462. for(i=0;i<HEAP_MAXIMUM_FREELISTS;i++)
  463. {
  464. ULONG_PTR pTmp;
  465. SLIST_HEADER_ * pHead_OOP = pLookasideArray[i].ListHead.Next;
  466. #ifdef _IA64_
  467. pTmp = (ULONG_PTR)pHead_OOP;
  468. pTmp>>=25;
  469. pTmp<<=4;
  470. pHead_OOP = (SLIST_HEADER_ *)pTmp;
  471. #endif
  472. dprintf(" LookAside[%x] - %p Depth %x Maximum %x\n",
  473. i,
  474. pHead_OOP, //pLookasideArray[i].ListHead.Next,
  475. pLookasideArray[i].Depth,
  476. pLookasideArray[i].MaximumDepth);
  477. //dprintf("size %x %p\n",sizeof(HEAP_LOOKASIDE),pHead_OOP);
  478. USHORT Depth = 0;
  479. while(pHead_OOP)
  480. {
  481. HEAP_ENTRY * pEntry_OOP = (HEAP_ENTRY *)pHead_OOP-1;
  482. if (ReadMemory((MEMORY_ADDRESS)pEntry_OOP,pEntry,sizeof(varHEAP_ENTRY),NULL))
  483. {
  484. ULONG_PTR pToWrite = sizeof(ULONG_PTR) + (ULONG_PTR)pHead_OOP;
  485. WriteMemory(pToWrite,Fill,sizeof(ULONG_PTR),0);
  486. pHead_OOP = pSListEntry->Next;
  487. PrintHeapEntry(pEntry,pEntry_OOP);
  488. }
  489. else
  490. {
  491. dprintf("RM %d\n",GetLastError());
  492. break;
  493. }
  494. Depth++;
  495. if (Depth > pLookasideArray[i].MaximumDepth)
  496. {
  497. dprintf("MaximumDepth exceeded\n");
  498. break;
  499. }
  500. };
  501. }
  502. }
  503. else
  504. {
  505. dprintf("RM %d\n",GetLastError());
  506. }
  507. delete [] pData;
  508. }
  509. }
  510. #define HEAP_FRONT_LOOKASIDE 1
  511. #define HEAP_FRONT_LOWFRAGHEAP 2
  512. //
  513. // prepares the Lookaside list for dump
  514. //
  515. DECLARE_API(lhp)
  516. {
  517. INIT_API();
  518. DEFINE_CPP_VAR( HEAP, varHEAP);
  519. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  520. MEMORY_ADDRESS pByte = GetExpression(args);
  521. DWORD i;
  522. if (pByte)
  523. {
  524. if (ReadMemory(pByte,pHeap ,sizeof(HEAP),NULL))
  525. {
  526. //dprintf("----- LookAside %p\n",pHeap->FrontEndHeap);
  527. if (1 == pHeap->FrontEndHeapType)
  528. Dump_LookAside((ULONG_PTR)pHeap->FrontEndHeap);
  529. else
  530. dprintf("_HEAP FrontEndHeapType %d not recognized \n",pHeap->FrontEndHeapType);
  531. }
  532. else
  533. {
  534. dprintf("RM %p %d\n",pByte,GetLastError());
  535. }
  536. }
  537. else
  538. {
  539. dprintf("invalid heap address %s\n",args);
  540. }
  541. }
  542. //
  543. // Low fragmentation heap data structures
  544. //
  545. typedef struct _BLOCK_ENTRY : HEAP_ENTRY
  546. {
  547. USHORT LinkOffset;
  548. USHORT Reserved2;
  549. } BLOCK_ENTRY, *PBLOCK_ENTRY;
  550. typedef struct _INTERLOCK_SEQ {
  551. union {
  552. struct {
  553. union {
  554. struct {
  555. USHORT Depth;
  556. USHORT FreeEntryOffset;
  557. };
  558. volatile ULONG OffsetAndDepth;
  559. };
  560. volatile ULONG Sequence;
  561. };
  562. volatile LONGLONG Exchg;
  563. };
  564. } INTERLOCK_SEQ, *PINTERLOCK_SEQ;
  565. struct _HEAP_USERDATA_HEADER;
  566. typedef struct _HEAP_SUBSEGMENT {
  567. PVOID Bucket;
  568. volatile struct _HEAP_USERDATA_HEADER * UserBlocks;
  569. INTERLOCK_SEQ AggregateExchg;
  570. union {
  571. struct {
  572. USHORT BlockSize;
  573. USHORT FreeThreshold;
  574. USHORT BlockCount;
  575. UCHAR SizeIndex;
  576. UCHAR AffinityIndex;
  577. };
  578. ULONG Alignment[2];
  579. };
  580. SINGLE_LIST_ENTRY SFreeListEntry;
  581. volatile ULONG Lock;
  582. } HEAP_SUBSEGMENT, *PHEAP_SUBSEGMENT;
  583. typedef struct _HEAP_USERDATA_HEADER {
  584. union {
  585. SINGLE_LIST_ENTRY SFreeListEntry;
  586. PHEAP_SUBSEGMENT SubSegment;
  587. };
  588. PVOID HeapHandle;
  589. ULONG_PTR SizeIndex;
  590. ULONG_PTR Signature;
  591. } HEAP_USERDATA_HEADER, *PHEAP_USERDATA_HEADER;
  592. typedef union _HEAP_BUCKET_COUNTERS{
  593. struct {
  594. volatile ULONG TotalBlocks;
  595. volatile ULONG SubSegmentCounts;
  596. };
  597. volatile LONGLONG Aggregate64;
  598. } HEAP_BUCKET_COUNTERS, *PHEAP_BUCKET_COUNTERS;
  599. //
  600. // The HEAP_BUCKET structure handles same size allocations
  601. //
  602. typedef struct _HEAP_BUCKET {
  603. HEAP_BUCKET_COUNTERS Counters;
  604. USHORT BlockUnits;
  605. UCHAR SizeIndex;
  606. UCHAR UseAffinity;
  607. LONG Conversions;
  608. } HEAP_BUCKET, *PHEAP_BUCKET;
  609. //
  610. // LFH heap uses zones to allocate sub-segment descriptors. This will preallocate
  611. // a large block and then for each individual sub-segment request will move the
  612. // water mark pointer with a non-blocking operation
  613. //
  614. typedef struct _LFH_BLOCK_ZONE {
  615. LIST_ENTRY ListEntry;
  616. PVOID FreePointer;
  617. PVOID Limit;
  618. } LFH_BLOCK_ZONE, *PLFH_BLOCK_ZONE;
  619. #define FREE_CACHE_SIZE 16
  620. typedef struct _HEAP_LOCAL_SEGMENT_INFO {
  621. PHEAP_SUBSEGMENT Hint;
  622. PHEAP_SUBSEGMENT ActiveSubsegment;
  623. PHEAP_SUBSEGMENT CachedItems[ FREE_CACHE_SIZE ];
  624. SLIST_HEADER SListHeader;
  625. SIZE_T BusyEntries;
  626. SIZE_T LastUsed;
  627. } HEAP_LOCAL_SEGMENT_INFO, *PHEAP_LOCAL_SEGMENT_INFO;
  628. #define HEAP_BUCKETS_COUNT 128
  629. typedef struct _HEAP_LOCAL_DATA {
  630. //
  631. // We reserve the 128 bytes below to avoid sharing memory
  632. // into the same cacheline on MP machines
  633. //
  634. UCHAR Reserved[128];
  635. volatile PLFH_BLOCK_ZONE CrtZone;
  636. struct _LFH_HEAP * LowFragHeap;
  637. HEAP_LOCAL_SEGMENT_INFO SegmentInfo[HEAP_BUCKETS_COUNT];
  638. SLIST_HEADER DeletedSubSegments;
  639. ULONG Affinity;
  640. ULONG Reserved1;
  641. } HEAP_LOCAL_DATA, *PHEAP_LOCAL_DATA;
  642. //
  643. // Fixed size large block cache data structures & definitions
  644. // This holds in S-Lists the blocks that can be free, but it
  645. // delay the free until no other thread is doing a heap operation
  646. // This helps reducing the contention on the heap lock,
  647. // improve the scalability with a relatively low memory footprint
  648. //
  649. #define HEAP_LOWEST_USER_SIZE_INDEX 7
  650. #define HEAP_HIGHEST_USER_SIZE_INDEX 18
  651. #define HEAP_USER_ENTRIES (HEAP_HIGHEST_USER_SIZE_INDEX - HEAP_LOWEST_USER_SIZE_INDEX + 1)
  652. typedef struct _USER_MEMORY_CACHE {
  653. SLIST_HEADER UserBlocks[ HEAP_USER_ENTRIES ];
  654. ULONG FreeBlocks;
  655. ULONG Sequence;
  656. ULONG MinDepth[ HEAP_USER_ENTRIES ];
  657. ULONG AvailableBlocks[ HEAP_USER_ENTRIES ];
  658. } USER_MEMORY_CACHE, *PUSER_MEMORY_CACHE;
  659. typedef struct _LFH_HEAP {
  660. RTL_CRITICAL_SECTION Lock;
  661. LIST_ENTRY SubSegmentZones;
  662. SIZE_T ZoneBlockSize;
  663. HANDLE Heap;
  664. LONG Conversions;
  665. LONG ConvertedSpace;
  666. ULONG SegmentChange; //
  667. ULONG SegmentCreate; // Various counters (optional)
  668. ULONG SegmentInsertInFree; //
  669. ULONG SegmentDelete; //
  670. USER_MEMORY_CACHE UserBlockCache;
  671. //
  672. // Bucket data
  673. //
  674. HEAP_BUCKET Buckets[HEAP_BUCKETS_COUNT];
  675. //
  676. // The LocalData array must be the last field in LFH structures
  677. // The sizes of the array is choosen depending upon the
  678. // number of processors.
  679. //
  680. HEAP_LOCAL_DATA LocalData[1];
  681. } LFH_HEAP, *PLFH_HEAP;
  682. /*
  683. MEMORY_ADDRESS Addr = GetExpression(args);
  684. if (NULL == Addr)
  685. {
  686. dprintf("unable to resolve %s\n",args);
  687. return;
  688. }
  689. HEAP_USERDATA_HEADER UserData;
  690. if (ReadMemory(Addr,&UserData,sizeof(UserData),NULL))
  691. {
  692. dprintf(" Next %p HeapHandle %p SizeIndex %p Signature %p\n",
  693. UserData.SFreeListEntry.Next,
  694. UserData.HeapHandle,
  695. UserData.SizeIndex,
  696. UserData.Signature);
  697. BLOCK_ENTRY * pBlkEntry = (BLOCK_ENTRY *)((HEAP_USERDATA_HEADER*)Addr+1);
  698. while(pBlkEntry)
  699. {
  700. BLOCK_ENTRY BlkEntry;
  701. if (ReadMemory((ULONG_PTR)pBlkEntry,&BlkEntry,sizeof(BlkEntry),NULL))
  702. {
  703. dprintf(" %p : %08x %02x %02x %02x %02x - %04x %04x\n",
  704. pBlkEntry,
  705. *(DWORD *)&BlkEntry.Size,
  706. BlkEntry.SmallTagIndex,
  707. BlkEntry.Flags,
  708. BlkEntry.UnusedBytes,
  709. BlkEntry.SegmentIndex,
  710. BlkEntry.LinkOffset,
  711. BlkEntry.Reserved2);
  712. GetVTable((MEMORY_ADDRESS)((BYTE*)pBlkEntry+sizeof(BLOCK_ENTRY)));
  713. if (1 == BlkEntry.SmallTagIndex)
  714. {
  715. pBlkEntry = (BLOCK_ENTRY *)((HEAP_ENTRY *)pBlkEntry+BlkEntry.LinkOffset);
  716. }
  717. else
  718. {
  719. pBlkEntry = 0;
  720. }
  721. }
  722. else
  723. {
  724. dprintf("RM %p\n",pBlkEntry);
  725. break;
  726. }
  727. }
  728. }
  729. else
  730. {
  731. dprintf("RM %p\n");
  732. }
  733. */
  734. void Print_HEAP_SUBSEGMENT( HEAP_SUBSEGMENT * pSubSeg_OOP,BOOL bHere)
  735. {
  736. HEAP_SUBSEGMENT HeapSubSeg;
  737. HEAP_SUBSEGMENT * pSubSegHERE = &HeapSubSeg;
  738. if (NULL == pSubSeg_OOP) return;
  739. if (bHere)
  740. {
  741. pSubSegHERE = pSubSeg_OOP;
  742. }
  743. else
  744. {
  745. if (!ReadMemory((ULONG_PTR)pSubSeg_OOP,&HeapSubSeg,sizeof(HeapSubSeg),0))
  746. {
  747. dprintf("RM %p\n",pSubSeg_OOP);
  748. return;
  749. }
  750. }
  751. dprintf(" - Bkt %p Blk %p D %04x F %04x S %08x\n",
  752. pSubSegHERE->Bucket,
  753. pSubSegHERE->UserBlocks,
  754. pSubSegHERE->AggregateExchg.Depth,
  755. pSubSegHERE->AggregateExchg.FreeEntryOffset,
  756. pSubSegHERE->AggregateExchg.Sequence);
  757. dprintf(" Bs %04x FT %04x BC %04x S %02x A %02x Lock %08x\n",
  758. pSubSegHERE->BlockSize,
  759. pSubSegHERE->FreeThreshold,
  760. pSubSegHERE->BlockCount,
  761. pSubSegHERE->SizeIndex,
  762. pSubSegHERE->AffinityIndex,
  763. pSubSegHERE->Lock);
  764. if (0 == pSubSegHERE->AggregateExchg.Depth) return;
  765. struct EntryTable : HEAP_ENTRY
  766. {
  767. ULONG_PTR vTable;
  768. } Entry;
  769. HEAP_ENTRY * pEntry_OOP = (HEAP_ENTRY *)((HEAP_USERDATA_HEADER *)pSubSegHERE->UserBlocks+1);
  770. DWORD Count = 0;
  771. do
  772. {
  773. if (ReadMemory((ULONG_PTR)pEntry_OOP,&Entry,sizeof(Entry),NULL))
  774. {
  775. dprintf(" %p: %04x . %04x [%02x] - (%x)\n",
  776. pEntry_OOP,1+pSubSegHERE->SizeIndex,0,
  777. Entry.Flags,
  778. (sizeof(HEAP_ENTRY))*( pSubSegHERE->BlockSize)-Entry.UnusedBytes);
  779. GetVTable(Entry.vTable);
  780. pEntry_OOP += ( pSubSegHERE->BlockSize );
  781. Count++;
  782. }
  783. else
  784. {
  785. dprintf("RM %p\n",pEntry_OOP);
  786. break;
  787. }
  788. } while(1 == Entry.SmallTagIndex && Count < pSubSegHERE->AggregateExchg.Depth);
  789. }
  790. DWORD EnumListCrtZone(VOID * pZone_OOP,
  791. VOID * pBlockZone)
  792. {
  793. LFH_BLOCK_ZONE CrtZone;
  794. LFH_BLOCK_ZONE * pBlockZone_OOP = (LFH_BLOCK_ZONE *)pZone_OOP;
  795. if (ReadMemory((ULONG_PTR)pBlockZone_OOP,&CrtZone,sizeof(CrtZone),NULL))
  796. {
  797. ULONG_PTR Size = (ULONG_PTR)CrtZone.FreePointer - (ULONG_PTR)pBlockZone_OOP;
  798. BYTE * pMem = (BYTE *)HeapAlloc(GetProcessHeap(),0,Size);
  799. if (pMem)
  800. {
  801. ULONG_PTR AddrCrtZone = (ULONG_PTR)pBlockZone_OOP;
  802. if (ReadMemory(AddrCrtZone,pMem,(ULONG)Size,NULL))
  803. {
  804. HEAP_SUBSEGMENT * pSubSeg = (HEAP_SUBSEGMENT *)((LFH_BLOCK_ZONE *)pMem + 1);
  805. HEAP_SUBSEGMENT * pSubSegEnd = (HEAP_SUBSEGMENT *)((BYTE *)pSubSeg+Size);
  806. HEAP_SUBSEGMENT * pSubSeg_OOP = (HEAP_SUBSEGMENT *)((LFH_BLOCK_ZONE *)AddrCrtZone+1);
  807. while (pSubSeg < pSubSegEnd )
  808. {
  809. //dprintf("SS - %p\n",pSubSeg_OOP);
  810. Print_HEAP_SUBSEGMENT(pSubSeg,TRUE);
  811. pSubSeg++;
  812. pSubSeg_OOP++;
  813. }
  814. }
  815. HeapFree(GetProcessHeap(),0,pMem);
  816. }
  817. }
  818. else
  819. {
  820. dprintf("RM %p\n",pBlockZone_OOP);
  821. }
  822. return 0;
  823. }
  824. void Print_LFH(LFH_HEAP * pLFH_OOP)
  825. {
  826. ULONG_PTR AddrAff = GetExpression("ntdll!RtlpHeapMaxAffinity");
  827. if (AddrAff)
  828. {
  829. ULONG Affinity = 0;
  830. if (ReadMemory(AddrAff,&Affinity,sizeof(Affinity),0))
  831. {
  832. ULONG_PTR SizeRead = sizeof(LFH_HEAP) + Affinity*sizeof(HEAP_LOCAL_DATA);
  833. LFH_HEAP * pLFH = (LFH_HEAP *)HeapAlloc(GetProcessHeap(),0,SizeRead);
  834. if (NULL == pLFH) return;
  835. if (ReadMemory((ULONG_PTR)pLFH_OOP,pLFH,(ULONG)SizeRead,0))
  836. {
  837. dprintf("LFH_HEAP %p\n",pLFH_OOP);
  838. LIST_ENTRY * pListHead_oop = &pLFH_OOP->SubSegmentZones;
  839. EnumLinkedListCB(pListHead_oop,
  840. sizeof(LFH_BLOCK_ZONE),
  841. FIELD_OFFSET(LFH_BLOCK_ZONE,ListEntry),
  842. EnumListCrtZone);
  843. /*
  844. for (DWORD i=0;i<HEAP_USER_ENTRIES;i++)
  845. {
  846. dprintf(" HEAP_USERDATA_HEADER - %d\n",i);
  847. HEAP_USERDATA_HEADER * pUsrDataHdr = (HEAP_USERDATA_HEADER *)pLFH->UserBlockCache.UserBlocks[i].Next.Next;
  848. dprintf(" Next %p Available %x\n",pUsrDataHdr,pLFH->UserBlockCache.AvailableBlocks[i]);
  849. HEAP_USERDATA_HEADER UsrDataHdr;
  850. UsrDataHdr.SFreeListEntry.Next = NULL;
  851. for (;pUsrDataHdr;pUsrDataHdr = (HEAP_USERDATA_HEADER *)UsrDataHdr.SFreeListEntry.Next)
  852. {
  853. if (ReadMemory((ULONG_PTR)pUsrDataHdr,&UsrDataHdr,sizeof(UsrDataHdr),NULL))
  854. {
  855. dprintf(" ----\n");
  856. dprintf(" Next %p\n",UsrDataHdr.SFreeListEntry.Next);
  857. dprintf(" HeapHandle %p\n",UsrDataHdr.HeapHandle);
  858. dprintf(" SizeIndex %p\n",UsrDataHdr.SizeIndex);
  859. dprintf(" Signature %p\n",UsrDataHdr.Signature);
  860. }
  861. else
  862. {
  863. dprintf("RM %p\n",pUsrDataHdr);
  864. }
  865. }
  866. }
  867. */
  868. //
  869. // Buckets
  870. //
  871. /*
  872. dprintf(" Buckets\n");
  873. dprintf(" # BUnt S A Conv TotBlk SubSegCnt\n");
  874. for (DWORD i = 0; i < HEAP_BUCKETS_COUNT; i++)
  875. {
  876. //+0x000 Counters : _HEAP_BUCKET
  877. dprintf(" %02x - %04x %02x %02x %p %08x %08x\n",
  878. i,
  879. pLFH->Buckets[i].BlockUnits,
  880. pLFH->Buckets[i].SizeIndex,
  881. pLFH->Buckets[i].UseAffinity,
  882. pLFH->Buckets[i].Conversions,
  883. pLFH->Buckets[i].Counters.TotalBlocks,
  884. pLFH->Buckets[i].Counters.SubSegmentCounts);
  885. }
  886. */
  887. for (DWORD i = 0; i <= Affinity; i++)
  888. {
  889. if (0 == i)
  890. dprintf(" HEAP_LOCAL_DATA - NO AFFINITY\n");
  891. else
  892. dprintf(" HEAP_LOCAL_DATA - AFFINITY %d\n",i-1);
  893. dprintf(" @ %p CrtZone %p LFHeap %p Affinity %x\n",
  894. (ULONG_PTR)pLFH_OOP + (ULONG_PTR)&pLFH->LocalData[i] - (ULONG_PTR)pLFH,
  895. pLFH->LocalData[i].CrtZone,
  896. pLFH->LocalData[i].LowFragHeap,
  897. pLFH->LocalData[i].Affinity);
  898. //Print_BLOCK_ZONE((LFH_BLOCK_ZONE *)pLFH->LocalData[i].CrtZone);
  899. HEAP_LOCAL_DATA * pLocData = &pLFH->LocalData[i];
  900. dprintf(" # Hint Active Next BusyEntries LastUsed\n");
  901. for (DWORD j=0;j<HEAP_BUCKETS_COUNT;j++)
  902. {
  903. dprintf(" %02x %p %p %p %08x %08x\n",
  904. j,
  905. pLocData->SegmentInfo[j].Hint,
  906. pLocData->SegmentInfo[j].ActiveSubsegment,
  907. pLocData->SegmentInfo[j].SListHeader, //.Next, //.next
  908. pLocData->SegmentInfo[j].BusyEntries,
  909. pLocData->SegmentInfo[j].LastUsed);
  910. //Print_HEAP_SUBSEGMENT(pLocData->SegmentInfo[j].Hint,FALSE);
  911. //Print_HEAP_SUBSEGMENT(pLocData->SegmentInfo[j].ActiveSubsegment,FALSE);
  912. }
  913. }
  914. }
  915. else
  916. {
  917. dprintf("RM %p\n",pLFH_OOP);
  918. }
  919. HeapFree(GetProcessHeap(),0,pLFH);
  920. }
  921. else
  922. {
  923. dprintf("RM %p\n",AddrAff);
  924. }
  925. }
  926. else
  927. {
  928. dprintf("unable to resolve ntdll!RtlpHeapMaxAffinity\n");
  929. }
  930. }
  931. DECLARE_API(lfhp)
  932. {
  933. INIT_API();
  934. MEMORY_ADDRESS Addr = GetExpression(args);
  935. if (NULL == Addr)
  936. {
  937. dprintf("unable to resolve %s\n",args);
  938. return;
  939. }
  940. DEFINE_CPP_VAR( HEAP, varHEAP);
  941. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  942. if (ReadMemory(Addr,pHeap ,sizeof(HEAP),NULL))
  943. {
  944. //dprintf("----- LookAside %p\n",pHeap->FrontEndHeap);
  945. //Dump_LookAside((ULONG_PTR)pHeap->FrontEndHeap);
  946. if (HEAP_FRONT_LOWFRAGHEAP == pHeap->FrontEndHeapType )
  947. {
  948. Print_LFH((LFH_HEAP*)pHeap->FrontEndHeap);
  949. }
  950. else
  951. {
  952. dprintf("Unrecognized FrontEndHeapType %d\n",pHeap->FrontEndHeapType);
  953. }
  954. }
  955. else
  956. {
  957. dprintf("RM %p\n",Addr);
  958. }
  959. }
  960. //
  961. //
  962. // dump the HEAP, incomplete
  963. //
  964. //
  965. DECLARE_API(hp)
  966. {
  967. INIT_API();
  968. g_UsedInHeap = 0;
  969. DEFINE_CPP_VAR( HEAP, varHEAP);
  970. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  971. MEMORY_ADDRESS pByte = GetExpression(args);
  972. DWORD i;
  973. if (pByte)
  974. {
  975. if (ReadMemory(pByte,pHeap ,sizeof(HEAP),NULL))
  976. {
  977. for (i=0;i<HEAP_MAXIMUM_SEGMENTS;i++)
  978. {
  979. if (pHeap->Segments[i])
  980. PrintHEAP_SEGMENT(pHeap->Segments[i],NULL,NULL);
  981. //dprintf(" seg %i - %p\n",i,pHeap->Segments[i]);
  982. }
  983. dprintf("Used Bytes %p\n",g_UsedInHeap);
  984. }
  985. else
  986. {
  987. dprintf("RM %p %d\n",pByte,GetLastError());
  988. }
  989. }
  990. else
  991. {
  992. dprintf("invalid address %s\n",args);
  993. }
  994. }
  995. //
  996. //
  997. //
  998. /////////////////////////////////////////////////////////////
  999. DWORD g_BlockSize;
  1000. ULONG_PTR * g_pBlockBlob;
  1001. ULONG g_NumMatch;
  1002. DWORD CallBackSearch(ULONG_PTR pHeapEntry_OOP,ULONG_PTR Addr)
  1003. {
  1004. if (!g_pBlockBlob)
  1005. {
  1006. dprintf("no GLOBAL search block\n");
  1007. return STATUS_NO_MEMORY;
  1008. }
  1009. HEAP_ENTRY Entry;
  1010. if (ReadMemory(pHeapEntry_OOP,&Entry,sizeof(HEAP_ENTRY),NULL))
  1011. {
  1012. HEAP_ENTRY * pEntry = (HEAP_ENTRY *)&Entry;
  1013. DWORD Size = (pEntry->Flags & HEAP_ENTRY_BUSY)?(pEntry->Size<<HEAP_GRANULARITY_SHIFT)-pEntry->UnusedBytes:0;
  1014. if (Size)
  1015. {
  1016. if (Size < g_BlockSize)
  1017. {
  1018. ULONG_PTR * pData = (ULONG_PTR *)g_pBlockBlob;
  1019. ReadMemory(pHeapEntry_OOP+sizeof(HEAP_ENTRY),pData,Size,NULL);
  1020. // here is the assumption that pointers are aligned
  1021. DWORD nTimes = Size/sizeof(ULONG_PTR);
  1022. DWORD i;
  1023. for (i=0;i<nTimes;i++)
  1024. {
  1025. if (Addr == pData[i])
  1026. {
  1027. dprintf("- %p off %p\n",pHeapEntry_OOP,sizeof(ULONG_PTR)*i);
  1028. PrintHeapEntry((HEAP_ENTRY *)pEntry,(void *)pHeapEntry_OOP);
  1029. g_NumMatch++;
  1030. }
  1031. }
  1032. }
  1033. else
  1034. {
  1035. dprintf(" entry %p too big\n",pHeapEntry_OOP);
  1036. }
  1037. }
  1038. }
  1039. else
  1040. {
  1041. dprintf("RM %p\n",pHeapEntry_OOP);
  1042. }
  1043. return 0;
  1044. }
  1045. //
  1046. //
  1047. // search the HEAP, incomplete
  1048. //
  1049. ///////////////////////////////////////////////
  1050. DECLARE_API(shp)
  1051. {
  1052. INIT_API();
  1053. DEFINE_CPP_VAR( HEAP, varHEAP);
  1054. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  1055. char * pArgs = (char *)args;
  1056. while(isspace(*pArgs)) pArgs++;
  1057. MEMORY_ADDRESS pByte = GetExpression(pArgs);
  1058. while(!isspace(*pArgs)) pArgs++;
  1059. MEMORY_ADDRESS Addr = GetExpression(pArgs);
  1060. DWORD i;
  1061. if (pByte && Addr)
  1062. {
  1063. g_BlockSize = 0x10000*sizeof(HEAP_ENTRY);
  1064. g_pBlockBlob = (ULONG_PTR *)VirtualAlloc(NULL,g_BlockSize,MEM_COMMIT,PAGE_READWRITE);
  1065. if (!g_pBlockBlob)
  1066. {
  1067. dprintf("VirtualAlloc err %d\n",GetLastError());
  1068. return;
  1069. }
  1070. if (ReadMemory(pByte,pHeap ,sizeof(HEAP),NULL))
  1071. {
  1072. g_NumMatch = 0;
  1073. for (i=0;i<HEAP_MAXIMUM_SEGMENTS;i++)
  1074. {
  1075. if (pHeap->Segments[i])
  1076. PrintHEAP_SEGMENT(pHeap->Segments[i],CallBackSearch,(ULONG_PTR)Addr);
  1077. // dprintf(" seg %i - %p\n",i,pHeap->Segments[i]);
  1078. }
  1079. dprintf("%d matches found\n",g_NumMatch);
  1080. }
  1081. else
  1082. {
  1083. dprintf("RM %p %d\n",pByte,GetLastError());
  1084. }
  1085. if (g_pBlockBlob)
  1086. {
  1087. VirtualFree(g_pBlockBlob,0,MEM_RELEASE);
  1088. g_pBlockBlob = NULL;
  1089. g_BlockSize = 0;
  1090. }
  1091. }
  1092. else
  1093. {
  1094. dprintf("invalid heap address pair in%s\n",args);
  1095. }
  1096. }
  1097. //
  1098. // decode heap flags
  1099. //
  1100. /*
  1101. #define HEAP_NO_SERIALIZE 0x00000001 // winnt
  1102. #define HEAP_GROWABLE 0x00000002 // winnt
  1103. #define HEAP_GENERATE_EXCEPTIONS 0x00000004 // winnt
  1104. #define HEAP_ZERO_MEMORY 0x00000008 // winnt
  1105. #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 // winnt
  1106. #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 // winnt
  1107. #define HEAP_FREE_CHECKING_ENABLED 0x00000040 // winnt
  1108. #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 // winnt
  1109. #define HEAP_SETTABLE_USER_VALUE 0x00000100
  1110. #define HEAP_SETTABLE_USER_FLAG1 0x00000200
  1111. #define HEAP_SETTABLE_USER_FLAG2 0x00000400
  1112. #define HEAP_SETTABLE_USER_FLAG3 0x00000800
  1113. #define HEAP_CLASS_0 0x00000000 // process heap
  1114. #define HEAP_CLASS_1 0x00001000 // private heap
  1115. #define HEAP_CLASS_2 0x00002000 // Kernel Heap
  1116. #define HEAP_CLASS_3 0x00003000 // GDI heap
  1117. #define HEAP_CLASS_4 0x00004000 // User heap
  1118. #define HEAP_CLASS_5 0x00005000 // Console heap
  1119. #define HEAP_CLASS_6 0x00006000 // User Desktop heap
  1120. #define HEAP_CLASS_7 0x00007000 // Csrss Shared heap
  1121. #define HEAP_CLASS_8 0x00008000 // Csr Port heap
  1122. */
  1123. #define HEAP_LOCK_USER_ALLOCATED (ULONG)0x80000000
  1124. #define HEAP_VALIDATE_PARAMETERS_ENABLED (ULONG)0x40000000
  1125. #define HEAP_VALIDATE_ALL_ENABLED (ULONG)0x20000000
  1126. #define HEAP_SKIP_VALIDATION_CHECKS (ULONG)0x10000000
  1127. #define HEAP_CAPTURE_STACK_BACKTRACES (ULONG)0x08000000
  1128. #define HEAP_FLAG_PAGE_ALLOCS 0x01000000
  1129. #define HEAP_PROTECTION_ENABLED 0x02000000
  1130. #define HEAP_BREAK_WHEN_OUT_OF_VM 0x04000000
  1131. #define HEAP_NO_ALIGNMENT 0x08000000
  1132. void DecodeFlags(ULONG Flags)
  1133. {
  1134. dprintf(" Flags: %08x ",Flags);
  1135. if (Flags & HEAP_NO_SERIALIZE)
  1136. dprintf("HEAP_NO_SERIALIZE ");
  1137. if (Flags & HEAP_GROWABLE)
  1138. dprintf("HEAP_GROWABLE ");
  1139. if (Flags & HEAP_GENERATE_EXCEPTIONS)
  1140. dprintf("HEAP_GENERATE_EXCEPTIONS ");
  1141. if (Flags & HEAP_ZERO_MEMORY)
  1142. dprintf("HEAP_ZERO_MEMORY ");
  1143. if (Flags & HEAP_REALLOC_IN_PLACE_ONLY)
  1144. dprintf("HEAP_REALLOC_IN_PLACE_ONLY ");
  1145. if (Flags & HEAP_TAIL_CHECKING_ENABLED)
  1146. dprintf("HEAP_TAIL_CHECKING_ENABLED ");
  1147. if (Flags & HEAP_FREE_CHECKING_ENABLED)
  1148. dprintf("HEAP_FREE_CHECKING_ENABLED ");
  1149. if (Flags & HEAP_DISABLE_COALESCE_ON_FREE)
  1150. dprintf("HEAP_DISABLE_COALESCE_ON_FREE ");
  1151. if (Flags & HEAP_SETTABLE_USER_VALUE)
  1152. dprintf("HEAP_SETTABLE_USER_VALUE ");
  1153. if (Flags & HEAP_SETTABLE_USER_FLAG1)
  1154. dprintf("HEAP_SETTABLE_USER_FLAG1 ");
  1155. if (Flags & HEAP_SETTABLE_USER_FLAG2)
  1156. dprintf("HEAP_SETTABLE_USER_FLAG2 ");
  1157. if (Flags & HEAP_SETTABLE_USER_FLAG3)
  1158. dprintf("HEAP_SETTABLE_USER_FLAG3 ");
  1159. if (Flags & HEAP_CLASS_MASK)
  1160. dprintf("HEAP_CLASS %d",(Flags&HEAP_CLASS_MASK)>>12);
  1161. /*
  1162. if (Flags & HEAP_CLASS_1)
  1163. dprintf("HEAP_CLASS_1 ");
  1164. if (Flags & HEAP_CLASS_2)
  1165. dprintf("HEAP_CLASS_2 ");
  1166. if (Flags & HEAP_CLASS_3)
  1167. dprintf("HEAP_CLASS_3 ");
  1168. if (Flags & HEAP_CLASS_4)
  1169. dprintf("HEAP_CLASS_4 ");
  1170. if (Flags & HEAP_CLASS_5)
  1171. dprintf("HEAP_CLASS_5 ");
  1172. if (Flags & HEAP_CLASS_6)
  1173. dprintf("HEAP_CLASS_6 ");
  1174. if (Flags & HEAP_CLASS_7)
  1175. dprintf("HEAP_CLASS_7 ");
  1176. */
  1177. //if (Flags & HEAP_CAPTURE_STACK_BACKTRACES)
  1178. // dprintf("HEAP_CAPTURE_STACK_BACKTRACES ");
  1179. if (Flags &HEAP_SKIP_VALIDATION_CHECKS)
  1180. dprintf("HEAP_SKIP_VALIDATION_CHECKS ");
  1181. if (Flags &HEAP_VALIDATE_ALL_ENABLED)
  1182. dprintf("HEAP_VALIDATE_ALL_ENABLED ");
  1183. if (Flags &HEAP_VALIDATE_PARAMETERS_ENABLED)
  1184. dprintf("HEAP_VALIDATE_PARAMETERS_ENABLED ");
  1185. if (Flags &HEAP_LOCK_USER_ALLOCATED)
  1186. dprintf("HEAP_LOCK_USER_ALLOCATED ");
  1187. if (Flags &HEAP_FLAG_PAGE_ALLOCS)
  1188. dprintf("HEAP_FLAG_PAGE_ALLOCS ");
  1189. if (Flags &HEAP_PROTECTION_ENABLED)
  1190. dprintf("HEAP_PROTECTION_ENABLED ");
  1191. if (Flags &HEAP_BREAK_WHEN_OUT_OF_VM)
  1192. dprintf("HEAP_BREAK_WHEN_OUT_OF_VM ");
  1193. if (Flags &HEAP_NO_ALIGNMENT)
  1194. dprintf("HEAP_NO_ALIGNMENT ");
  1195. //if (Flags &)
  1196. // dprintf(" ");
  1197. dprintf("\n");
  1198. }
  1199. //
  1200. // Get all the heaps
  1201. //
  1202. DECLARE_API(hps)
  1203. {
  1204. INIT_API();
  1205. PEB * pPeb = NULL;
  1206. PEB ThisPeb;
  1207. GetPeb(hCurrentProcess,&pPeb);
  1208. if(!pPeb)
  1209. {
  1210. #ifdef _WIN64
  1211. pPeb = (PEB *)0x6fbfffde000;
  1212. #else
  1213. pPeb = (PEB *)0x7ffdf000;
  1214. #endif
  1215. }
  1216. if (pPeb)
  1217. {
  1218. ReadMemory((MEMORY_ADDRESS)pPeb,&ThisPeb,sizeof(PEB),0);
  1219. void ** pHeaps = (void**)_alloca(ThisPeb.NumberOfHeaps*sizeof(void*));
  1220. DWORD i,j;
  1221. ULONG_PTR TotCommitSize = 0;
  1222. ULONG_PTR TotVirtSize = 0;
  1223. if (ReadMemory((MEMORY_ADDRESS)ThisPeb.ProcessHeaps,pHeaps,ThisPeb.NumberOfHeaps*sizeof(void*),0))
  1224. {
  1225. for(i=0;i<ThisPeb.NumberOfHeaps;i++)
  1226. {
  1227. DEFINE_CPP_VAR( HEAP, varHEAP);
  1228. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  1229. ULONG_PTR TotHeapCommitSize = 0;
  1230. ULONG_PTR TotHeapVirtSize = 0;
  1231. if (ReadMemory((MEMORY_ADDRESS)pHeaps[i],pHeap ,sizeof(HEAP),0))
  1232. {
  1233. for (j=0;j<HEAP_MAXIMUM_SEGMENTS;j++)
  1234. {
  1235. if (pHeap->Segments[j])
  1236. {
  1237. DEFINE_CPP_VAR( HEAP_SEGMENT, varHEAP_SEGMENT);
  1238. HEAP_SEGMENT * pHeapSeg = GET_CPP_VAR_PTR( HEAP_SEGMENT , varHEAP_SEGMENT );
  1239. if (ReadMemory((MEMORY_ADDRESS)pHeap->Segments[j],pHeapSeg,sizeof(HEAP_SEGMENT),0))
  1240. {
  1241. dprintf(" - %p (C %p - R %p)\n",
  1242. pHeap->Segments[j],
  1243. (pHeapSeg->NumberOfPages - pHeapSeg->NumberOfUnCommittedPages) * PAGE_SIZE,
  1244. (pHeapSeg->NumberOfPages) * PAGE_SIZE);
  1245. TotHeapCommitSize += ((pHeapSeg->NumberOfPages - pHeapSeg->NumberOfUnCommittedPages) * PAGE_SIZE);
  1246. TotHeapVirtSize += ((pHeapSeg->NumberOfPages) * PAGE_SIZE);
  1247. // now print the beggining of a committed range
  1248. dprintf(" CR %p\n",pHeapSeg->BaseAddress);
  1249. HEAP_UNCOMMMTTED_RANGE * pUncomm_OOP = pHeapSeg->UnCommittedRanges;
  1250. for (DWORD i=0;i<pHeapSeg->NumberOfUnCommittedRanges && pUncomm_OOP;i++)
  1251. {
  1252. HEAP_UNCOMMMTTED_RANGE UncommRange;
  1253. if (ReadMemory((MEMORY_ADDRESS)pUncomm_OOP,&UncommRange,sizeof(HEAP_UNCOMMMTTED_RANGE),NULL))
  1254. {
  1255. if (UncommRange.Next)
  1256. {
  1257. pUncomm_OOP = UncommRange.Next;
  1258. }
  1259. ULONG_PTR RangeAddr = (ULONG_PTR)UncommRange.Address+UncommRange.Size;
  1260. if (RangeAddr != (ULONG_PTR)pHeapSeg->LastEntryInSegment)
  1261. dprintf(" CR %p\n",RangeAddr);
  1262. }
  1263. else
  1264. {
  1265. dprintf("RM %p\n",pHeapSeg->UnCommittedRanges);
  1266. break;
  1267. }
  1268. }
  1269. }
  1270. else
  1271. {
  1272. dprintf("RM %p\n",pHeap->Segments[j]);
  1273. }
  1274. }
  1275. }
  1276. }
  1277. else
  1278. {
  1279. dprintf("RM %p\n",pHeaps[i]);
  1280. pHeap = NULL;
  1281. }
  1282. dprintf(" HEAP %p - %p\n",pHeaps[i],TotHeapCommitSize);
  1283. if (pHeap)
  1284. {
  1285. DecodeFlags(pHeap->Flags|pHeap->ForceFlags);
  1286. dprintf(" FrontEndHeapType %d\n",pHeap->FrontEndHeapType);
  1287. }
  1288. TotCommitSize += TotHeapCommitSize;
  1289. TotVirtSize += TotHeapVirtSize;
  1290. }
  1291. dprintf(" -- Tot C %p Tot R %p\n",TotCommitSize, TotVirtSize);
  1292. }
  1293. else
  1294. {
  1295. dprintf("RM %p\n",ThisPeb.ProcessHeaps);
  1296. }
  1297. }
  1298. else
  1299. {
  1300. dprintf("unable to get PEB\n");
  1301. }
  1302. }
  1303. //
  1304. // reverse heap free list
  1305. //
  1306. //////////////////
  1307. DWORD
  1308. CallBackFreeList(VOID * pStructure_OOP,
  1309. VOID * pLocalCopy)
  1310. {
  1311. HEAP_FREE_ENTRY * pFreeEntry = (HEAP_FREE_ENTRY *)pLocalCopy;
  1312. dprintf(" %p (%p,%p): %04x - %04x [%02x] %02x %02x (%x)\n",
  1313. pStructure_OOP,
  1314. pFreeEntry->FreeList.Flink,
  1315. pFreeEntry->FreeList.Blink,
  1316. pFreeEntry->Size,
  1317. pFreeEntry->PreviousSize,
  1318. pFreeEntry->Flags,
  1319. pFreeEntry->Index,
  1320. pFreeEntry->Mask,
  1321. pFreeEntry->Size*sizeof(HEAP_ENTRY));
  1322. return 0;
  1323. }
  1324. DECLARE_API( rllc )
  1325. {
  1326. INIT_API();
  1327. MEMORY_ADDRESS Addr = GetExpression(args);
  1328. if (Addr)
  1329. {
  1330. EnumReverseLinkedListCB((LIST_ENTRY *)Addr,
  1331. sizeof(HEAP_FREE_ENTRY),
  1332. FIELD_OFFSET(HEAP_FREE_ENTRY,FreeList),
  1333. CallBackFreeList);
  1334. }
  1335. else
  1336. {
  1337. dprintf("cannot resolve %s\n",args);
  1338. }
  1339. }
  1340. //
  1341. //
  1342. // Print the Free Lists of the Heap
  1343. //
  1344. /////////////////////////////////////////////////
  1345. DWORD
  1346. CallBackFreeList2(VOID * pStructure_OOP,
  1347. VOID * pLocalCopy)
  1348. {
  1349. HEAP_FREE_ENTRY * pFreeEntry = (HEAP_FREE_ENTRY *)pLocalCopy;
  1350. dprintf(" %p (%p,%p): %04x - %04x [%02x] %02x %02x (%x)",
  1351. pStructure_OOP,
  1352. pFreeEntry->FreeList.Flink,
  1353. pFreeEntry->FreeList.Blink,
  1354. pFreeEntry->Size,
  1355. pFreeEntry->PreviousSize,
  1356. pFreeEntry->Flags,
  1357. pFreeEntry->Index,
  1358. pFreeEntry->Mask,
  1359. pFreeEntry->Size*sizeof(HEAP_ENTRY));
  1360. MEMORY_ADDRESS pEntry = (MEMORY_ADDRESS)pStructure_OOP;
  1361. HEAP_ENTRY HeapEntry;
  1362. ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0);
  1363. while (HeapEntry.PreviousSize)
  1364. {
  1365. pEntry = (MEMORY_ADDRESS)((HEAP_ENTRY*)pEntry - HeapEntry.PreviousSize);
  1366. if (ReadMemory((MEMORY_ADDRESS)pEntry,&HeapEntry,sizeof(HeapEntry),0))
  1367. {
  1368. }
  1369. else
  1370. {
  1371. dprintf("RM %p\n",pEntry);
  1372. break;
  1373. }
  1374. if (CheckControlC())
  1375. break;
  1376. }
  1377. dprintf(" -B %p\n",pEntry);
  1378. return 0;
  1379. }
  1380. #define EmptyFull( expr ) (( expr )?'F':'-')
  1381. DECLARE_API( hpf )
  1382. {
  1383. INIT_API();
  1384. DEFINE_CPP_VAR( HEAP, varHEAP);
  1385. HEAP * pHeap = GET_CPP_VAR_PTR( HEAP , varHEAP );
  1386. MEMORY_ADDRESS pByte = GetExpression(args);
  1387. if (pByte)
  1388. {
  1389. if (ReadMemory(pByte,pHeap ,sizeof(HEAP),NULL))
  1390. {
  1391. dprintf(" -- 00 01 02 03 04 05 06 07\n");
  1392. DWORD nBytes = HEAP_MAXIMUM_FREELISTS / 8 ;
  1393. for (DWORD i=0;i<nBytes;i++)
  1394. {
  1395. BYTE Set = pHeap->u.FreeListsInUseBytes[i];
  1396. dprintf(" %02x : %c %c %c %c %c %c %c %c\n",8*i,
  1397. EmptyFull(Set & 0x01),EmptyFull(Set & 0x02),EmptyFull(Set & 0x04),EmptyFull(Set & 0x08),
  1398. EmptyFull(Set & 0x10),EmptyFull(Set & 0x20),EmptyFull(Set & 0x40),EmptyFull(Set & 0x80));
  1399. }
  1400. dprintf(" ------------\n");
  1401. HEAP * pHeap_OOP = (HEAP *)pByte;
  1402. for (DWORD i=0;i<HEAP_MAXIMUM_FREELISTS;i++)
  1403. {
  1404. dprintf(" FreeList[%x] @ %p\n",i,&pHeap_OOP->FreeLists[i]);
  1405. EnumReverseLinkedListCB((LIST_ENTRY *)&pHeap_OOP->FreeLists[i],
  1406. sizeof(HEAP_FREE_ENTRY),
  1407. FIELD_OFFSET(HEAP_FREE_ENTRY,FreeList),
  1408. CallBackFreeList2);
  1409. }
  1410. }
  1411. else
  1412. {
  1413. dprintf("RM %p\n",pByte);
  1414. }
  1415. }
  1416. else
  1417. {
  1418. dprintf("invalid address %s\n",args);
  1419. }
  1420. }
  1421. //
  1422. // dumps the DPH_HEAP_ROOT
  1423. //
  1424. ///////////////////////////////////////
  1425. DECLARE_API( php )
  1426. {
  1427. INIT_API();
  1428. char * pHeapAddr = (char *)args;
  1429. while (isspace(*pHeapAddr)) pHeapAddr++;
  1430. char * pNext = pHeapAddr;
  1431. while (!isspace(*pNext)) pNext++; // skipt the Heap Addr
  1432. if (*pNext)
  1433. {
  1434. *pNext = 0;
  1435. pNext++;
  1436. }
  1437. MEMORY_ADDRESS Addr = GetExpression(pHeapAddr);
  1438. while (isspace(*pNext)) pNext++; // skip the other spaces
  1439. MEMORY_ADDRESS SearchAddr = 0;
  1440. if (*pNext == 's' ||*pNext == 'S')
  1441. {
  1442. pNext++; // skip the 's'
  1443. if (*pNext)
  1444. {
  1445. while(isspace(*pNext)) pNext++; // skip the spaces
  1446. SearchAddr = GetExpression(pNext);
  1447. }
  1448. }
  1449. //dprintf("heap %p addr %p\n",Addr,SearchAddr);
  1450. if (Addr)
  1451. {
  1452. g_BlockSize = 0x10000*sizeof(HEAP_ENTRY);
  1453. g_pBlockBlob = NULL;
  1454. if (SearchAddr)
  1455. g_pBlockBlob = (ULONG_PTR *)VirtualAlloc(NULL,g_BlockSize,MEM_COMMIT,PAGE_READWRITE);
  1456. if (SearchAddr && !g_pBlockBlob)
  1457. {
  1458. dprintf("VirtualAlloc err %d\n",GetLastError());
  1459. return;
  1460. }
  1461. HEAP Heap;
  1462. DPH_HEAP_ROOT HeapPage;
  1463. if (0 == SearchAddr)
  1464. dprintf(" HEAP @ %p\n",Addr);
  1465. if (ReadMemory((MEMORY_ADDRESS)Addr,&Heap,sizeof(HEAP),NULL))
  1466. {
  1467. if (Heap.ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
  1468. {
  1469. Addr += PAGE_SIZE;
  1470. dprintf(" DPH_HEAP_ROOT @ %p\n",Addr);
  1471. if (ReadMemory((MEMORY_ADDRESS)Addr,&HeapPage,sizeof(DPH_HEAP_ROOT),NULL))
  1472. {
  1473. DPH_HEAP_BLOCK HeapBlock;
  1474. DPH_HEAP_BLOCK * pNextBlock;
  1475. if (0 == SearchAddr)
  1476. {
  1477. pNextBlock = HeapPage.pVirtualStorageListHead;
  1478. dprintf(" - pVirtualStorageListHead\n");
  1479. while(pNextBlock)
  1480. {
  1481. if (ReadMemory((MEMORY_ADDRESS)pNextBlock,&HeapBlock,sizeof(DPH_HEAP_BLOCK),NULL))
  1482. {
  1483. dprintf(" %p - (%p) B %p S %p \n",
  1484. pNextBlock,
  1485. HeapBlock.pNextAlloc,
  1486. HeapBlock.pVirtualBlock,
  1487. HeapBlock.nVirtualBlockSize);
  1488. pNextBlock = HeapBlock.pNextAlloc;
  1489. }
  1490. else
  1491. {
  1492. pNextBlock = NULL;
  1493. }
  1494. }
  1495. }
  1496. pNextBlock = HeapPage.pBusyAllocationListHead;
  1497. if (0 == SearchAddr)
  1498. dprintf(" - pBusyAllocationListHead\n");
  1499. while(pNextBlock)
  1500. {
  1501. if (ReadMemory((MEMORY_ADDRESS)pNextBlock,&HeapBlock,sizeof(DPH_HEAP_BLOCK),NULL))
  1502. {
  1503. if (0 == SearchAddr)
  1504. {
  1505. dprintf(" %p - (%p) %x %x %x U %p S %p\n",
  1506. pNextBlock,
  1507. HeapBlock.pNextAlloc,
  1508. ULONG_PTR(HeapBlock.pVirtualBlock)/PAGE_SIZE,
  1509. HeapBlock.nVirtualBlockSize/PAGE_SIZE,
  1510. HeapBlock.nVirtualAccessSize/PAGE_SIZE,
  1511. HeapBlock.pUserAllocation,
  1512. HeapBlock.StackTrace_);
  1513. GetVTable((MEMORY_ADDRESS)HeapBlock.pUserAllocation+sizeof(DPH_BLOCK_INFORMATION));
  1514. }
  1515. else // do the real search
  1516. {
  1517. MEMORY_ADDRESS Size = (MEMORY_ADDRESS)HeapBlock.pVirtualBlock+HeapBlock.nVirtualAccessSize-(MEMORY_ADDRESS)HeapBlock.pUserAllocation;
  1518. if (ReadMemory((MEMORY_ADDRESS)HeapBlock.pUserAllocation,g_pBlockBlob,(ULONG)Size,NULL))
  1519. {
  1520. Size /= sizeof(ULONG_PTR);
  1521. BOOL bFound = FALSE;
  1522. for (ULONG_PTR j =0;j<Size;j++)
  1523. {
  1524. if (SearchAddr == g_pBlockBlob[j])
  1525. {
  1526. bFound = TRUE;
  1527. dprintf(" OFF %p\n",j*sizeof(ULONG_PTR));
  1528. }
  1529. }
  1530. if (bFound)
  1531. {
  1532. dprintf(" B %p\n",HeapBlock.pUserAllocation);
  1533. }
  1534. }
  1535. else
  1536. {
  1537. dprintf("RM %p\n",HeapBlock.pUserAllocation);
  1538. }
  1539. }
  1540. pNextBlock = HeapBlock.pNextAlloc;
  1541. }
  1542. else
  1543. {
  1544. pNextBlock = NULL;
  1545. }
  1546. }
  1547. if (0 == SearchAddr)
  1548. {
  1549. pNextBlock = HeapPage.pFreeAllocationListHead;
  1550. dprintf(" - pFreeAllocationListHead\n");
  1551. while(pNextBlock)
  1552. {
  1553. if (ReadMemory((MEMORY_ADDRESS)pNextBlock,&HeapBlock,sizeof(DPH_HEAP_BLOCK),NULL))
  1554. {
  1555. dprintf(" %p - (%p) %x %x %x U %p S %p\n",
  1556. pNextBlock,
  1557. HeapBlock.pNextAlloc,
  1558. ULONG_PTR(HeapBlock.pVirtualBlock)/PAGE_SIZE,
  1559. HeapBlock.nVirtualBlockSize/PAGE_SIZE,
  1560. HeapBlock.nVirtualAccessSize/PAGE_SIZE,
  1561. HeapBlock.pUserAllocation,
  1562. HeapBlock.StackTrace_);
  1563. pNextBlock = HeapBlock.pNextAlloc;
  1564. }
  1565. else
  1566. {
  1567. pNextBlock = NULL;
  1568. }
  1569. }
  1570. }
  1571. if (0 == SearchAddr)
  1572. {
  1573. pNextBlock = HeapPage.pAvailableAllocationListHead;
  1574. dprintf(" - pAvailableAllocationListHead\n");
  1575. while(pNextBlock)
  1576. {
  1577. if (ReadMemory((MEMORY_ADDRESS)pNextBlock,&HeapBlock,sizeof(DPH_HEAP_BLOCK),NULL))
  1578. {
  1579. dprintf(" %p - (%p) B %p S %p \n",
  1580. pNextBlock,
  1581. HeapBlock.pNextAlloc,
  1582. HeapBlock.pVirtualBlock,
  1583. HeapBlock.nVirtualBlockSize);
  1584. pNextBlock = HeapBlock.pNextAlloc;
  1585. }
  1586. else
  1587. {
  1588. pNextBlock = NULL;
  1589. }
  1590. }
  1591. }
  1592. if (0 == SearchAddr)
  1593. {
  1594. pNextBlock = HeapPage.pNodePoolListHead;
  1595. dprintf(" - pNodePoolListHead\n");
  1596. while(pNextBlock)
  1597. {
  1598. if (ReadMemory((MEMORY_ADDRESS)pNextBlock,&HeapBlock,sizeof(DPH_HEAP_BLOCK),NULL))
  1599. {
  1600. dprintf(" %p - (%p) B %p S %p \n",
  1601. pNextBlock,
  1602. HeapBlock.pNextAlloc,
  1603. HeapBlock.pVirtualBlock,
  1604. HeapBlock.nVirtualBlockSize);
  1605. pNextBlock = HeapBlock.pNextAlloc;
  1606. }
  1607. else
  1608. {
  1609. pNextBlock = NULL;
  1610. }
  1611. }
  1612. }
  1613. dprintf(" NormalHeap @ %p\n",HeapPage.NormalHeap);
  1614. if (ReadMemory((ULONG_PTR)HeapPage.NormalHeap,&Heap ,sizeof(HEAP),NULL))
  1615. {
  1616. for (DWORD h=0;h<HEAP_MAXIMUM_SEGMENTS;h++)
  1617. {
  1618. if (Heap.Segments[h])
  1619. {
  1620. if (SearchAddr)
  1621. PrintHEAP_SEGMENT(Heap.Segments[h],CallBackSearch,(ULONG_PTR)SearchAddr);
  1622. else
  1623. PrintHEAP_SEGMENT(Heap.Segments[h],NULL,NULL);
  1624. }
  1625. }
  1626. }
  1627. else
  1628. {
  1629. dprintf("RM %p\n",HeapPage.NormalHeap);
  1630. }
  1631. }
  1632. else
  1633. {
  1634. dprintf("RM %p\n",Addr);
  1635. }
  1636. }
  1637. else
  1638. {
  1639. DecodeFlags(Heap.ForceFlags|Heap.Flags);
  1640. }
  1641. }
  1642. else
  1643. {
  1644. dprintf("RM %p\n",Addr);
  1645. }
  1646. if (g_pBlockBlob)
  1647. {
  1648. VirtualFree(g_pBlockBlob,g_BlockSize,MEM_RELEASE);
  1649. g_pBlockBlob = NULL;
  1650. g_BlockSize = 0;
  1651. }
  1652. }
  1653. else
  1654. {
  1655. dprintf("unable to resolve %s\n",args);
  1656. }
  1657. }
  1658. //
  1659. //
  1660. // virtual_query helper
  1661. //
  1662. ///////////////////////////////////////////////////////////////
  1663. char * GetState(DWORD State)
  1664. {
  1665. switch(State)
  1666. {
  1667. case MEM_COMMIT:
  1668. return "MEM_COMMIT";
  1669. case MEM_RESERVE:
  1670. return "MEM_RESERVE";
  1671. case MEM_FREE:
  1672. return "MEM_FREE";
  1673. };
  1674. return "";
  1675. }
  1676. char * GetType(DWORD Type)
  1677. {
  1678. switch(Type)
  1679. {
  1680. case MEM_IMAGE:
  1681. return "MEM_IMAGE";
  1682. case MEM_MAPPED:
  1683. return "MEM_MAPPED";
  1684. case MEM_PRIVATE:
  1685. return "MEM_PRIVATE";
  1686. }
  1687. return "";
  1688. }
  1689. char * GetProtect(DWORD Protect)
  1690. {
  1691. switch(Protect)
  1692. {
  1693. case PAGE_NOACCESS:
  1694. return "PAGE_NOACCESS";
  1695. case PAGE_READONLY:
  1696. return "PAGE_READONLY";
  1697. case PAGE_READWRITE:
  1698. return "PAGE_READWRITE";
  1699. case PAGE_WRITECOPY:
  1700. return "PAGE_WRITECOPY";
  1701. case PAGE_EXECUTE:
  1702. return "PAGE_EXECUTE";
  1703. case PAGE_EXECUTE_READ:
  1704. return "PAGE_EXECUTE_READ";
  1705. case PAGE_EXECUTE_READWRITE:
  1706. return "PAGE_EXECUTE_READWRITE";
  1707. case PAGE_EXECUTE_WRITECOPY:
  1708. return "PAGE_EXECUTE_WRITECOPY";
  1709. case PAGE_GUARD:
  1710. return "PAGE_GUARD";
  1711. case PAGE_NOCACHE:
  1712. return "PAGE_NOCACHE";
  1713. case PAGE_WRITECOMBINE:
  1714. return "PAGE_WRITECOMBINE";
  1715. }
  1716. return "<unk>";
  1717. }
  1718. //
  1719. //
  1720. // VirtualQueryEx
  1721. //
  1722. //
  1723. // vq -a address
  1724. // vq -f filter <all address space>
  1725. //
  1726. ///////////////////////////////////////////
  1727. DECLARE_API(vq)
  1728. {
  1729. INIT_API();
  1730. MEMORY_ADDRESS pVA = 0;
  1731. MEMORY_ADDRESS Filter = (MEMORY_ADDRESS)-1;
  1732. DWORD FilterSize = 0;
  1733. BOOL bAll = TRUE;
  1734. char * pCurrent = (char *)args;
  1735. if(0 < strlen(pCurrent))
  1736. {
  1737. while (isspace(*pCurrent)) pCurrent++;
  1738. if ('-' == *pCurrent ||
  1739. '/' == *pCurrent)
  1740. {
  1741. pCurrent++;
  1742. while (isspace(*pCurrent)) pCurrent++;
  1743. if ('a' == *pCurrent)
  1744. {
  1745. pCurrent++;
  1746. while (*pCurrent && isspace(*pCurrent)) pCurrent++;
  1747. pVA = GetExpression(pCurrent);
  1748. bAll = FALSE;
  1749. }
  1750. else if ('f' == *pCurrent)
  1751. {
  1752. pCurrent++;
  1753. while (*pCurrent && isspace(*pCurrent)) pCurrent++;
  1754. Filter = GetExpression(pCurrent);
  1755. dprintf("FILTER %08x\n",Filter);
  1756. }
  1757. else if ('s' == *pCurrent)
  1758. {
  1759. pCurrent++;
  1760. while (*pCurrent && isspace(*pCurrent)) pCurrent++;
  1761. FilterSize = (DWORD)GetExpression(pCurrent);
  1762. dprintf("Size %08x\n",FilterSize);
  1763. }
  1764. else
  1765. {
  1766. dprintf("usage: -a ADDR\n"
  1767. "usage: -F Filter <all address space>\n");
  1768. }
  1769. }
  1770. }
  1771. else
  1772. {
  1773. dprintf("no param\n");
  1774. }
  1775. ULONG_PTR Tot = 0;
  1776. MEMORY_BASIC_INFORMATION MemInfo;
  1777. SIZE_T dwRet = 0;
  1778. do
  1779. {
  1780. dwRet = VirtualQueryEx(hCurrentProcess,(LPCVOID)pVA,&MemInfo,sizeof(MemInfo));
  1781. if (dwRet &&
  1782. (MemInfo.AllocationProtect & Filter) &&
  1783. (MemInfo.RegionSize > FilterSize))
  1784. {
  1785. dprintf(" Base %p Size %p Alloc %p Prot %s %s %s %s\n",
  1786. MemInfo.BaseAddress,
  1787. MemInfo.RegionSize,
  1788. MemInfo.AllocationBase,
  1789. GetProtect(MemInfo.AllocationProtect),
  1790. GetState(MemInfo.State),
  1791. GetProtect(MemInfo.Protect),
  1792. GetType(MemInfo.Type));
  1793. Tot += MemInfo.RegionSize;
  1794. }
  1795. pVA = (ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize;
  1796. if (CheckControlC())
  1797. break;
  1798. } while (dwRet && bAll);
  1799. dprintf(" Total %p\n",Tot);
  1800. }
  1801. //
  1802. //
  1803. //
  1804. //
  1805. #ifdef KDEXT_64BIT
  1806. struct _HEAP_ENTRY_64
  1807. {
  1808. WORD Size ;
  1809. WORD PreviousSize ;
  1810. BYTE SegmentIndex ;
  1811. BYTE Flags ;
  1812. BYTE UnusedBytes ;
  1813. BYTE SmallTagIndex;
  1814. ULONG64 Pointer;
  1815. };
  1816. #endif /*KDEXT_64BIT*/
  1817. DECLARE_API(hef64)
  1818. {
  1819. INIT_API();
  1820. #ifdef KDEXT_64BIT
  1821. _HEAP_ENTRY_64 HeapEntry;
  1822. ULONG64 MemAddr = GetExpression(args);
  1823. ULONG64 pVTable = 0;
  1824. if (MemAddr)
  1825. {
  1826. if (ReadMemory(MemAddr,&HeapEntry,sizeof(HeapEntry),NULL))
  1827. {
  1828. dprintf(" %p: %04x - %04x [%02x] (%x)\n",MemAddr,HeapEntry.Size,HeapEntry.PreviousSize,HeapEntry.Flags,HeapEntry.Size*sizeof(_HEAP_ENTRY_64)-HeapEntry.UnusedBytes);
  1829. GetVTable(MemAddr + sizeof(_HEAP_ENTRY_64));
  1830. MemAddr = MemAddr+HeapEntry.Size*sizeof(_HEAP_ENTRY_64);
  1831. // 0x10 is LAST_ENTRY
  1832. while(!(HeapEntry.Flags & 0x10))
  1833. {
  1834. if (ReadMemory(MemAddr,&HeapEntry,sizeof(HeapEntry),NULL))
  1835. {
  1836. dprintf(" %p: %04x - %04x [%02x] (%x)\n",MemAddr,HeapEntry.Size,HeapEntry.PreviousSize,HeapEntry.Flags,HeapEntry.Size*sizeof(_HEAP_ENTRY_64)-HeapEntry.UnusedBytes);
  1837. GetVTable(MemAddr + sizeof(_HEAP_ENTRY_64));
  1838. MemAddr = MemAddr+HeapEntry.Size*sizeof(_HEAP_ENTRY_64);
  1839. }
  1840. else
  1841. {
  1842. dprintf("RM %p\n",MemAddr);
  1843. break;
  1844. }
  1845. if (CheckControlC())
  1846. break;
  1847. }
  1848. dprintf("last %p\n",MemAddr);
  1849. }
  1850. else
  1851. {
  1852. dprintf("RM %p\n",MemAddr);
  1853. }
  1854. }
  1855. else
  1856. {
  1857. dprintf("unable to resolve %s\n",args);
  1858. }
  1859. #endif /*KDEXT_64BIT*/
  1860. }
  1861. DECLARE_API(heb64)
  1862. {
  1863. INIT_API();
  1864. #ifdef KDEXT_64BIT
  1865. _HEAP_ENTRY_64 HeapEntry;
  1866. ULONG64 MemAddr = GetExpression(args);
  1867. ULONG64 pVTable = 0;
  1868. if (MemAddr)
  1869. {
  1870. if (ReadMemory(MemAddr,&HeapEntry,sizeof(HeapEntry),NULL))
  1871. {
  1872. dprintf(" %p: %04x - %04x [%02x] (%x)\n",MemAddr,HeapEntry.Size,HeapEntry.PreviousSize,HeapEntry.Flags,HeapEntry.Size*sizeof(_HEAP_ENTRY_64)-HeapEntry.UnusedBytes);
  1873. GetVTable(MemAddr + sizeof(_HEAP_ENTRY_64));
  1874. MemAddr = MemAddr - HeapEntry.PreviousSize*sizeof(_HEAP_ENTRY_64);
  1875. // 0x10 is LAST_ENTRY
  1876. while(HeapEntry.PreviousSize)
  1877. {
  1878. if (ReadMemory(MemAddr,&HeapEntry,sizeof(HeapEntry),NULL))
  1879. {
  1880. dprintf(" %p: %04x - %04x [%02x] (%x)\n",MemAddr,HeapEntry.Size,HeapEntry.PreviousSize,HeapEntry.Flags,HeapEntry.Size*sizeof(_HEAP_ENTRY_64)-HeapEntry.UnusedBytes);
  1881. GetVTable(MemAddr + sizeof(_HEAP_ENTRY_64));
  1882. MemAddr = MemAddr - HeapEntry.PreviousSize*sizeof(_HEAP_ENTRY_64);
  1883. }
  1884. else
  1885. {
  1886. dprintf("RM %p\n",MemAddr);
  1887. break;
  1888. }
  1889. if (CheckControlC())
  1890. break;
  1891. }
  1892. dprintf("last %p\n",MemAddr);
  1893. }
  1894. else
  1895. {
  1896. dprintf("RM %p\n",MemAddr);
  1897. }
  1898. }
  1899. else
  1900. {
  1901. dprintf("unable to resolve %s\n",args);
  1902. }
  1903. #endif /*KDEXT_64BIT*/
  1904. }
  1905. DECLARE_API(hps64)
  1906. {
  1907. INIT_API();
  1908. #ifdef KDEXT_64BIT
  1909. ULONG64 Peb = GetExpression(args);
  1910. if (!Peb)
  1911. {
  1912. Peb = 0x6fbfffde000;
  1913. }
  1914. ULONG NumberOfHeapsOffset;
  1915. ULONG HeapsOffset;
  1916. ULONG SegmentsOffset;
  1917. if ( Peb &&
  1918. (0 == GetFieldOffset("ntdll!_PEB","NumberOfHeaps",&NumberOfHeapsOffset)) &&
  1919. (0 == GetFieldOffset("ntdll!_PEB","ProcessHeaps",&HeapsOffset)) &&
  1920. (0 == GetFieldOffset("ntdll!_HEAP","Segments",&SegmentsOffset)))
  1921. {
  1922. //dprintf(" %x %x\n",NumberOfHeapsOffset,HeapsOffset);
  1923. ULONG nHeaps;
  1924. ULONG64 MemAddr;
  1925. if (ReadMemory(Peb+NumberOfHeapsOffset,&nHeaps,sizeof(ULONG),NULL))
  1926. {
  1927. //dprintf("nHeaps %08x\n",nHeaps);
  1928. ReadMemory(Peb+HeapsOffset,&MemAddr,sizeof(ULONG64),NULL);
  1929. ULONG64 * pHeaps = (ULONG64 *)_alloca(sizeof(ULONG64)*(DWORD)nHeaps);
  1930. ReadMemory(MemAddr,pHeaps,sizeof(ULONG64)*(DWORD)nHeaps,NULL);
  1931. // +0x0a0 Segments : [64] 0x000006fb`f9fa0c50
  1932. ULONG64 Segments[64];
  1933. for(ULONG i=0;i<nHeaps;i++)
  1934. {
  1935. if (ReadMemory(pHeaps[i]+SegmentsOffset,Segments,sizeof(Segments),NULL))
  1936. {
  1937. for (DWORD j=0;j<64;j++)
  1938. {
  1939. if (Segments[j])
  1940. {
  1941. dprintf(" S %p\n",Segments[j]);
  1942. }
  1943. if (CheckControlC())
  1944. break;
  1945. }
  1946. }
  1947. dprintf(" %p\n",pHeaps[i]);
  1948. if (CheckControlC())
  1949. break;
  1950. }
  1951. }
  1952. else
  1953. {
  1954. dprintf("RM %p\n",Peb+NumberOfHeapsOffset);
  1955. }
  1956. }
  1957. else
  1958. {
  1959. dprintf("check symbols for ntdll.dll or validate %p as PEB\n",Peb);
  1960. }
  1961. #endif /*KDEXT_64BIT*/
  1962. }