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.

2420 lines
73 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. pool.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Lou Perazzoli (Loup) 5-Nov-1993
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. Kshitiz K. Sharma (kksharma)
  13. Using debugger type info.
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. typedef struct _POOL_BLOCK_HEAD {
  18. // POOL_HEADER Header;
  19. LIST_ENTRY List;
  20. } POOL_BLOCK_HEAD, *PPOOL_BLOCK_HEADER;
  21. typedef struct _POOL_HACKER {
  22. // POOL_HEADER Header;
  23. ULONG Contents[8];
  24. } POOL_HACKER;
  25. #define TAG 0
  26. #define NONPAGED_ALLOC 1
  27. #define NONPAGED_FREE 2
  28. #define PAGED_ALLOC 3
  29. #define PAGED_FREE 4
  30. #define NONPAGED_USED 5
  31. #define PAGED_USED 6
  32. BOOL NewPool;
  33. ULONG SortBy;
  34. typedef struct _FILTER {
  35. ULONG Tag;
  36. BOOLEAN Exclude;
  37. } FILTER, *PFILTER;
  38. #define MAX_FILTER 64
  39. FILTER Filter[MAX_FILTER];
  40. ULONG64 SpecialPoolStart;
  41. ULONG64 SpecialPoolEnd;
  42. ULONG64 PoolBigTableAddress;
  43. #define DecodeLink(Pool) ( (ULONG64) (Pool & (ULONG64) ~1))
  44. //
  45. // Size of a pool page.
  46. //
  47. // This must be greater than or equal to the page size.
  48. //
  49. #define POOL_PAGE_SIZE PageSize
  50. //
  51. // The smallest pool block size must be a multiple of the page size.
  52. //
  53. // Define the block size as 32.
  54. //
  55. #define POOL_LIST_HEADS (POOL_PAGE_SIZE / (1 << POOL_BLOCK_SHIFT))
  56. #define SPECIAL_POOL_BLOCK_SIZE(PoolHeader_Ulong1) (PoolHeader_Ulong1 & (MI_SPECIAL_POOL_VERIFIER - 1))
  57. #ifndef _EXTFNS_H
  58. // GetPoolTagDescription
  59. typedef HRESULT
  60. (WINAPI *PGET_POOL_TAG_DESCRIPTION)(
  61. ULONG PoolTag,
  62. PSTR *pDescription
  63. );
  64. #endif
  65. ULONG64
  66. GetSpecialPoolHeader (
  67. IN PVOID DataPage,
  68. IN ULONG64 RealDataPage,
  69. OUT PULONG64 ReturnedDataStart
  70. );
  71. int __cdecl
  72. ulcomp(const void *e1,const void *e2)
  73. {
  74. ULONG u1;
  75. LONG64 diff;
  76. ULONG64 ValE1, ValE2;
  77. switch (SortBy) {
  78. case TAG:
  79. GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "Key", ValE1);
  80. GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "Key", ValE2);
  81. u1 = ((PUCHAR)&ValE1)[0] - ((PUCHAR)&ValE2)[0];
  82. if (u1 != 0) {
  83. return u1;
  84. }
  85. u1 = ((PUCHAR)&ValE1)[1] - ((PUCHAR)&ValE2)[1];
  86. if (u1 != 0) {
  87. return u1;
  88. }
  89. u1 = ((PUCHAR)&ValE1)[2] - ((PUCHAR)&ValE2)[2];
  90. if (u1 != 0) {
  91. return u1;
  92. }
  93. u1 = ((PUCHAR)&ValE1)[3] - ((PUCHAR)&ValE2)[3];
  94. return u1;
  95. break;
  96. case NONPAGED_ALLOC:
  97. GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedAllocs", ValE1);
  98. GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedAllocs", ValE2);
  99. diff = ValE2 - ValE1;
  100. return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
  101. break;
  102. case NONPAGED_FREE:
  103. GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedFrees", ValE1);
  104. GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedFrees", ValE2);
  105. diff = ValE2 - ValE1;
  106. return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
  107. break;
  108. case NONPAGED_USED:
  109. GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "NonPagedBytes", ValE1);
  110. GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "NonPagedBytes", ValE2);
  111. diff = ValE2 - ValE1;
  112. return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
  113. break;
  114. case PAGED_USED:
  115. GetFieldValue(*((PULONG64) e1), "nt!_POOL_TRACKER_TABLE", "PagedBytes", ValE1);
  116. GetFieldValue(*((PULONG64) e2), "nt!_POOL_TRACKER_TABLE", "PagedBytes", ValE2);
  117. diff = ValE2 - ValE1;
  118. return( diff ? ( diff > 0 ? 1 : -1 ) : 0 );
  119. break;
  120. default:
  121. return(0);
  122. break;
  123. }
  124. }
  125. /*++
  126. Routine Description:
  127. Sets up generally useful pool globals.
  128. Must be called in every DECLARE_API interface that uses pool.
  129. Arguments:
  130. None.
  131. Return Value:
  132. None
  133. --*/
  134. LOGICAL PoolInitialized = FALSE;
  135. LOGICAL
  136. PoolInitializeGlobals(
  137. VOID
  138. )
  139. {
  140. if (PoolInitialized == TRUE) {
  141. return TRUE;
  142. }
  143. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  144. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  145. if (PageSize < 0x1000 || (PageSize & (ULONG)0xFFF)) {
  146. dprintf ("unable to get MmPageSize (0x%x) - probably bad symbols\n", PageSize);
  147. return FALSE;
  148. }
  149. PoolInitialized = TRUE;
  150. return TRUE;
  151. }
  152. DECLARE_API( frag )
  153. /*++
  154. Routine Description:
  155. Dump pool fragmentation
  156. Arguments:
  157. args - Flags
  158. Return Value:
  159. None
  160. --*/
  161. {
  162. ULONG Flags;
  163. ULONG result;
  164. ULONG i;
  165. ULONG count;
  166. ULONG64 Pool;
  167. ULONG64 PoolLoc1;
  168. ULONG TotalFrag;
  169. ULONG TotalCount;
  170. ULONG Frag;
  171. ULONG64 PoolStart;
  172. ULONG PoolOverhead;
  173. ULONG64 PoolLoc;
  174. ULONG PoolTag, BlockSize, PreviousSize, PoolIndex;
  175. ULONG TotalPages, TotalBigPages;
  176. ULONG64 Flink, Blink;
  177. PCHAR pc;
  178. ULONG64 tmp;
  179. #define PoolBlk(F,V) GetFieldValue(Pool, "nt!_POOL_BLOCK_HEAD", #F, V)
  180. if (PoolInitializeGlobals() == FALSE) {
  181. return E_INVALIDARG;
  182. }
  183. dprintf("\n NonPaged Pool Fragmentation\n\n");
  184. Flags = 0;
  185. PoolStart = 0;
  186. if (GetExpressionEx(args, &tmp, &args)) {
  187. Flags = (ULONG) tmp;
  188. PoolStart = GetExpression (args);
  189. }
  190. PoolOverhead = GetTypeSize("nt!_POOL_HEADER");
  191. if (PoolStart != 0) {
  192. PoolStart += PoolOverhead;
  193. Pool = DecodeLink(PoolStart);
  194. do {
  195. Pool = Pool - PoolOverhead;
  196. if ( PoolBlk(Header.PoolTag, PoolTag) ) {
  197. dprintf("%08p: Unable to get contents of pool block\n", Pool );
  198. return E_INVALIDARG;
  199. }
  200. PoolBlk(Header.BlockSize,BlockSize);
  201. PoolBlk(Header.PreviousSize,PreviousSize);
  202. PoolBlk(List.Flink,Flink);
  203. PoolBlk(List.Blink,Blink);
  204. dprintf(" %p size: %4lx previous size: %4lx %c%c%c%c links: %8p %8p\n",
  205. Pool,
  206. (ULONG)BlockSize << POOL_BLOCK_SHIFT,
  207. (ULONG)PreviousSize << POOL_BLOCK_SHIFT,
  208. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  209. PP(PoolTag),
  210. PP(PoolTag >> 8),
  211. PP(PoolTag >> 16),
  212. PP((PoolTag&~PROTECTED_POOL) >> 24),
  213. #undef PP
  214. Flink,
  215. Blink);
  216. if (Flags != 3) {
  217. Pool = Flink;
  218. } else {
  219. Pool = Blink;
  220. }
  221. Pool = DecodeLink(Pool);
  222. if (CheckControlC()) {
  223. return E_INVALIDARG;
  224. }
  225. } while ( (Pool & (ULONG64) ~1) != (PoolStart & (ULONG64) ~1) );
  226. return E_INVALIDARG;
  227. }
  228. PoolLoc1 = GetNtDebuggerData( NonPagedPoolDescriptor );
  229. if (PoolLoc1 == 0) {
  230. dprintf ("unable to get nonpaged pool head\n");
  231. return E_INVALIDARG;
  232. }
  233. PoolLoc = PoolLoc1;
  234. TotalFrag = 0;
  235. TotalCount = 0;
  236. for (i = 0; i < POOL_LIST_HEADS; i += 1) {
  237. CHAR Buffer[40];
  238. ULONG ListOffset;
  239. sprintf(Buffer, "ListHeads[%d].Flink", i);
  240. Frag = 0;
  241. count = 0;
  242. if (GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", Buffer, Pool)) {
  243. dprintf ("%08p: Unable to get pool descriptor\n", PoolLoc1);
  244. return E_INVALIDARG;
  245. }
  246. GetFieldOffset("nt!_POOL_DESCRIPTOR", Buffer, &ListOffset);
  247. // Pool = (PUCHAR)PoolDesc.ListHeads[i].Flink;
  248. Pool = DecodeLink(Pool);
  249. while (Pool != (ListOffset + PoolLoc)) {
  250. Pool = Pool - PoolOverhead;
  251. if ( PoolBlk(Header.PoolTag, PoolTag) ) {
  252. dprintf("%08p: Unable to get contents of pool block\n", Pool );
  253. return E_INVALIDARG;
  254. }
  255. PoolBlk(Header.BlockSize,BlockSize);
  256. PoolBlk(Header.PreviousSize,PreviousSize);
  257. PoolBlk(List.Flink,Flink);
  258. Frag += BlockSize << POOL_BLOCK_SHIFT;
  259. count += 1;
  260. if (Flags & 2) {
  261. dprintf(" ListHead[%x]: %p size: %4lx previous size: %4lx %c%c%c%c\n",
  262. i,
  263. (ULONG)Pool,
  264. (ULONG)BlockSize << POOL_BLOCK_SHIFT,
  265. (ULONG)PreviousSize << POOL_BLOCK_SHIFT,
  266. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  267. PP(PoolTag),
  268. PP(PoolTag >> 8),
  269. PP(PoolTag >> 16),
  270. PP((PoolTag&~PROTECTED_POOL) >> 24));
  271. #undef PP
  272. }
  273. Pool = Flink;
  274. Pool = DecodeLink(Pool);
  275. if (CheckControlC()) {
  276. return E_INVALIDARG;
  277. }
  278. }
  279. if (Flags & 1) {
  280. dprintf("index: %2ld number of fragments: %5ld bytes: %6ld\n",
  281. i,count,Frag);
  282. }
  283. TotalFrag += Frag;
  284. TotalCount += count;
  285. }
  286. dprintf("\n Number of fragments: %7ld consuming %7ld bytes\n",
  287. TotalCount,TotalFrag);
  288. GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages",TotalPages);
  289. GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalBigPages", TotalBigPages);
  290. dprintf( " NonPagedPool Usage: %7ld bytes\n",(TotalPages + TotalBigPages)*PageSize);
  291. return S_OK;
  292. #undef PoolBlk
  293. }
  294. PRTL_BITMAP
  295. GetBitmap(
  296. ULONG64 pBitmap
  297. )
  298. {
  299. PRTL_BITMAP p;
  300. ULONG Size, Result;
  301. ULONG64 Buffer=0;
  302. if ( GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "Buffer", Buffer)) {
  303. dprintf("%08p: Unable to get contents of bitmap\n", pBitmap );
  304. return 0;
  305. }
  306. GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "SizeOfBitMap", Size);
  307. p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) + (Size / 8) );
  308. if (p) {
  309. p->SizeOfBitMap = Size;
  310. p->Buffer = (PULONG)(p + 1);
  311. if ( !ReadMemory( Buffer,
  312. p->Buffer,
  313. Size / 8,
  314. &Result) ) {
  315. dprintf("%08p: Unable to get contents of bitmap buffer\n", Buffer );
  316. HeapFree( GetProcessHeap(), 0, p );
  317. p = NULL;
  318. }
  319. }
  320. return p;
  321. }
  322. VOID
  323. DumpPool(
  324. VOID
  325. )
  326. {
  327. ULONG64 p, pStart;
  328. ULONG64 Size;
  329. ULONG BusyFlag;
  330. ULONG CurrentPage, NumberOfPages;
  331. PRTL_BITMAP StartMap;
  332. PRTL_BITMAP EndMap;
  333. ULONG64 PagedPoolStart;
  334. ULONG64 PagedPoolEnd;
  335. ULONG Result;
  336. UCHAR PgPool[] = "nt!_MM_PAGED_POOL_INFO";
  337. ULONG64 PagedPoolInfoPointer;
  338. ULONG64 PagedPoolAllocationMap=0, EndOfPagedPoolBitmap=0;
  339. if (PoolInitializeGlobals() == FALSE) {
  340. return;
  341. }
  342. PagedPoolInfoPointer = GetNtDebuggerData( MmPagedPoolInformation );
  343. if ( GetFieldValue( PagedPoolInfoPointer,
  344. PgPool,
  345. "PagedPoolAllocationMap",
  346. PagedPoolAllocationMap)) {
  347. dprintf("%08p: Unable to get contents of paged pool information\n",
  348. PagedPoolInfoPointer );
  349. return;
  350. }
  351. GetFieldValue( PagedPoolInfoPointer, PgPool, "EndOfPagedPoolBitmap", EndOfPagedPoolBitmap);
  352. StartMap = GetBitmap( PagedPoolAllocationMap );
  353. EndMap = GetBitmap( EndOfPagedPoolBitmap );
  354. PagedPoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
  355. PagedPoolEnd = GetNtDebuggerDataPtrValue( MmPagedPoolEnd );
  356. if (StartMap && EndMap) {
  357. p = PagedPoolStart;
  358. CurrentPage = 0;
  359. dprintf( "Paged Pool: %p .. %p\n", PagedPoolStart, PagedPoolEnd );
  360. while (p < PagedPoolEnd) {
  361. if ( CheckControlC() ) {
  362. return;
  363. }
  364. pStart = p;
  365. BusyFlag = RtlCheckBit( StartMap, CurrentPage );
  366. while ( ~(BusyFlag ^ RtlCheckBit( StartMap, CurrentPage )) ) {
  367. p += PageSize;
  368. if (RtlCheckBit( EndMap, CurrentPage )) {
  369. CurrentPage++;
  370. break;
  371. }
  372. CurrentPage++;
  373. if (p > PagedPoolEnd) {
  374. break;
  375. }
  376. }
  377. Size = p - pStart;
  378. dprintf( "%p: %I64x - %s\n", pStart, Size, BusyFlag ? "busy" : "free" );
  379. }
  380. }
  381. HeapFree( GetProcessHeap(), 0, StartMap );
  382. HeapFree( GetProcessHeap(), 0, EndMap );
  383. }
  384. void
  385. PrintPoolTagComponent(
  386. ULONG PoolTag
  387. )
  388. {
  389. PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
  390. PSTR TagComponent;
  391. #ifdef _EXTFNS_H
  392. DEBUG_POOLTAG_DESCRIPTION Desc = {0};
  393. Desc.SizeOfStruct = sizeof(DEBUG_POOLTAG_DESCRIPTION);
  394. GetPoolTagDescription = NULL;
  395. if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
  396. !GetPoolTagDescription) {
  397. return;
  398. }
  399. (*GetPoolTagDescription)(PoolTag, &Desc);
  400. if (Desc.Description[0]) {
  401. dprintf("\t\tPooltag %4.4s : %s", &PoolTag, Desc.Description);
  402. if (Desc.Binary[0]) {
  403. dprintf(", Binary : %s",Desc.Binary);
  404. }
  405. if (Desc.Owner[0]) {
  406. dprintf(", Owner : %s", Desc.Owner);
  407. }
  408. dprintf("\n");
  409. } else {
  410. dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
  411. }
  412. #else
  413. GetPoolTagDescription = NULL;
  414. if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
  415. !GetPoolTagDescription) {
  416. return;
  417. }
  418. (*GetPoolTagDescription)(PoolTag, &TagComponent);
  419. if (TagComponent && (100 < (ULONG64) TagComponent)) {
  420. dprintf("\t\tOwning component : %s\n", TagComponent);
  421. } else {
  422. dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
  423. }
  424. #endif
  425. }
  426. PSTR g_PoolRegion[DbgPoolRegionMax] = {
  427. "Unknown", // DbgPoolRegionUnknown,
  428. "Special pool", // DbgPoolRegionSpecial,
  429. "Paged pool", // DbgPoolRegionPaged,
  430. "Nonpaged pool", // DbgPoolRegionNonPaged,
  431. "Pool code", // DbgPoolRegionCode,
  432. "Nonpaged pool expansion", // DbgPoolRegionNonPagedExpansion,
  433. };
  434. DEBUG_POOL_REGION
  435. GetPoolRegion(
  436. ULONG64 Pool
  437. )
  438. {
  439. static ULONG64 PoolCodeEnd;
  440. static ULONG64 SpecialPoolEnd;
  441. static ULONG64 PagedPoolEnd;
  442. static ULONG64 NonPagedPoolEnd;
  443. static ULONG64 NonPagedPoolStart;
  444. static ULONG64 SpecialPoolStart;
  445. static ULONG64 PagedPoolStart;
  446. static ULONG64 NonPagedPoolExpansionStart;
  447. static ULONG64 PoolCodeStart;
  448. static BOOL GotAll = FALSE;
  449. if (!GotAll) {
  450. PoolCodeEnd = GetPointerValue("nt!MmPoolCodeEnd");
  451. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  452. PagedPoolEnd = GetPointerValue("nt!MmPagedPoolEnd");
  453. NonPagedPoolEnd = GetPointerValue("nt!MmNonPagedPoolEnd");
  454. NonPagedPoolStart = GetPointerValue("nt!MmNonPagedPoolStart");
  455. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  456. PagedPoolStart = GetPointerValue("nt!MmPagedPoolStart");
  457. NonPagedPoolExpansionStart = GetPointerValue("nt!MmNonPagedPoolExpansionStart");
  458. PoolCodeStart = GetPointerValue("nt!MmPoolCodeStart");
  459. GotAll = TRUE;
  460. }
  461. if (!(PoolCodeStart || SpecialPoolStart || SpecialPoolEnd || PoolCodeEnd ||
  462. NonPagedPoolExpansionStart || NonPagedPoolStart || NonPagedPoolEnd ||
  463. PagedPoolStart || PagedPoolEnd)) {
  464. GotAll = FALSE;
  465. return DbgPoolRegionUnknown;
  466. }
  467. if ( Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
  468. return DbgPoolRegionSpecial;
  469. } else if ( Pool >= PagedPoolStart && Pool < PagedPoolEnd) {
  470. return DbgPoolRegionPaged;
  471. } else if ( Pool >= NonPagedPoolStart && Pool < NonPagedPoolEnd) {
  472. return DbgPoolRegionNonPaged;
  473. } else if ( Pool >= PoolCodeStart && Pool < PoolCodeEnd) {
  474. return DbgPoolRegionCode;
  475. } else if ( Pool >= NonPagedPoolExpansionStart) {
  476. return DbgPoolRegionNonPagedExpansion;
  477. } else {
  478. return DbgPoolRegionUnknown;
  479. }
  480. return DbgPoolRegionUnknown;
  481. }
  482. void
  483. PrintPoolRegion(
  484. ULONG64 Pool
  485. )
  486. {
  487. PSTR pszRegion;
  488. DEBUG_POOL_REGION Region;
  489. Region = GetPoolRegion(Pool);
  490. pszRegion = g_PoolRegion[Region];
  491. if (pszRegion) {
  492. dprintf(pszRegion);
  493. dprintf("\n");
  494. } else {
  495. dprintf("Region unkown\n", Pool);
  496. }
  497. }
  498. HRESULT
  499. ListPoolPage(
  500. ULONG64 PoolPageToDump,
  501. ULONG Flags,
  502. PDEBUG_POOL_DATA PoolData
  503. )
  504. {
  505. ULONG64 PoolTableAddress;
  506. ULONG result;
  507. ULONG PoolTag;
  508. ULONG Result;
  509. ULONG64 StartPage;
  510. ULONG64 Pool;
  511. ULONG PoolBlockSize;
  512. ULONG PoolHeaderSize;
  513. ULONG64 PoolHeader;
  514. ULONG Previous;
  515. UCHAR c;
  516. PUCHAR p;
  517. ULONG64 PoolDataEnd;
  518. UCHAR PoolBlockPattern;
  519. UCHAR DataPage[0x5000];
  520. PUCHAR DataStart;
  521. ULONG64 RealDataStart;
  522. LOGICAL Pagable;
  523. LOGICAL FirstBlock;
  524. ULONG BlockType;
  525. ULONG PoolWhere;
  526. ULONG i;
  527. ULONG j;
  528. ULONG ct;
  529. ULONG start;
  530. ULONG PoolBigPageTableSize;
  531. ULONG SizeOfPoolHdr=GetTypeSize("nt!_POOL_HEADER");
  532. if (!SpecialPoolStart) {
  533. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  534. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  535. }
  536. Pool = PAGE_ALIGN64 (PoolPageToDump);
  537. StartPage = Pool;
  538. Previous = 0;
  539. if (PoolData) {
  540. ZeroMemory(PoolData, sizeof(DEBUG_POOL_DATA));
  541. }
  542. if (!(Flags & 0x80000000)) {
  543. dprintf("Pool page %p region is ", PoolPageToDump);
  544. PrintPoolRegion(PoolPageToDump);
  545. }
  546. if ( Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
  547. ULONG Hdr_Ulong=0;
  548. // LWFIX: this is not ported yet.
  549. // dprintf("reading %I64x datapage %x\n", Pool, min(PageSize, sizeof(DataPage)));
  550. // Pre read the pool
  551. if ( !ReadMemory( Pool,
  552. &DataPage[0],
  553. min(PageSize, sizeof(DataPage)),
  554. &Result) ) {
  555. dprintf("%08p: Unable to get contents of special pool block\n", Pool );
  556. return E_INVALIDARG;
  557. }
  558. if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong)) {
  559. dprintf("%08p: Unable to get nt!_POOL_HEADER\n", Pool );
  560. return E_INVALIDARG;
  561. }
  562. //
  563. // Determine whether the data is at the start or end of the page.
  564. // Start off by assuming the data is at the end, in this case the
  565. // header will be at the start.
  566. //
  567. PoolHeader = GetSpecialPoolHeader((PVOID) &DataPage[0], Pool, &RealDataStart);
  568. if (PoolHeader == 0) {
  569. dprintf("Block %p is a corrupted special pool allocation\n",
  570. PoolPageToDump);
  571. return E_INVALIDARG;
  572. }
  573. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong);
  574. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  575. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(Hdr_Ulong);
  576. if (Hdr_Ulong & MI_SPECIAL_POOL_PAGABLE) {
  577. Pagable = TRUE;
  578. } else {
  579. Pagable = FALSE;
  580. }
  581. if (PoolData) {
  582. PoolData->Pool = RealDataStart;
  583. PoolData->PoolBlock = PoolPageToDump;
  584. PoolData->SpecialPool = 1;
  585. PoolData->Pageable = Hdr_Ulong & 0x8000 ? 1 : 0;
  586. PoolData->Size = PoolBlockSize;
  587. if (Flags & 0x80000000) {
  588. // do not print anything
  589. return S_OK;
  590. }
  591. }
  592. dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
  593. RealDataStart,
  594. PoolBlockSize,
  595. Hdr_Ulong & 0x8000 ? "pagable" : "non-paged",
  596. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  597. PP(PoolTag),
  598. PP(PoolTag >> 8),
  599. PP(PoolTag >> 16),
  600. PP(PoolTag >> 24)
  601. );
  602. #undef PP
  603. PrintPoolTagComponent(PoolTag);
  604. //
  605. // Add code to validate whole block.
  606. //
  607. return S_OK;
  608. }
  609. FirstBlock = TRUE;
  610. while (PAGE_ALIGN64(Pool) == StartPage) {
  611. ULONG BlockSize=0, PreviousSize=0, PoolType=0, AllocatorBackTraceIndex=0;
  612. ULONG PoolTagHash=0, PoolIndex=0;
  613. ULONG64 ProcessBilled=0;
  614. if ( CheckControlC() ) {
  615. return E_INVALIDARG;
  616. }
  617. if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize) ) {
  618. dprintf("%08p: Unable to get contents of pool block\n", Pool );
  619. return E_INVALIDARG;
  620. }
  621. if (PoolPageToDump >= Pool &&
  622. PoolPageToDump < (Pool + (BlockSize << POOL_BLOCK_SHIFT))
  623. ) {
  624. c = '*';
  625. } else {
  626. c = ' ';
  627. }
  628. GetFieldValue( Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  629. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolType", PoolType);
  630. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  631. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
  632. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
  633. GetFieldValue( Pool, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
  634. GetFieldValue( Pool, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  635. BlockType = 0;
  636. if ((BlockSize << POOL_BLOCK_SHIFT) >= POOL_PAGE_SIZE) {
  637. BlockType = 1;
  638. } else if (BlockSize == 0) {
  639. BlockType = 2;
  640. } else if (PreviousSize != Previous) {
  641. BlockType = 3;
  642. }
  643. if (BlockType != 0) {
  644. ULONG BigPageSize = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
  645. if (!BigPageSize) {
  646. dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
  647. break;
  648. }
  649. //
  650. // See if this is a big block allocation. Iff we have not parsed
  651. // any other small blocks in here already.
  652. //
  653. if (FirstBlock == TRUE) {
  654. if (!PoolBigTableAddress) {
  655. PoolBigTableAddress = GetPointerValue ("PoolBigPageTable");
  656. }
  657. PoolTableAddress = PoolBigTableAddress;
  658. if (PoolTableAddress) {
  659. dprintf ("%p is not a valid small pool allocation, checking large pool...\n", Pool);
  660. PoolBigPageTableSize = GetUlongValue ("PoolBigPageTableSize");
  661. //
  662. // Scan the table looking for a match.
  663. //
  664. i = 0;
  665. ct = PageSize / BigPageSize;
  666. while (i < PoolBigPageTableSize) {
  667. ULONG64 Va=0;
  668. ULONG Key=0, NumberOfPages=0;
  669. if (PoolBigPageTableSize - i < ct) {
  670. ct = PoolBigPageTableSize - i;
  671. }
  672. if ( GetFieldValue( PoolTableAddress,
  673. "nt!_POOL_TRACKER_BIG_PAGES",
  674. "Va",
  675. Va) ) {
  676. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  677. return E_INVALIDARG;
  678. }
  679. for (j = 0; j < ct; j += 1) {
  680. if ( GetFieldValue( PoolTableAddress + BigPageSize*j,
  681. "nt!_POOL_TRACKER_BIG_PAGES",
  682. "Va",
  683. Va) ) {
  684. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  685. return E_INVALIDARG;
  686. }
  687. if (Va == PAGE_ALIGN64(Pool)) {
  688. //
  689. // Match !
  690. //
  691. GetFieldValue( PoolTableAddress + BigPageSize*j,
  692. "nt!_POOL_TRACKER_BIG_PAGES",
  693. "Key",
  694. Key);
  695. GetFieldValue( PoolTableAddress + BigPageSize*j,
  696. "nt!_POOL_TRACKER_BIG_PAGES",
  697. "NumberOfPages",
  698. NumberOfPages);
  699. PoolTag = Key;
  700. if (PoolData) {
  701. PoolData->Pool = PoolPageToDump;
  702. PoolData->Size = NumberOfPages*PageSize;
  703. PoolData->PoolTag = PoolTag;
  704. PoolData->LargePool = 1;
  705. PoolData->Free = (Pool & POOL_BIG_TABLE_ENTRY_FREE) ? 1 : 0;
  706. if (Flags & 0x80000000) {
  707. // do not print anything
  708. return S_OK;
  709. }
  710. }
  711. dprintf("*%p :%s large page allocation, Tag is %c%c%c%c, size is 0x%x bytes\n",
  712. (Pool & ~POOL_BIG_TABLE_ENTRY_FREE),
  713. (Pool & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
  714. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  715. PP(PoolTag),
  716. PP(PoolTag >> 8),
  717. PP(PoolTag >> 16),
  718. PP(PoolTag >> 24),
  719. NumberOfPages * PageSize
  720. );
  721. #undef PP
  722. PrintPoolTagComponent(PoolTag);
  723. return S_OK;
  724. }
  725. }
  726. i += ct;
  727. PoolTableAddress += (ct * BigPageSize);
  728. }
  729. //
  730. // No match in small or large pool, must be
  731. // freed or corrupt pool
  732. //
  733. dprintf("%p is freed (or corrupt) pool\n", Pool);
  734. return E_INVALIDARG;
  735. }
  736. dprintf("unable to get pool big page table - either wrong symbols or pool tagging is disabled\n");
  737. }
  738. if (BlockType == 1) {
  739. dprintf("Bad allocation size @%p, too large\n", Pool);
  740. return E_INVALIDARG;
  741. } else if (BlockType == 2) {
  742. dprintf("Bad allocation size @%p, zero is invalid\n", Pool);
  743. return E_INVALIDARG;
  744. } else if (BlockType == 3) {
  745. dprintf("Bad previous allocation size @%p, last size was %lx\n",
  746. Pool, Previous);
  747. return E_INVALIDARG;
  748. }
  749. }
  750. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  751. if (!(Flags & 2) || c == '*') {
  752. if (PoolData) {
  753. PoolData->Pool = Pool;
  754. PoolData->PoolBlock = PoolPageToDump;
  755. PoolData->PoolTag = PoolTag & ~PROTECTED_POOL;
  756. PoolData->ProcessBilled = ProcessBilled;
  757. PoolData->PreviousSize = PreviousSize << POOL_BLOCK_SHIFT;
  758. PoolData->Size = BlockSize << POOL_BLOCK_SHIFT;
  759. PoolData->Free = ((PoolType != 0) && (!NewPool ?
  760. (PoolIndex & 0x80) : (PoolType & 0x04))) ? 0 : 1;
  761. PoolData->Protected = (PoolTag&PROTECTED_POOL) ? 1 : 0;
  762. if (Flags & 0x80000000) {
  763. // do not print anything
  764. return S_OK;
  765. }
  766. }
  767. dprintf("%c%p size: %4lx previous size: %4lx ",
  768. c,
  769. Pool,
  770. BlockSize << POOL_BLOCK_SHIFT,
  771. PreviousSize << POOL_BLOCK_SHIFT);
  772. if (PoolType == 0) {
  773. //
  774. // "Free " with a space after it before the parentheses means
  775. // it's been freed to a (pool manager internal) lookaside list.
  776. // We used to print "Lookaside" but that just confused driver
  777. // writers because they didn't know if this meant in use or not
  778. // and many would say "but I don't use lookaside lists - the
  779. // extension or kernel is broken".
  780. //
  781. // "Free" with no space after it before the parentheses means
  782. // it is not on a pool manager internal lookaside list and is
  783. // instead on the regular pool manager internal flink/blink
  784. // chains.
  785. //
  786. // Note to anyone using the pool package, these 2 terms are
  787. // equivalent. The fine distinction is only for those actually
  788. // writing pool internal code.
  789. //
  790. dprintf(" (Free)");
  791. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  792. dprintf(" %c%c%c%c%c\n",
  793. c,
  794. PP(PoolTag),
  795. PP(PoolTag >> 8),
  796. PP(PoolTag >> 16),
  797. PP((PoolTag&~PROTECTED_POOL) >> 24)
  798. );
  799. #undef PP
  800. if (c=='*') {
  801. PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
  802. }
  803. } else {
  804. if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
  805. dprintf(" (Allocated)");
  806. } else {
  807. //
  808. // "Free " with a space after it before the parentheses means
  809. // it's been freed to a (pool manager internal) lookaside list.
  810. // We used to print "Lookaside" but that just confused driver
  811. // writers because they didn't know if this meant in use or not
  812. // and many would say "but I don't use lookaside lists - the
  813. // extension or kernel is broken".
  814. //
  815. // "Free" with no space after it before the parentheses means
  816. // it is not on a pool manager internal lookaside list and is
  817. // instead on the regular pool manager internal flink/blink
  818. // chains.
  819. //
  820. // Note to anyone using the pool package, these 2 terms are
  821. // equivalent. The fine distinction is only for those actually
  822. // writing pool internal code.
  823. //
  824. dprintf(" (Free )");
  825. }
  826. if ((PoolType & POOL_QUOTA_MASK) == 0) {
  827. /*
  828. ULONG Key=0;
  829. if (AllocatorBackTraceIndex != 0 &&
  830. AllocatorBackTraceIndex & POOL_BACKTRACEINDEX_PRESENT
  831. ) {
  832. if ( GetFieldValue( PoolTrackTable + ( PoolTagHash&~(PROTECTED_POOL >> 16) )*GetTypeSize("nt!_POOL_TRACKER_TABLE"),
  833. "nt!_POOL_TRACKER_TABLE",
  834. "Key",
  835. Key) ) {
  836. PoolTag = 0;
  837. } else {
  838. PoolTag = Key;
  839. }
  840. if (PoolTagHash & (PROTECTED_POOL >> 16)) {
  841. PoolTag |= PROTECTED_POOL;
  842. }
  843. } else {
  844. PoolTag = PoolTag;
  845. }*/
  846. dprintf(" %c%c%c%c%c%s\n",
  847. c,
  848. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  849. PP(PoolTag),
  850. PP(PoolTag >> 8),
  851. PP(PoolTag >> 16),
  852. PP((PoolTag&~PROTECTED_POOL) >> 24),
  853. (PoolTag&PROTECTED_POOL) ? " (Protected)" : ""
  854. #undef PP
  855. );
  856. if (c=='*') {
  857. PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
  858. }
  859. } else {
  860. if (ProcessBilled != 0) {
  861. dprintf(" Process: %0p\n", ProcessBilled );
  862. }
  863. }
  864. }
  865. }
  866. if (Flags & 1) {
  867. ULONG i, Contents[8];
  868. // BUG if Contents have different size than 32 bits
  869. ReadMemory(Pool + SizeOfPoolHdr,
  870. &Contents,
  871. sizeof(Contents),
  872. &i);
  873. dprintf(" %08lx %08lx %08lx %08lx %08lx\n",
  874. Pool+SizeOfPoolHdr,
  875. Contents[0],
  876. Contents[1],
  877. Contents[2],
  878. Contents[3]);
  879. dprintf(" %08lx %08lx %08lx %08lx %08lx\n",
  880. Pool+SizeOfPoolHdr+16,
  881. Contents[4],
  882. Contents[5],
  883. Contents[6],
  884. Contents[7]);
  885. dprintf("\n");
  886. }
  887. Previous = BlockSize;
  888. Pool += (Previous << POOL_BLOCK_SHIFT);
  889. FirstBlock = FALSE;
  890. }
  891. return S_OK;
  892. }
  893. DECLARE_API( pool )
  894. /*++
  895. Routine Description:
  896. Dump kernel mode heap
  897. Arguments:
  898. args - Page Flags
  899. Return Value:
  900. None
  901. --*/
  902. {
  903. ULONG64 PoolPageToDump;
  904. ULONG Flags;
  905. HRESULT Hr;
  906. INIT_API();
  907. if (PoolInitializeGlobals() == FALSE) {
  908. Hr = E_INVALIDARG;
  909. } else {
  910. PoolPageToDump = 0;
  911. Flags = 0;
  912. if (GetExpressionEx(args, &PoolPageToDump, &args)) {
  913. Flags = (ULONG) GetExpression (args);
  914. }
  915. if (PoolPageToDump == 0) {
  916. DumpPool();
  917. Hr = S_OK;;
  918. } else {
  919. Hr = ListPoolPage(PoolPageToDump, Flags, NULL);
  920. }
  921. }
  922. EXIT_API();
  923. return Hr;
  924. }
  925. DECLARE_API( poolused )
  926. /*++
  927. Routine Description:
  928. Dump usage by pool tag
  929. Arguments:
  930. args -
  931. Return Value:
  932. None
  933. --*/
  934. {
  935. ULONG PoolTrackTableSize;
  936. ULONG PoolTrackTableSizeInBytes;
  937. PULONG64 p;
  938. PUCHAR PoolTrackTableData;
  939. ULONG Flags;
  940. ULONG i;
  941. ULONG result;
  942. ULONG ct;
  943. ULONG TagName;
  944. CHAR TagNameX[4] = {'*','*','*','*'};
  945. ULONG SizeOfPoolTarker;
  946. ULONG64 PoolTableAddress;
  947. ULONG64 PoolTrackTable;
  948. ULONG NonPagedAllocsTotal,NonPagedFreesTotal,PagedAllocsTotal,PagedFreesTotal;
  949. ULONG64 NonPagedBytesTotal, PagedBytesTotal;
  950. if (PoolInitializeGlobals() == FALSE) {
  951. return E_INVALIDARG;
  952. }
  953. Flags = 0;
  954. if (!sscanf(args,"%lx %c%c%c%c", &Flags, &TagNameX[0],
  955. &TagNameX[1], &TagNameX[2], &TagNameX[3])) {
  956. Flags = 0;
  957. }
  958. TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
  959. PoolTrackTableSize = GetUlongValue ("PoolTrackTableSize");
  960. if (!(SizeOfPoolTarker = GetTypeSize("nt!_POOL_TRACKER_TABLE"))) {
  961. dprintf("Unable to get _POOL_TRACKER_TABLE : probably wrong symbols.\n");
  962. return E_INVALIDARG;
  963. }
  964. PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
  965. if (PoolTrackTable == 0) {
  966. dprintf ("unable to get PoolTrackTable - ");
  967. if (GetExpression("nt!PoolTrackTable")) {
  968. dprintf ("pool tagging is disabled, enable it to use this command\n");
  969. dprintf ("Use gflags.exe and check the box that says \"Enable pool tagging\".\n");
  970. } else {
  971. dprintf ("symbols could be worng\n");
  972. }
  973. return E_INVALIDARG;
  974. }
  975. PoolTrackTableSizeInBytes = PoolTrackTableSize * SizeOfPoolTarker;
  976. PoolTrackTableData = malloc (PoolTrackTableSizeInBytes);
  977. if (PoolTrackTableData == NULL) {
  978. dprintf("unable to allocate memory for tag table.\n");
  979. return E_INVALIDARG;
  980. }
  981. //
  982. // KD is going to cache the data
  983. //
  984. PoolTableAddress = PoolTrackTable;
  985. if ( !ReadMemory( PoolTableAddress,
  986. &PoolTrackTableData[0],
  987. PoolTrackTableSizeInBytes,
  988. &result) ) {
  989. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  990. free (PoolTrackTableData);
  991. return E_INVALIDARG;
  992. }
  993. if (Flags & 2) {
  994. SortBy = NONPAGED_USED;
  995. dprintf(" Sorting by NonPaged Pool Consumed\n");
  996. } else if (Flags & 4) {
  997. SortBy = PAGED_USED;
  998. dprintf(" Sorting by Paged Pool Consumed\n");
  999. } else {
  1000. SortBy = TAG;
  1001. dprintf(" Sorting by Tag\n");
  1002. }
  1003. dprintf("\n Pool Used:\n");
  1004. if (!(Flags & 1)) {
  1005. dprintf(" NonPaged Paged\n");
  1006. dprintf(" Tag Allocs Used Allocs Used\n");
  1007. } else {
  1008. dprintf(" NonPaged Paged\n");
  1009. dprintf(" Tag Allocs Frees Diff Used Allocs Frees Diff Used\n");
  1010. }
  1011. ct = PageSize / SizeOfPoolTarker;
  1012. i = 0;
  1013. PoolTableAddress = PoolTrackTable;
  1014. free (PoolTrackTableData);
  1015. //
  1016. // Create array of POOL_TRACKER_TABLE addresses and sort the addresses
  1017. //
  1018. PoolTrackTableData = malloc (PoolTrackTableSize * sizeof(ULONG64));
  1019. if (PoolTrackTableData == NULL) {
  1020. dprintf("unable to allocate memory for tag table.\n");
  1021. return E_INVALIDARG;
  1022. }
  1023. while (i < PoolTrackTableSize) {
  1024. if ( CheckControlC() ) {
  1025. free (PoolTrackTableData);
  1026. return E_INVALIDARG;
  1027. }
  1028. ((PULONG64) PoolTrackTableData)[i] = PoolTableAddress + i * SizeOfPoolTarker;
  1029. i++;
  1030. }
  1031. qsort((void *)PoolTrackTableData,
  1032. (size_t)PoolTrackTableSize,
  1033. (size_t)sizeof(ULONG64),
  1034. ulcomp);
  1035. i = 0;
  1036. p = (PULONG64) &PoolTrackTableData[i];
  1037. NonPagedAllocsTotal = 0;
  1038. NonPagedFreesTotal = 0;
  1039. NonPagedBytesTotal = 0;
  1040. PagedAllocsTotal = 0;
  1041. PagedFreesTotal = 0;
  1042. PagedBytesTotal = 0;
  1043. for ( ; i < PoolTrackTableSize; i += 1, p += 1) {
  1044. ULONG Key,NonPagedAllocs,NonPagedFrees,PagedAllocs,PagedFrees;
  1045. ULONG64 NonPagedBytes, PagedBytes;
  1046. #define TrackFld(F) GetFieldValue(*p, "nt!_POOL_TRACKER_TABLE", #F, F)
  1047. TrackFld(Key); TrackFld(NonPagedAllocs); TrackFld(NonPagedBytes);
  1048. TrackFld(PagedBytes); TrackFld(NonPagedFrees); TrackFld(PagedAllocs);
  1049. TrackFld(PagedFrees);
  1050. #undef TrackFld
  1051. if ((Key != 0) &&
  1052. (CheckSingleFilter ((PCHAR)&Key, (PCHAR)&TagName))) {
  1053. if (!(Flags & 1)) {
  1054. if ((NonPagedBytes != 0) || (PagedBytes != 0)) {
  1055. NonPagedAllocsTotal += NonPagedAllocs;
  1056. NonPagedFreesTotal += NonPagedFrees;
  1057. NonPagedBytesTotal += NonPagedBytes;
  1058. PagedAllocsTotal += PagedAllocs;
  1059. PagedFreesTotal += PagedFrees;
  1060. PagedBytesTotal += PagedBytes;
  1061. dprintf(" %c%c%c%c %8ld %8I64ld %8ld %8I64ld\n",
  1062. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  1063. PP(Key),
  1064. PP(Key >> 8),
  1065. PP(Key >> 16),
  1066. PP(Key >> 24),
  1067. NonPagedAllocs - NonPagedFrees,
  1068. NonPagedBytes,
  1069. PagedAllocs - PagedFrees,
  1070. PagedBytes);
  1071. }
  1072. } else {
  1073. NonPagedAllocsTotal += NonPagedAllocs;
  1074. NonPagedFreesTotal += NonPagedFrees;
  1075. NonPagedBytesTotal += NonPagedBytes;
  1076. PagedAllocsTotal += PagedAllocs;
  1077. PagedFreesTotal += PagedFrees;
  1078. PagedBytesTotal += PagedBytes;
  1079. dprintf(" %c%c%c%c %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
  1080. PP(Key),
  1081. PP(Key >> 8),
  1082. PP(Key >> 16),
  1083. PP(Key >> 24),
  1084. NonPagedAllocs,
  1085. NonPagedFrees,
  1086. NonPagedAllocs - NonPagedFrees,
  1087. NonPagedBytes,
  1088. PagedAllocs,
  1089. PagedFrees,
  1090. PagedAllocs - PagedFrees,
  1091. PagedBytes);
  1092. #undef PP
  1093. }
  1094. }
  1095. }
  1096. if (!(Flags & 1)) {
  1097. dprintf(" TOTAL %8ld %8I64ld %8ld %8I64ld\n",
  1098. NonPagedAllocsTotal - NonPagedFreesTotal,
  1099. NonPagedBytesTotal,
  1100. PagedAllocsTotal - PagedFreesTotal,
  1101. PagedBytesTotal);
  1102. } else {
  1103. dprintf(" TOTAL %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
  1104. NonPagedAllocsTotal,
  1105. NonPagedFreesTotal,
  1106. NonPagedAllocsTotal - NonPagedFreesTotal,
  1107. NonPagedBytesTotal,
  1108. PagedAllocsTotal,
  1109. PagedFreesTotal,
  1110. PagedAllocsTotal - PagedFreesTotal,
  1111. PagedBytesTotal);
  1112. }
  1113. free (PoolTrackTableData);
  1114. return S_OK;
  1115. }
  1116. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  1117. BOOLEAN WINAPI
  1118. CheckSingleFilterAndPrint (
  1119. PCHAR Tag,
  1120. PCHAR Filter,
  1121. ULONG Flags,
  1122. ULONG64 PoolHeader,
  1123. ULONG BlockSize,
  1124. ULONG64 Data,
  1125. PVOID Context
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Callback to check a piece of pool and print out information about it
  1130. if it matches the specified tag.
  1131. Arguments:
  1132. Tag - Supplies the tag to search for.
  1133. Filter - Supplies the filter string to match against.
  1134. Flags - Supplies 0 if a nonpaged pool search is desired.
  1135. Supplies 1 if a paged pool search is desired.
  1136. Supplies 2 if a special pool search is desired.
  1137. Supplies 4 if a pool is a large pool
  1138. PoolHeader - Supplies the pool header.
  1139. BlockSize - Supplies the size of the pool block in bytes.
  1140. Data - Supplies the address of the pool block.
  1141. Context - Unused.
  1142. Return Value:
  1143. TRUE for a match, FALSE if not.
  1144. --*/
  1145. {
  1146. ULONG UTag = *((PULONG)Tag);
  1147. ULONG HdrUlong1=0, HdrPoolSize ;
  1148. UNREFERENCED_PARAMETER (Context);
  1149. if (CheckSingleFilter (Tag, Filter) == FALSE) {
  1150. return FALSE;
  1151. }
  1152. HdrPoolSize = GetTypeSize("nt!_POOL_HEADER");
  1153. if ((BlockSize >= (PageSize-2*HdrPoolSize)) || (Flags & 0x4)) {
  1154. dprintf("*%p :%slarge page allocation, Tag %3s %c%c%c%c, size %3s 0x%x bytes\n",
  1155. (Data & ~POOL_BIG_TABLE_ENTRY_FREE),
  1156. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
  1157. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
  1158. PP(UTag),
  1159. PP(UTag >> 8),
  1160. PP(UTag >> 16),
  1161. PP(UTag >> 24),
  1162. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
  1163. BlockSize
  1164. );
  1165. } else if (Flags & 0x2) {
  1166. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  1167. dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
  1168. Data,
  1169. BlockSize,
  1170. HdrUlong1 & MI_SPECIAL_POOL_PAGABLE ? "pagable" : "non-paged",
  1171. PP(UTag),
  1172. PP(UTag >> 8),
  1173. PP(UTag >> 16),
  1174. PP(UTag >> 24)
  1175. );
  1176. } else {
  1177. ULONG BlockSize, PreviousSize, PoolType, PoolIndex, AllocatorBackTraceIndex;
  1178. ULONG PoolTagHash, PoolTag;
  1179. ULONG64 ProcessBilled;
  1180. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  1181. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType);
  1182. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
  1183. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  1184. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
  1185. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  1186. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  1187. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
  1188. dprintf("%p size: %4lx previous size: %4lx ",
  1189. Data - HdrPoolSize,
  1190. BlockSize << POOL_BLOCK_SHIFT,
  1191. PreviousSize << POOL_BLOCK_SHIFT);
  1192. if (PoolType == 0) {
  1193. //
  1194. // "Free " with a space after it before the parentheses means
  1195. // it's been freed to a (pool manager internal) lookaside list.
  1196. // We used to print "Lookaside" but that just confused driver
  1197. // writers because they didn't know if this meant in use or not
  1198. // and many would say "but I don't use lookaside lists - the
  1199. // extension or kernel is broken".
  1200. //
  1201. // "Free" with no space after it before the parentheses means
  1202. // it is not on a pool manager internal lookaside list and is
  1203. // instead on the regular pool manager internal flink/blink
  1204. // chains.
  1205. //
  1206. // Note to anyone using the pool package, these 2 terms are
  1207. // equivalent. The fine distinction is only for those actually
  1208. // writing pool internal code.
  1209. //
  1210. dprintf(" (Free)");
  1211. dprintf(" %c%c%c%c\n",
  1212. PP(UTag),
  1213. PP(UTag >> 8),
  1214. PP(UTag >> 16),
  1215. PP(UTag >> 24)
  1216. );
  1217. } else {
  1218. if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
  1219. dprintf(" (Allocated)");
  1220. } else {
  1221. //
  1222. // "Free " with a space after it before the parentheses means
  1223. // it's been freed to a (pool manager internal) lookaside list.
  1224. // We used to print "Lookaside" but that just confused driver
  1225. // writers because they didn't know if this meant in use or not
  1226. // and many would say "but I don't use lookaside lists - the
  1227. // extension or kernel is broken".
  1228. //
  1229. // "Free" with no space after it before the parentheses means
  1230. // it is not on a pool manager internal lookaside list and is
  1231. // instead on the regular pool manager internal flink/blink
  1232. // chains.
  1233. //
  1234. // Note to anyone using the pool package, these 2 terms are
  1235. // equivalent. The fine distinction is only for those actually
  1236. // writing pool internal code.
  1237. //
  1238. dprintf(" (Free )");
  1239. }
  1240. if ((PoolType & POOL_QUOTA_MASK) == 0) {
  1241. UTag = PoolTag;
  1242. dprintf(" %c%c%c%c%s\n",
  1243. PP(UTag),
  1244. PP(UTag >> 8),
  1245. PP(UTag >> 16),
  1246. PP((UTag &~PROTECTED_POOL) >> 24),
  1247. (UTag & PROTECTED_POOL) ? " (Protected)" : ""
  1248. );
  1249. } else {
  1250. if (ProcessBilled != 0) {
  1251. dprintf(" Process: %08p\n", ProcessBilled );
  1252. }
  1253. }
  1254. }
  1255. }
  1256. return TRUE;
  1257. } // CheckSingleFilterAndPrint
  1258. #undef PP
  1259. ULONG64
  1260. GetNextResidentAddress (
  1261. ULONG64 VirtualAddress,
  1262. ULONG64 MaximumVirtualAddress
  1263. )
  1264. {
  1265. ULONG64 PointerPde;
  1266. ULONG64 PointerPte;
  1267. ULONG SizeOfPte;
  1268. ULONG Valid;
  1269. //
  1270. // Note this code will need to handle one more level of indirection for
  1271. // WIN64.
  1272. //
  1273. if (!(SizeOfPte=GetTypeSize("nt!_MMPTE"))) {
  1274. dprintf("Cannot get MMPTE type.\n");
  1275. return 0;
  1276. }
  1277. top:
  1278. PointerPde = DbgGetPdeAddress (VirtualAddress);
  1279. while (GetFieldValue(PointerPde,
  1280. "nt!_MMPTE",
  1281. "u.Hard.Valid",
  1282. Valid) ||
  1283. (Valid == 0)) {
  1284. //
  1285. // Note that on 32-bit systems, the PDE should always be readable.
  1286. // If the PDE is not valid then increment to the next PDE's VA.
  1287. //
  1288. PointerPde = (PointerPde + SizeOfPte);
  1289. VirtualAddress = DbgGetVirtualAddressMappedByPte (PointerPde);
  1290. VirtualAddress = DbgGetVirtualAddressMappedByPte (VirtualAddress);
  1291. if (VirtualAddress >= MaximumVirtualAddress) {
  1292. return VirtualAddress;
  1293. }
  1294. if (CheckControlC()) {
  1295. return VirtualAddress;
  1296. }
  1297. continue;
  1298. }
  1299. PointerPte = DbgGetPteAddress (VirtualAddress);
  1300. while (GetFieldValue(PointerPde,
  1301. "nt!_MMPTE",
  1302. "u.Hard.Valid",
  1303. Valid) ||
  1304. (Valid == 0)) {
  1305. //
  1306. // If the PTE cannot be read then increment by PAGE_SIZE.
  1307. //
  1308. VirtualAddress = (VirtualAddress + PageSize);
  1309. if (CheckControlC()) {
  1310. return VirtualAddress;
  1311. }
  1312. PointerPte = (PointerPte + SizeOfPte);
  1313. if ((PointerPte & (PageSize - 1)) == 0) {
  1314. goto top;
  1315. }
  1316. if (VirtualAddress >= MaximumVirtualAddress) {
  1317. return VirtualAddress;
  1318. }
  1319. }
  1320. return VirtualAddress;
  1321. }
  1322. VOID
  1323. SearchPool(
  1324. ULONG TagName,
  1325. ULONG Flags,
  1326. ULONG64 RestartAddr,
  1327. POOLFILTER Filter,
  1328. PVOID Context
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. Engine to search the pool.
  1333. Arguments:
  1334. TagName - Supplies the tag to search for.
  1335. Flags - Supplies 0 if a nonpaged pool search is desired.
  1336. Supplies 1 if a paged pool search is desired.
  1337. Supplies 2 if a special pool search is desired.
  1338. RestartAddr - Supplies the address to restart the search from.
  1339. Filter - Supplies the filter routine to use.
  1340. Context - Supplies the user defined context blob.
  1341. Return Value:
  1342. None.
  1343. --*/
  1344. {
  1345. LOGICAL PhysicallyContiguous;
  1346. ULONG PoolBlockSize;
  1347. ULONG64 PoolHeader;
  1348. ULONG PoolTag;
  1349. ULONG Result;
  1350. ULONG64 PoolPage;
  1351. ULONG64 StartPage;
  1352. ULONG64 Pool;
  1353. ULONG Previous;
  1354. ULONG64 PoolStart;
  1355. ULONG64 PoolPteAddress;
  1356. ULONG64 PoolEnd;
  1357. ULONG64 ExpandedPoolStart;
  1358. ULONG64 ExpandedPoolEnd;
  1359. ULONG InitialPoolSize;
  1360. ULONG SkipSize;
  1361. BOOLEAN TwoPools;
  1362. UCHAR DataPage[0x4000]; // MAX pzger size
  1363. ULONG64 DataPageReal;
  1364. ULONG64 DataStartReal;
  1365. LOGICAL Found;
  1366. ULONG i;
  1367. ULONG j;
  1368. ULONG ct;
  1369. ULONG PoolBigPageTableSize;
  1370. ULONG64 PoolTableAddress;
  1371. UCHAR FastTag[4];
  1372. ULONG TagLength;
  1373. ULONG SizeOfBigPages;
  1374. ULONG PoolTypeFlags = Flags & 0x3;
  1375. ULONG Ulong1;
  1376. ULONG HdrSize;
  1377. if (PoolInitializeGlobals() == FALSE) {
  1378. return;
  1379. }
  1380. if (PoolTypeFlags == 2) {
  1381. if (RestartAddr && (RestartAddr >= SpecialPoolStart) && (RestartAddr <= SpecialPoolEnd)) {
  1382. Pool = RestartAddr;
  1383. } else {
  1384. Pool = SpecialPoolStart;
  1385. }
  1386. dprintf("\nSearching special pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
  1387. Pool,
  1388. SpecialPoolEnd,
  1389. TagName,
  1390. TagName >> 8,
  1391. TagName >> 16,
  1392. TagName >> 24);
  1393. Found = FALSE;
  1394. SkipSize = PageSize;
  1395. if (SpecialPoolStart && SpecialPoolEnd) {
  1396. //
  1397. // Search special pool for the tag.
  1398. //
  1399. while (Pool < SpecialPoolEnd) {
  1400. if ( CheckControlC() ) {
  1401. dprintf("\n...terminating - searched pool to %p\n",
  1402. Pool);
  1403. return;
  1404. }
  1405. DataStartReal = Pool;
  1406. DataPageReal = Pool;
  1407. if ( !ReadMemory( Pool,
  1408. &DataPage[0],
  1409. min(PageSize, sizeof(DataPage)),
  1410. &Result) ) {
  1411. ULONG64 PteLong=0, PageFileHigh;
  1412. if (SkipSize != 2 * PageSize) {
  1413. // dprintf("SP skip %x", Pool);
  1414. PoolPteAddress = DbgGetPteAddress (Pool);
  1415. if (!GetFieldValue(PoolPteAddress,
  1416. "nt!_MMPTE",
  1417. "u.Soft.PageFileHigh",
  1418. PageFileHigh) ) {
  1419. if ((PageFileHigh == 0) ||
  1420. (PageFileHigh == MI_SPECIAL_POOL_PTE_PAGABLE) ||
  1421. (PageFileHigh == MI_SPECIAL_POOL_PTE_NONPAGABLE)) {
  1422. //
  1423. // Found a NO ACCESS PTE - skip these from
  1424. // here on to speed up the search.
  1425. //
  1426. // dprintf("SP skip double %p", PoolPteAddress);
  1427. SkipSize = 2 * PageSize;
  1428. Pool += PageSize;
  1429. // dprintf("SP skip final %p", Pool);
  1430. continue;
  1431. }
  1432. }
  1433. }
  1434. Pool += SkipSize;
  1435. continue;
  1436. }
  1437. //
  1438. // Determine whether this is a valid special pool block.
  1439. //
  1440. PoolHeader = GetSpecialPoolHeader (DataPage,
  1441. DataPageReal,
  1442. &DataStartReal);
  1443. if (PoolHeader != 0) {
  1444. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  1445. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Ulong1);
  1446. PoolBlockSize = (ULONG) SPECIAL_POOL_BLOCK_SIZE(Ulong1);
  1447. Found = Filter( (PCHAR)&PoolTag,
  1448. (PCHAR)&TagName,
  1449. Flags,
  1450. PoolHeader,
  1451. PoolBlockSize,
  1452. DataStartReal,
  1453. Context );
  1454. } else {
  1455. dprintf( "No pool header for page: 0x%p\n", Pool );
  1456. }
  1457. Pool += SkipSize;
  1458. }
  1459. }
  1460. if (Found == FALSE) {
  1461. dprintf("The %c%c%c%c tag could not be found in special pool.\n",
  1462. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  1463. PP(TagName),
  1464. PP(TagName >> 8),
  1465. PP(TagName >> 16),
  1466. PP(TagName >> 24)
  1467. );
  1468. #undef PP
  1469. }
  1470. return;
  1471. }
  1472. if (PoolTypeFlags == 0) {
  1473. PhysicallyContiguous = TRUE;
  1474. } else {
  1475. PhysicallyContiguous = FALSE;
  1476. }
  1477. __try {
  1478. TwoPools = FALSE;
  1479. if (!PoolBigTableAddress) {
  1480. PoolBigTableAddress = GetPointerValue ("PoolBigPageTable");
  1481. }
  1482. PoolTableAddress = PoolBigTableAddress;
  1483. if (PoolTableAddress) {
  1484. ULONG VaOffset;
  1485. ULONG NumPagesOffset;
  1486. ULONG PtrSize;
  1487. ULONG KeyOffset;
  1488. PoolBigPageTableSize = GetUlongValue ("PoolBigPageTableSize");
  1489. //
  1490. // Scan the table looking for a match. We read close to a page at a time
  1491. // physical page / sizeof ( pool_tracker_big_page ) * sizeof ( pool_tracker_big_page )
  1492. // on x86 this works out to ffc
  1493. //
  1494. i = 0;
  1495. SizeOfBigPages = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
  1496. if (!SizeOfBigPages) {
  1497. dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
  1498. return;
  1499. }
  1500. ct = PageSize / SizeOfBigPages;
  1501. dprintf( "\nScanning large pool allocation table for Tag: %c%c%c%c (%p : %p)\n\n\r",
  1502. TagName,
  1503. TagName >> 8,
  1504. TagName >> 16,
  1505. TagName >> 24,
  1506. PoolBigTableAddress,
  1507. PoolBigTableAddress + PoolBigPageTableSize * SizeOfBigPages );
  1508. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Va", &VaOffset );
  1509. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "NumberOfPages", &NumPagesOffset );
  1510. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Key", &KeyOffset );
  1511. PtrSize = IsPtr64() ? 8 : 4;
  1512. while (i < PoolBigPageTableSize) {
  1513. if (PoolBigPageTableSize - i < ct) {
  1514. ct = PoolBigPageTableSize - i;
  1515. }
  1516. if ( !ReadMemory( PoolTableAddress,
  1517. &DataPage[0],
  1518. ct * SizeOfBigPages,
  1519. &Result) ) {
  1520. dprintf( "%08lx: Unable to get contents of big pool block\r\n", PoolTableAddress );
  1521. break;
  1522. }
  1523. for (j = 0; j < ct; j += 1) {
  1524. ULONG64 Va = 0;
  1525. memcpy( &Va, (PCHAR)DataPage + (SizeOfBigPages * j) + VaOffset, PtrSize );
  1526. Filter( ((PCHAR)DataPage + (SizeOfBigPages * j) + KeyOffset),
  1527. (PCHAR)&TagName,
  1528. Flags | 0x4, // To assist filter routine to recognize this as large pool
  1529. PoolTableAddress + SizeOfBigPages * j,
  1530. (*((PULONG)((PCHAR)DataPage + (SizeOfBigPages * j) + NumPagesOffset))) * PageSize,
  1531. Va,
  1532. Context );
  1533. if ( CheckControlC() ) {
  1534. dprintf("\n...terminating - searched pool to %p\n",
  1535. PoolTableAddress + j * SizeOfBigPages);
  1536. return;
  1537. }
  1538. }
  1539. i += ct;
  1540. PoolTableAddress += (ct * SizeOfBigPages);
  1541. if ( CheckControlC() ) {
  1542. dprintf("\n...terminating - searched pool to %p\n",
  1543. PoolTableAddress);
  1544. return;
  1545. }
  1546. }
  1547. } else {
  1548. dprintf("unable to get large pool allocation table - either wrong symbols or pool tagging is disabled\n");
  1549. }
  1550. if (PoolTypeFlags == 0) {
  1551. PoolStart = GetNtDebuggerDataPtrValue( MmNonPagedPoolStart );
  1552. if (0 == PoolStart) {
  1553. dprintf( "Unable to get MmNonPagedPoolStart\n" );
  1554. }
  1555. PoolEnd =
  1556. PoolStart + GetNtDebuggerDataValue( MmMaximumNonPagedPoolInBytes );
  1557. ExpandedPoolEnd = GetNtDebuggerDataPtrValue( MmNonPagedPoolEnd );
  1558. if (PoolEnd != ExpandedPoolEnd) {
  1559. InitialPoolSize = (ULONG)GetUlongValue( "MmSizeOfNonPagedPoolInBytes" );
  1560. PoolEnd = PoolStart + InitialPoolSize;
  1561. ExpandedPoolStart = GetPointerValue( "MmNonPagedPoolExpansionStart" );
  1562. TwoPools = TRUE;
  1563. }
  1564. for (TagLength = 0;TagLength < 3; TagLength++) {
  1565. if ((*(((PCHAR)&TagName)+TagLength) == '?') ||
  1566. (*(((PCHAR)&TagName)+TagLength) == '*')) {
  1567. break;
  1568. }
  1569. FastTag[TagLength] = *(((PCHAR)&TagName)+TagLength);
  1570. }
  1571. } else {
  1572. PoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
  1573. PoolEnd =
  1574. PoolStart + GetNtDebuggerDataValue( MmSizeOfPagedPoolInBytes );
  1575. }
  1576. if (RestartAddr) {
  1577. PoolStart = RestartAddr;
  1578. if (TwoPools == TRUE) {
  1579. if (PoolStart > PoolEnd) {
  1580. TwoPools = FALSE;
  1581. PoolStart = RestartAddr;
  1582. PoolEnd = ExpandedPoolEnd;
  1583. }
  1584. }
  1585. }
  1586. dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
  1587. (PoolTypeFlags == 0) ? "NonPaged" : "Paged",
  1588. PoolStart,
  1589. PoolEnd,
  1590. TagName,
  1591. TagName >> 8,
  1592. TagName >> 16,
  1593. TagName >> 24);
  1594. PoolPage = PoolStart;
  1595. HdrSize = GetTypeSize("nt!_POOL_HEADER");
  1596. while (PoolPage < PoolEnd) {
  1597. //
  1598. // Optimize things by ioctl'ing over to the other side to
  1599. // do a fast search and start with that page.
  1600. //
  1601. if ((PoolTypeFlags == 0) &&
  1602. PhysicallyContiguous &&
  1603. (TagLength > 0)) {
  1604. SEARCHMEMORY Search;
  1605. Search.SearchAddress = PoolPage;
  1606. Search.SearchLength = PoolEnd-PoolPage;
  1607. Search.PatternLength = TagLength;
  1608. Search.Pattern = &FastTag;
  1609. Search.FoundAddress = 0;
  1610. if ((Ioctl(IG_SEARCH_MEMORY, &Search, sizeof(Search))) &&
  1611. (Search.FoundAddress != 0)) {
  1612. //
  1613. // Got a hit, search the whole page
  1614. //
  1615. PoolPage = PAGE_ALIGN64(Search.FoundAddress);
  1616. } else {
  1617. //
  1618. // The tag was not found at all, so we can just skip
  1619. // this chunk entirely.
  1620. //
  1621. PoolPage = PoolEnd;
  1622. goto skiprange;
  1623. }
  1624. }
  1625. Pool = PAGE_ALIGN64 (PoolPage);
  1626. StartPage = Pool;
  1627. Previous = 0;
  1628. while (PAGE_ALIGN64(Pool) == StartPage) {
  1629. ULONG HdrPoolTag, BlockSize, PreviousSize, AllocatorBackTraceIndex, PoolTagHash;
  1630. ULONG PoolType;
  1631. if ( GetFieldValue(Pool,
  1632. "nt!_POOL_HEADER",
  1633. "PoolTag",
  1634. HdrPoolTag) ) {
  1635. PoolPage = GetNextResidentAddress (Pool, PoolEnd);
  1636. //
  1637. // If we're half resident - half non-res then we'll get back
  1638. // that are starting address is the next resident page. In that
  1639. // case just go on to the next page
  1640. //
  1641. if (PoolPage == Pool) {
  1642. PoolPage = PoolPage + PageSize;
  1643. }
  1644. goto nextpage;
  1645. }
  1646. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTag",HdrPoolTag);
  1647. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolType", PoolType);
  1648. GetFieldValue(Pool,"nt!_POOL_HEADER","BlockSize",BlockSize);
  1649. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTagHash",PoolTagHash);
  1650. GetFieldValue(Pool,"nt!_POOL_HEADER","PreviousSize",PreviousSize);
  1651. GetFieldValue(Pool,"nt!_POOL_HEADER","AllocatorBackTraceIndex",AllocatorBackTraceIndex);
  1652. if ((BlockSize << POOL_BLOCK_SHIFT) > POOL_PAGE_SIZE) {
  1653. //dprintf("Bad allocation size @%lx, too large\n", Pool);
  1654. break;
  1655. }
  1656. if (BlockSize == 0) {
  1657. //dprintf("Bad allocation size @%lx, zero is invalid\n", Pool);
  1658. break;
  1659. }
  1660. if (PreviousSize != Previous) {
  1661. //dprintf("Bad previous allocation size @%lx, last size was %lx\n",Pool, Previous);
  1662. break;
  1663. }
  1664. PoolTag = HdrPoolTag;
  1665. Filter((PCHAR)&PoolTag,
  1666. (PCHAR)&TagName,
  1667. Flags,
  1668. Pool,
  1669. BlockSize << POOL_BLOCK_SHIFT,
  1670. Pool + HdrSize,
  1671. Context );
  1672. Previous = BlockSize;
  1673. Pool += (Previous << POOL_BLOCK_SHIFT);
  1674. if ( CheckControlC() ) {
  1675. dprintf("\n...terminating - searched pool to %p\n",
  1676. PoolPage);
  1677. return;
  1678. }
  1679. }
  1680. PoolPage = (PoolPage + PageSize);
  1681. nextpage:
  1682. if ( CheckControlC() ) {
  1683. dprintf("\n...terminating - searched pool to %p\n",
  1684. PoolPage);
  1685. return;
  1686. }
  1687. skiprange:
  1688. if (TwoPools == TRUE) {
  1689. if (PoolPage == PoolEnd) {
  1690. TwoPools = FALSE;
  1691. PoolStart = ExpandedPoolStart;
  1692. PoolEnd = ExpandedPoolEnd;
  1693. PoolPage = PoolStart;
  1694. PhysicallyContiguous = FALSE;
  1695. dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\n\n",
  1696. "NonPaged",
  1697. PoolStart,
  1698. PoolEnd,
  1699. TagName,
  1700. TagName >> 8,
  1701. TagName >> 16,
  1702. TagName >> 24);
  1703. }
  1704. }
  1705. }
  1706. } __finally {
  1707. }
  1708. return;
  1709. } // SearchPool
  1710. DECLARE_API( poolfind )
  1711. /*++
  1712. Routine Description:
  1713. flags == 0 means finds a tag in nonpaged pool.
  1714. flags == 1 means finds a tag in paged pool.
  1715. flags == 2 means finds a tag in special pool.
  1716. Arguments:
  1717. args -
  1718. Return Value:
  1719. None
  1720. --*/
  1721. {
  1722. ULONG Flags;
  1723. CHAR TagNameX[4] = {' ',' ',' ',' '};
  1724. ULONG TagName;
  1725. ULONG64 PoolTrackTable;
  1726. Flags = 0;
  1727. if (!sscanf(args,"%c%c%c%c %lx", &TagNameX[0],
  1728. &TagNameX[1], &TagNameX[2], &TagNameX[3], &Flags)) {
  1729. Flags = 0;
  1730. }
  1731. if (TagNameX[0] == '0' && TagNameX[1] == 'x') {
  1732. if (!sscanf( args, "%lx %lx", &TagName, &Flags )) {
  1733. TagName = 0;
  1734. }
  1735. } else {
  1736. TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
  1737. }
  1738. PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
  1739. if (PoolTrackTable == 0) {
  1740. dprintf ("unable to get PoolTrackTable - probably pool tagging disabled or wrong symbols\n");
  1741. }
  1742. SearchPool( TagName, Flags, 0, CheckSingleFilterAndPrint, NULL );
  1743. return S_OK;
  1744. }
  1745. BOOLEAN
  1746. CheckSingleFilter (
  1747. PCHAR Tag,
  1748. PCHAR Filter
  1749. )
  1750. {
  1751. ULONG i;
  1752. UCHAR tc;
  1753. UCHAR fc;
  1754. for ( i = 0; i < 4; i++ ) {
  1755. tc = (UCHAR) *Tag++;
  1756. fc = (UCHAR) *Filter++;
  1757. if ( fc == '*' ) return TRUE;
  1758. if ( fc == '?' ) continue;
  1759. if (i == 3 && (tc & ~(PROTECTED_POOL >> 24)) == fc) continue;
  1760. if ( tc != fc ) return FALSE;
  1761. }
  1762. return TRUE;
  1763. }
  1764. ULONG64
  1765. GetSpecialPoolHeader (
  1766. IN PVOID DataPage,
  1767. IN ULONG64 RealDataPage,
  1768. OUT PULONG64 ReturnedDataStart
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. Examine a page of data to determine if it is a special pool block.
  1773. Arguments:
  1774. DataPage - Supplies a pointer to a page of data to examine.
  1775. ReturnedDataStart - Supplies a pointer to return the start of the data.
  1776. Only valid if this routine returns non-NULL.
  1777. Return Value:
  1778. Returns a pointer to the pool header for this special pool block or
  1779. NULL if the block is not valid special pool.
  1780. --*/
  1781. {
  1782. ULONG PoolBlockSize;
  1783. ULONG PoolHeaderSize;
  1784. ULONG PoolBlockPattern;
  1785. PUCHAR p;
  1786. PUCHAR PoolDataEnd;
  1787. PUCHAR DataStart;
  1788. ULONG64 PoolHeader;
  1789. ULONG HdrUlong1;
  1790. PoolHeader = RealDataPage;
  1791. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  1792. //
  1793. // Determine whether the data is at the start or end of the page.
  1794. // Start off by assuming the data is at the end, in this case the
  1795. // header will be at the start.
  1796. //
  1797. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
  1798. if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
  1799. PoolHeaderSize = POOL_OVERHEAD;
  1800. if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
  1801. PoolHeaderSize += GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
  1802. }
  1803. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
  1804. DataStart = (PUCHAR)DataPage + PageSize - PoolBlockSize;
  1805. p = (PUCHAR)DataPage + PoolHeaderSize;
  1806. for ( ; p < DataStart; p += 1) {
  1807. if (*p != PoolBlockPattern) {
  1808. break;
  1809. }
  1810. }
  1811. if (p == DataStart || p >= (PUCHAR)DataPage + PoolHeaderSize + 0x10) {
  1812. //
  1813. // For this page, the data is at the end of the block.
  1814. // The 0x10 is just to give corrupt blocks some slack.
  1815. // All pool allocations are quadword aligned.
  1816. //
  1817. DataStart = (PUCHAR)DataPage + ((PageSize - PoolBlockSize) & ~(sizeof(QUAD)-1));
  1818. *ReturnedDataStart = RealDataPage + (ULONG64) ((PUCHAR) DataStart - (PUCHAR) DataPage);
  1819. return PoolHeader;
  1820. }
  1821. //
  1822. // The data must be at the front or the block is corrupt.
  1823. //
  1824. }
  1825. //
  1826. // Try for the data at the front. Checks are necessary as
  1827. // the page could be corrupt on both ends.
  1828. //
  1829. PoolHeader = (RealDataPage + PageSize - POOL_OVERHEAD);
  1830. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  1831. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
  1832. if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
  1833. PoolDataEnd = (PUCHAR)PoolHeader;
  1834. if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
  1835. PoolDataEnd -= GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
  1836. }
  1837. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
  1838. DataStart = (PUCHAR)DataPage;
  1839. p = DataStart + PoolBlockSize;
  1840. for ( ; p < PoolDataEnd; p += 1) {
  1841. if (*p != PoolBlockPattern) {
  1842. break;
  1843. }
  1844. }
  1845. if (p == (PUCHAR)PoolDataEnd || p > (PUCHAR)DataPage + PoolBlockSize + 0x10) {
  1846. //
  1847. // For this page, the data is at the front of the block.
  1848. // The 0x10 is just to give corrupt blocks some slack.
  1849. // All pool allocations are quadword aligned.
  1850. //
  1851. *ReturnedDataStart = RealDataPage + (ULONG64)( (PUCHAR)DataStart - (PUCHAR) DataPage);
  1852. return PoolHeader;
  1853. }
  1854. }
  1855. //
  1856. // Not valid special pool.
  1857. //
  1858. return 0;
  1859. }
  1860. #define BYTE(u,n) ((u & (0xff << 8*n)) >> 8*n)
  1861. #define LOCHAR_BYTE(u,n) (tolower(BYTE(u,n)) & 0xff)
  1862. #define REVERSE_ULONGBYTES(u) (LOCHAR_BYTE(u,3) | (LOCHAR_BYTE(u,2) << 8) | (LOCHAR_BYTE(u,1) << 16) | (LOCHAR_BYTE(u,0) << 24))
  1863. PSTR
  1864. GetNextLine(
  1865. HANDLE hFile
  1866. )
  1867. // Returns next line in the file hFile
  1868. // Returns NULL if EOF is reached
  1869. {
  1870. static CHAR FileLines1[MAX_PATH] = {0}, FileLines2[MAX_PATH] = {0};
  1871. static CHAR FileLine[MAX_PATH];
  1872. PCHAR pEOL;
  1873. ULONG BytesRead;
  1874. PCHAR pEndOfBuff;
  1875. ULONG BuffLen, ReadLen;
  1876. pEOL = NULL;
  1877. if (!(pEOL = strchr(FileLines1, '\n'))) {
  1878. // We have something that was already read but it isn't enough for a whole line
  1879. // We need to read the data
  1880. BuffLen = strlen(FileLines1);
  1881. // sanity check
  1882. if (BuffLen >= sizeof(FileLines1)) {
  1883. return NULL;
  1884. }
  1885. pEndOfBuff = &FileLines1[0] + BuffLen;
  1886. ReadLen = sizeof(FileLines1) - BuffLen;
  1887. ZeroMemory(pEndOfBuff, ReadLen);
  1888. if (ReadFile(hFile, pEndOfBuff, ReadLen - 1, &BytesRead, NULL)) {
  1889. pEOL = strchr(FileLines1, '\n');
  1890. }
  1891. }
  1892. if (pEOL) {
  1893. FileLine[0] = 0;
  1894. strncat(FileLine,FileLines1, (ULONG) (pEOL - &FileLines1[0]));
  1895. strcpy(FileLines2, pEOL+1);
  1896. strcpy(FileLines1, FileLines2);
  1897. return FileLine;
  1898. }
  1899. return NULL;
  1900. }
  1901. EXTENSION_API ( GetPoolRegion )(
  1902. PDEBUG_CLIENT Client,
  1903. ULONG64 Pool,
  1904. DEBUG_POOL_REGION *PoolData
  1905. )
  1906. {
  1907. INIT_API();
  1908. *PoolData = GetPoolRegion(Pool);
  1909. EXIT_API();
  1910. return S_OK;
  1911. }
  1912. EXTENSION_API ( GetPoolData )(
  1913. PDEBUG_CLIENT Client,
  1914. ULONG64 Pool,
  1915. PDEBUG_POOL_DATA PoolData
  1916. )
  1917. {
  1918. PCHAR Desc;
  1919. HRESULT Hr;
  1920. PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
  1921. INIT_API();
  1922. if (!PoolInitializeGlobals()) {
  1923. EXIT_API();
  1924. return E_INVALIDARG;
  1925. }
  1926. Hr = ListPoolPage(Pool, 0x80000002, PoolData);
  1927. if (Hr != S_OK) {
  1928. EXIT_API();
  1929. return Hr;
  1930. }
  1931. GetPoolTagDescription = NULL;
  1932. #ifndef _EXTFNS_H
  1933. if (!GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription)) {
  1934. EXIT_API();
  1935. return E_INVALIDARG;
  1936. }
  1937. (*GetPoolTagDescription)(PoolData->PoolTag, &Desc);
  1938. if (Desc) {
  1939. ULONG strsize = strlen(Desc);
  1940. if (strsize > sizeof(PoolData->PoolTagDescription)) {
  1941. strsize = sizeof(PoolData->PoolTagDescription);
  1942. }
  1943. strncpy(PoolData->PoolTagDescription, Desc, strsize);
  1944. PoolData->PoolTagDescription[strsize] = 0;
  1945. }
  1946. #endif
  1947. EXIT_API();
  1948. return Hr;
  1949. }