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.

5195 lines
151 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. #define TAG 0
  18. #define NONPAGED_ALLOC 1
  19. #define NONPAGED_FREE 2
  20. #define PAGED_ALLOC 3
  21. #define PAGED_FREE 4
  22. #define NONPAGED_USED 5
  23. #define PAGED_USED 6
  24. BOOL NewPool;
  25. ULONG SortBy;
  26. typedef struct _FILTER {
  27. ULONG Tag;
  28. BOOLEAN Exclude;
  29. } FILTER, *PFILTER;
  30. typedef struct _POOLTRACK_READ {
  31. ULONG64 Address;
  32. ULONG Key;
  33. ULONG NonPagedAllocs;
  34. ULONG NonPagedFrees;
  35. ULONG PagedAllocs;
  36. ULONG PagedFrees;
  37. LONG64 NonPagedBytes;
  38. LONG64 PagedBytes;
  39. } POOLTRACK_READ, *PPOOLTRACK_READ;
  40. #define MAX_FILTER 64
  41. FILTER Filter[MAX_FILTER];
  42. ULONG64 SpecialPoolStart;
  43. ULONG64 SpecialPoolEnd;
  44. ULONG64 PoolBigTableAddress;
  45. #define DecodeLink(Pool) ( (ULONG64) (Pool & (ULONG64) ~1))
  46. //
  47. // Size of a pool page.
  48. //
  49. // This must be greater than or equal to the page size.
  50. //
  51. #define POOL_PAGE_SIZE PageSize
  52. #define MAX_POOL_HEADER_COUNT (PageSize/SizeOfPoolHdr)
  53. //
  54. // The smallest pool block size must be a multiple of the page size.
  55. //
  56. // Define the block size as 32.
  57. //
  58. #define POOL_LIST_HEADS (POOL_PAGE_SIZE / (1 << POOL_BLOCK_SHIFT))
  59. #define SPECIAL_POOL_BLOCK_SIZE(PoolHeader_Ulong1) (PoolHeader_Ulong1 & (MI_SPECIAL_POOL_VERIFIER - 1))
  60. NTSTATUS
  61. DiagnosePoolPage(
  62. ULONG64 PoolPageToDump
  63. );
  64. #ifndef _EXTFNS_H
  65. // GetPoolTagDescription
  66. typedef HRESULT
  67. (WINAPI *PGET_POOL_TAG_DESCRIPTION)(
  68. ULONG PoolTag,
  69. PSTR *pDescription
  70. );
  71. #endif
  72. ULONG64
  73. GetSpecialPoolHeader (
  74. IN PVOID pDataPage,
  75. IN ULONG64 RealDataPage,
  76. OUT PULONG64 ReturnedDataStart
  77. );
  78. int __cdecl
  79. ulcomp(const void *e1,const void *e2)
  80. {
  81. PPOOLTRACK_READ p1, p2;
  82. ULONG u1;
  83. p1 = (PPOOLTRACK_READ) e1;
  84. p2 = (PPOOLTRACK_READ) e2;
  85. switch (SortBy) {
  86. case TAG:
  87. u1 = ((PUCHAR)&p1->Key)[0] - ((PUCHAR)&p2->Key)[0];
  88. if (u1 != 0) {
  89. return u1;
  90. }
  91. u1 = ((PUCHAR)&p1->Key)[1] - ((PUCHAR)&p2->Key)[1];
  92. if (u1 != 0) {
  93. return u1;
  94. }
  95. u1 = ((PUCHAR)&p1->Key)[2] - ((PUCHAR)&p2->Key)[2];
  96. if (u1 != 0) {
  97. return u1;
  98. }
  99. u1 = ((PUCHAR)&p1->Key)[3] - ((PUCHAR)&p2->Key)[3];
  100. return u1;
  101. case NONPAGED_ALLOC:
  102. if (p2->NonPagedAllocs == p1->NonPagedAllocs) {
  103. return 0;
  104. }
  105. if (p2->NonPagedAllocs > p1->NonPagedAllocs) {
  106. return 1;
  107. }
  108. return -1;
  109. case NONPAGED_FREE:
  110. if (p2->NonPagedFrees == p1->NonPagedFrees) {
  111. return 0;
  112. }
  113. if (p2->NonPagedFrees > p1->NonPagedFrees) {
  114. return 1;
  115. }
  116. return -1;
  117. case NONPAGED_USED:
  118. if (p2->NonPagedBytes == p1->NonPagedBytes) {
  119. return 0;
  120. }
  121. if (p2->NonPagedBytes > p1->NonPagedBytes) {
  122. return 1;
  123. }
  124. return -1;
  125. case PAGED_USED:
  126. if (p2->PagedBytes == p1->PagedBytes) {
  127. return 0;
  128. }
  129. if (p2->PagedBytes > p1->PagedBytes) {
  130. return 1;
  131. }
  132. return -1;
  133. default:
  134. break;
  135. }
  136. return 0;
  137. }
  138. /*++
  139. Routine Description:
  140. Sets up generally useful pool globals.
  141. Must be called in every DECLARE_API interface that uses pool.
  142. Arguments:
  143. None.
  144. Return Value:
  145. None
  146. --*/
  147. LOGICAL PoolInitialized = FALSE;
  148. LOGICAL
  149. PoolInitializeGlobals(
  150. VOID
  151. )
  152. {
  153. if (PoolInitialized == TRUE) {
  154. return TRUE;
  155. }
  156. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  157. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  158. if (PageSize < 0x1000 || (PageSize & (ULONG)0xFFF)) {
  159. dprintf ("unable to get MmPageSize (0x%x) - probably bad symbols\n", PageSize);
  160. return FALSE;
  161. }
  162. PoolInitialized = TRUE;
  163. return TRUE;
  164. }
  165. DECLARE_API( frag )
  166. /*++
  167. Routine Description:
  168. Dump pool fragmentation
  169. Arguments:
  170. args - Flags
  171. Return Value:
  172. None
  173. --*/
  174. {
  175. ULONG Flags;
  176. ULONG result;
  177. ULONG i;
  178. ULONG count;
  179. ULONG64 Pool;
  180. ULONG64 PoolLoc1;
  181. ULONG TotalFrag;
  182. ULONG TotalCount;
  183. ULONG Frag;
  184. ULONG64 PoolStart;
  185. ULONG PoolOverhead;
  186. ULONG64 PoolLoc;
  187. ULONG PoolTag, BlockSize, PreviousSize, PoolIndex;
  188. ULONG TotalPages, TotalBigPages;
  189. ULONG64 Flink, Blink;
  190. PCHAR pc;
  191. ULONG ListHeadOffset, ListEntryOffset;
  192. ULONG64 tmp;
  193. #define PoolBlk(F,V) GetFieldValue(Pool, "nt!_POOL_HEADER", #F, V)
  194. if (PoolInitializeGlobals() == FALSE) {
  195. return E_INVALIDARG;
  196. }
  197. dprintf("\n NonPaged Pool Fragmentation\n\n");
  198. Flags = 0;
  199. PoolStart = 0;
  200. if (GetExpressionEx(args, &tmp, &args)) {
  201. Flags = (ULONG) tmp;
  202. PoolStart = GetExpression (args);
  203. }
  204. PoolOverhead = GetTypeSize("nt!_POOL_HEADER");
  205. if (PoolStart != 0) {
  206. PoolStart += PoolOverhead;
  207. Pool = DecodeLink(PoolStart);
  208. do {
  209. Pool = Pool - PoolOverhead;
  210. if ( PoolBlk(k, PoolTag) ) {
  211. dprintf("%08p: Unable to get contents of pool block\n", Pool );
  212. return E_INVALIDARG;
  213. }
  214. PoolBlk(BlockSize,BlockSize);
  215. PoolBlk(PreviousSize,PreviousSize);
  216. ReadPointer(Pool + PoolOverhead, &Flink);
  217. ReadPointer(Pool + PoolOverhead + DBG_PTR_SIZE, &Blink);
  218. dprintf(" %p size: %4lx previous size: %4lx %c%c%c%c links: %8p %8p\n",
  219. Pool,
  220. (ULONG)BlockSize << POOL_BLOCK_SHIFT,
  221. (ULONG)PreviousSize << POOL_BLOCK_SHIFT,
  222. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  223. PP(PoolTag),
  224. PP(PoolTag >> 8),
  225. PP(PoolTag >> 16),
  226. PP((PoolTag&~PROTECTED_POOL) >> 24),
  227. #undef PP
  228. Flink,
  229. Blink);
  230. if (Flags != 3) {
  231. Pool = Flink;
  232. } else {
  233. Pool = Blink;
  234. }
  235. Pool = DecodeLink(Pool);
  236. if (CheckControlC()) {
  237. return E_INVALIDARG;
  238. }
  239. } while ( (Pool & (ULONG64) ~0xf) != (PoolStart & (ULONG64) ~0xf) );
  240. return E_INVALIDARG;
  241. }
  242. PoolLoc1 = GetNtDebuggerData( NonPagedPoolDescriptor );
  243. if (PoolLoc1 == 0) {
  244. dprintf ("unable to get nonpaged pool head\n");
  245. return E_INVALIDARG;
  246. }
  247. PoolLoc = PoolLoc1;
  248. GetFieldOffset("nt!_POOL_DESCRIPTOR", "ListHeads", &ListHeadOffset);
  249. TotalFrag = 0;
  250. TotalCount = 0;
  251. for (i = 0; i < POOL_LIST_HEADS; i += 1) {
  252. Frag = 0;
  253. count = 0;
  254. // Get Offset of this entry
  255. ListEntryOffset = ListHeadOffset + i * 2 * DBG_PTR_SIZE;
  256. if (GetFieldValue(PoolLoc + ListEntryOffset, "nt!_LIST_ENTRY", "Flink", Pool)) {
  257. dprintf ("Unable to get pool descriptor list entry %#lx, %p\n", i, PoolLoc1);
  258. return E_INVALIDARG;
  259. }
  260. // Pool = (PUCHAR)PoolDesc.ListHeads[i].Flink;
  261. Pool = DecodeLink(Pool);
  262. while (Pool != (ListEntryOffset + PoolLoc)) {
  263. Pool = Pool - PoolOverhead;
  264. if ( PoolBlk(PoolTag, PoolTag) ) {
  265. dprintf("%08p: Unable to get contents of pool block\n", Pool );
  266. return E_INVALIDARG;
  267. }
  268. PoolBlk(BlockSize,BlockSize);
  269. PoolBlk(PreviousSize,PreviousSize);
  270. ReadPointer(Pool + PoolOverhead, &Flink);
  271. ReadPointer(Pool + PoolOverhead + DBG_PTR_SIZE, &Blink);
  272. Frag += BlockSize << POOL_BLOCK_SHIFT;
  273. count += 1;
  274. if (Flags & 2) {
  275. dprintf(" ListHead[%x]: %p size: %4lx previous size: %4lx %c%c%c%c\n",
  276. i,
  277. (ULONG)Pool,
  278. (ULONG)BlockSize << POOL_BLOCK_SHIFT,
  279. (ULONG)PreviousSize << POOL_BLOCK_SHIFT,
  280. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  281. PP(PoolTag),
  282. PP(PoolTag >> 8),
  283. PP(PoolTag >> 16),
  284. PP((PoolTag&~PROTECTED_POOL) >> 24));
  285. #undef PP
  286. }
  287. Pool = Flink;
  288. Pool = DecodeLink(Pool);
  289. if (CheckControlC()) {
  290. return E_INVALIDARG;
  291. }
  292. }
  293. if (Flags & 1) {
  294. dprintf("index: %2ld number of fragments: %5ld bytes: %6ld\n",
  295. i,count,Frag);
  296. }
  297. TotalFrag += Frag;
  298. TotalCount += count;
  299. }
  300. dprintf("\n Number of fragments: %7ld consuming %7ld bytes\n",
  301. TotalCount,TotalFrag);
  302. GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalPages",TotalPages);
  303. GetFieldValue(PoolLoc, "nt!_POOL_DESCRIPTOR", "TotalBigPages", TotalBigPages);
  304. dprintf( " NonPagedPool Usage: %7ld bytes\n",(TotalPages + TotalBigPages)*PageSize);
  305. return S_OK;
  306. #undef PoolBlk
  307. }
  308. PRTL_BITMAP
  309. GetBitmap(
  310. ULONG64 pBitmap
  311. )
  312. {
  313. PRTL_BITMAP p;
  314. ULONG Size, Result;
  315. ULONG64 Buffer=0;
  316. if (!pBitmap || GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "Buffer", Buffer)) {
  317. dprintf("%08p: Unable to get contents of bitmap\n", pBitmap );
  318. return 0;
  319. }
  320. GetFieldValue(pBitmap, "nt!_RTL_BITMAP", "SizeOfBitMap", Size);
  321. p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) + (Size / 8) );
  322. if (p) {
  323. p->SizeOfBitMap = Size;
  324. p->Buffer = (PULONG)(p + 1);
  325. if ( !ReadMemory( Buffer,
  326. p->Buffer,
  327. Size / 8,
  328. &Result) ) {
  329. dprintf("%08p: Unable to get contents of bitmap buffer\n", Buffer );
  330. HeapFree( GetProcessHeap(), 0, p );
  331. p = NULL;
  332. }
  333. }
  334. return p;
  335. }
  336. VOID
  337. DumpPool(
  338. VOID
  339. )
  340. {
  341. ULONG64 p, pStart;
  342. ULONG64 Size;
  343. ULONG BusyFlag;
  344. ULONG CurrentPage, NumberOfPages;
  345. PRTL_BITMAP StartMap;
  346. PRTL_BITMAP EndMap;
  347. ULONG64 PagedPoolStart;
  348. ULONG64 PagedPoolEnd;
  349. ULONG Result;
  350. UCHAR PgPool[] = "nt!_MM_PAGED_POOL_INFO";
  351. ULONG64 PagedPoolInfoPointer;
  352. ULONG64 PagedPoolAllocationMap=0, EndOfPagedPoolBitmap=0;
  353. if (PoolInitializeGlobals() == FALSE) {
  354. return;
  355. }
  356. PagedPoolInfoPointer = GetNtDebuggerData( MmPagedPoolInformation );
  357. if ( GetFieldValue( PagedPoolInfoPointer,
  358. PgPool,
  359. "PagedPoolAllocationMap",
  360. PagedPoolAllocationMap)) {
  361. dprintf("%08p: Unable to get contents of paged pool information\n",
  362. PagedPoolInfoPointer );
  363. return;
  364. }
  365. GetFieldValue( PagedPoolInfoPointer, PgPool, "EndOfPagedPoolBitmap", EndOfPagedPoolBitmap);
  366. StartMap = GetBitmap( PagedPoolAllocationMap );
  367. EndMap = GetBitmap( EndOfPagedPoolBitmap );
  368. PagedPoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
  369. PagedPoolEnd = GetNtDebuggerDataPtrValue( MmPagedPoolEnd );
  370. if (StartMap && EndMap) {
  371. p = PagedPoolStart;
  372. CurrentPage = 0;
  373. dprintf( "Paged Pool: %p .. %p\n", PagedPoolStart, PagedPoolEnd );
  374. while (p < PagedPoolEnd) {
  375. if ( CheckControlC() ) {
  376. return;
  377. }
  378. pStart = p;
  379. BusyFlag = RtlCheckBit( StartMap, CurrentPage );
  380. while ( ~(BusyFlag ^ RtlCheckBit( StartMap, CurrentPage )) ) {
  381. p += PageSize;
  382. if (RtlCheckBit( EndMap, CurrentPage )) {
  383. CurrentPage++;
  384. break;
  385. }
  386. CurrentPage++;
  387. if (p > PagedPoolEnd) {
  388. break;
  389. }
  390. }
  391. Size = p - pStart;
  392. dprintf( "%p: %I64x - %s\n", pStart, Size, BusyFlag ? "busy" : "free" );
  393. }
  394. }
  395. HeapFree( GetProcessHeap(), 0, StartMap );
  396. HeapFree( GetProcessHeap(), 0, EndMap );
  397. }
  398. void
  399. PrintPoolTagComponent(
  400. ULONG PoolTag
  401. )
  402. {
  403. PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
  404. PSTR TagComponent;
  405. #ifdef _EXTFNS_H
  406. DEBUG_POOLTAG_DESCRIPTION Desc = {0};
  407. Desc.SizeOfStruct = sizeof(DEBUG_POOLTAG_DESCRIPTION);
  408. GetPoolTagDescription = NULL;
  409. if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
  410. !GetPoolTagDescription) {
  411. return;
  412. }
  413. (*GetPoolTagDescription)(PoolTag, &Desc);
  414. if (Desc.Description[0]) {
  415. dprintf("\t\tPooltag %4.4s : %s", &PoolTag, Desc.Description);
  416. if (Desc.Binary[0]) {
  417. dprintf(", Binary : %s",Desc.Binary);
  418. }
  419. if (Desc.Owner[0]) {
  420. dprintf(", Owner : %s", Desc.Owner);
  421. }
  422. dprintf("\n");
  423. } else {
  424. dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
  425. }
  426. #else
  427. GetPoolTagDescription = NULL;
  428. if ((GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription) != S_OK) ||
  429. !GetPoolTagDescription) {
  430. return;
  431. }
  432. (*GetPoolTagDescription)(PoolTag, &TagComponent);
  433. if (TagComponent && (100 < (ULONG64) TagComponent)) {
  434. dprintf("\t\tOwning component : %s\n", TagComponent);
  435. } else {
  436. dprintf("\t\tOwning component : Unknown (update pooltag.txt)\n");
  437. }
  438. #endif
  439. }
  440. PSTR g_PoolRegion[DbgPoolRegionMax] = {
  441. "Unknown", // DbgPoolRegionUnknown,
  442. "Special pool", // DbgPoolRegionSpecial,
  443. "Paged pool", // DbgPoolRegionPaged,
  444. "Nonpaged pool", // DbgPoolRegionNonPaged,
  445. "Pool code", // DbgPoolRegionCode,
  446. "Nonpaged pool expansion", // DbgPoolRegionNonPagedExpansion,
  447. };
  448. DEBUG_POOL_REGION
  449. GetPoolRegion(
  450. ULONG64 Pool
  451. )
  452. {
  453. static ULONG64 PoolCodeEnd;
  454. static ULONG64 PagedPoolEnd;
  455. static ULONG64 NonPagedPoolEnd;
  456. static ULONG64 NonPagedPoolStart;
  457. static ULONG64 PagedPoolStart;
  458. static ULONG64 SessionPagedPoolStart;
  459. static ULONG64 SessionPagedPoolEnd;
  460. static ULONG64 NonPagedPoolExpansionStart;
  461. static ULONG64 PoolCodeStart;
  462. static BOOL GotAll = FALSE;
  463. if (!GotAll) {
  464. PoolCodeEnd = GetPointerValue("nt!MmPoolCodeEnd");
  465. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  466. PagedPoolEnd = GetPointerValue("nt!MmPagedPoolEnd");
  467. NonPagedPoolEnd = GetPointerValue("nt!MmNonPagedPoolEnd");
  468. NonPagedPoolStart = GetPointerValue("nt!MmNonPagedPoolStart");
  469. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  470. PagedPoolStart = GetPointerValue("nt!MmPagedPoolStart");
  471. SessionPagedPoolStart = GetPointerValue("nt!MiSessionPoolStart");
  472. SessionPagedPoolEnd = GetPointerValue("nt!MiSessionPoolEnd");
  473. NonPagedPoolExpansionStart = GetPointerValue("nt!MmNonPagedPoolExpansionStart");
  474. PoolCodeStart = GetPointerValue("nt!MmPoolCodeStart");
  475. GotAll = TRUE;
  476. }
  477. if (!(PoolCodeStart || SpecialPoolStart || SpecialPoolEnd || PoolCodeEnd ||
  478. NonPagedPoolExpansionStart || NonPagedPoolStart || NonPagedPoolEnd ||
  479. SessionPagedPoolStart || SessionPagedPoolEnd || PagedPoolStart || PagedPoolEnd)) {
  480. GotAll = FALSE;
  481. return DbgPoolRegionUnknown;
  482. }
  483. if ( Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
  484. return DbgPoolRegionSpecial;
  485. } else if ( Pool >= PagedPoolStart && Pool < PagedPoolEnd) {
  486. return DbgPoolRegionPaged;
  487. } else if ( Pool >= SessionPagedPoolStart && Pool < SessionPagedPoolEnd) {
  488. return DbgPoolRegionPaged;
  489. } else if ( Pool >= NonPagedPoolStart && Pool < NonPagedPoolEnd) {
  490. return DbgPoolRegionNonPaged;
  491. } else if ( Pool >= PoolCodeStart && Pool < PoolCodeEnd) {
  492. return DbgPoolRegionCode;
  493. } else if ( Pool >= NonPagedPoolExpansionStart) {
  494. return DbgPoolRegionNonPagedExpansion;
  495. } else {
  496. return DbgPoolRegionUnknown;
  497. }
  498. return DbgPoolRegionUnknown;
  499. }
  500. void
  501. PrintPoolRegion(
  502. ULONG64 Pool
  503. )
  504. {
  505. PSTR pszRegion;
  506. DEBUG_POOL_REGION Region;
  507. Region = GetPoolRegion(Pool);
  508. pszRegion = g_PoolRegion[Region];
  509. if (pszRegion) {
  510. dprintf(pszRegion);
  511. dprintf("\n");
  512. } else {
  513. dprintf("Region unkown (0x%I64X)\n", Pool);
  514. }
  515. }
  516. ULONG64
  517. READ_PVOID (
  518. ULONG64 Address
  519. );
  520. UCHAR DataPage[0x5000];
  521. HRESULT
  522. ListPoolPage(
  523. ULONG64 PoolPageToDump,
  524. ULONG Flags,
  525. PDEBUG_POOL_DATA PoolData
  526. )
  527. {
  528. LOGICAL QuotaProcessAtEndOfPoolBlock;
  529. ULONG64 PoolTableAddress;
  530. ULONG result;
  531. ULONG PoolTag;
  532. ULONG Result;
  533. ULONG64 StartPage;
  534. ULONG64 Pool;
  535. ULONG PoolBlockSize;
  536. ULONG PoolHeaderSize;
  537. ULONG64 PoolHeader;
  538. ULONG Previous;
  539. UCHAR c;
  540. PUCHAR p;
  541. ULONG64 PoolDataEnd;
  542. UCHAR PoolBlockPattern;
  543. PUCHAR DataStart;
  544. ULONG64 RealDataStart;
  545. LOGICAL Pagable;
  546. LOGICAL FirstBlock;
  547. ULONG BlockType;
  548. ULONG PoolWhere;
  549. ULONG i;
  550. ULONG j;
  551. ULONG ct;
  552. ULONG start;
  553. ULONG PoolBigPageTableSize;
  554. ULONG SizeOfPoolHdr=GetTypeSize("nt!_POOL_HEADER");
  555. if (!SpecialPoolStart) {
  556. SpecialPoolStart = GetPointerValue("nt!MmSpecialPoolStart");
  557. SpecialPoolEnd = GetPointerValue("nt!MmSpecialPoolEnd");
  558. }
  559. Pool = PAGE_ALIGN64 (PoolPageToDump);
  560. StartPage = Pool;
  561. Previous = 0;
  562. if (PoolData) {
  563. ZeroMemory(PoolData, sizeof(DEBUG_POOL_DATA));
  564. }
  565. if (!(Flags & 0x80000000)) {
  566. dprintf("Pool page %p region is ", PoolPageToDump);
  567. PrintPoolRegion(PoolPageToDump);
  568. }
  569. if (Pool >= SpecialPoolStart && Pool < SpecialPoolEnd) {
  570. ULONG Hdr_Ulong=0;
  571. // Pre read the pool
  572. if ( !ReadMemory( Pool,
  573. &DataPage[0],
  574. min(PageSize, sizeof(DataPage)),
  575. &Result) ) {
  576. dprintf("%08p: Unable to get contents of special pool block\n", Pool );
  577. return E_INVALIDARG;
  578. }
  579. if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong)) {
  580. dprintf("%08p: Unable to get nt!_POOL_HEADER\n", Pool );
  581. return E_INVALIDARG;
  582. }
  583. //
  584. // Determine whether the data is at the start or end of the page.
  585. // Start off by assuming the data is at the end, in this case the
  586. // header will be at the start.
  587. //
  588. PoolHeader = GetSpecialPoolHeader((PVOID) &DataPage[0], Pool, &RealDataStart);
  589. if (PoolHeader == 0) {
  590. dprintf("Block %p is a corrupted special pool allocation\n",
  591. PoolPageToDump);
  592. return E_INVALIDARG;
  593. }
  594. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Hdr_Ulong);
  595. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  596. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(Hdr_Ulong);
  597. if (Hdr_Ulong & MI_SPECIAL_POOL_PAGABLE) {
  598. Pagable = TRUE;
  599. } else {
  600. Pagable = FALSE;
  601. }
  602. if (PoolData) {
  603. PoolData->Pool = RealDataStart;
  604. PoolData->PoolBlock = PoolPageToDump;
  605. PoolData->SpecialPool = 1;
  606. PoolData->Pageable = Hdr_Ulong & 0x8000 ? 1 : 0;
  607. PoolData->Size = PoolBlockSize;
  608. if (Flags & 0x80000000) {
  609. // do not print anything
  610. return S_OK;
  611. }
  612. }
  613. dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
  614. RealDataStart,
  615. PoolBlockSize,
  616. Hdr_Ulong & 0x8000 ? "pagable" : "non-paged",
  617. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  618. PP(PoolTag),
  619. PP(PoolTag >> 8),
  620. PP(PoolTag >> 16),
  621. PP(PoolTag >> 24)
  622. );
  623. #undef PP
  624. PrintPoolTagComponent(PoolTag);
  625. //
  626. // Add code to validate whole block.
  627. //
  628. return S_OK;
  629. }
  630. FirstBlock = TRUE;
  631. QuotaProcessAtEndOfPoolBlock = FALSE;
  632. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  633. if (GetExpression ("nt!ExGetPoolTagInfo") != 0) {
  634. //
  635. // This is a kernel where the quota process pointer is at the end
  636. // of the pool block instead of overlaid on the tag field.
  637. //
  638. QuotaProcessAtEndOfPoolBlock = TRUE;
  639. }
  640. }
  641. while (PAGE_ALIGN64(Pool) == StartPage) {
  642. ULONG BlockSize=0, PreviousSize=0, PoolType=0, AllocatorBackTraceIndex=0;
  643. ULONG PoolTagHash=0, PoolIndex=0;
  644. ULONG64 ProcessBilled=0;
  645. if ( CheckControlC() ) {
  646. return E_INVALIDARG;
  647. }
  648. if ( GetFieldValue( Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize) ) {
  649. //
  650. // If this is a large pool allocation the memory address at this address
  651. // might still be DemandZero and we cannot read from it. This is not an error -
  652. // we could still find the allocation in the large allocations table.
  653. //
  654. BlockType = 1;
  655. goto TryLargePool;
  656. }
  657. if (PoolPageToDump >= Pool &&
  658. PoolPageToDump < (Pool + ((ULONG64) BlockSize << POOL_BLOCK_SHIFT))
  659. ) {
  660. c = '*';
  661. } else {
  662. c = ' ';
  663. }
  664. GetFieldValue( Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  665. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolType", PoolType);
  666. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  667. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
  668. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
  669. GetFieldValue( Pool, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
  670. BlockType = 0;
  671. if ((BlockSize << POOL_BLOCK_SHIFT) >= POOL_PAGE_SIZE) {
  672. BlockType = 1;
  673. } else if (BlockSize == 0) {
  674. BlockType = 2;
  675. } else if (PreviousSize != Previous) {
  676. BlockType = 3;
  677. }
  678. TryLargePool:
  679. if (BlockType != 0) {
  680. ULONG BigPageSize = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
  681. if (!BigPageSize) {
  682. dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
  683. break;
  684. }
  685. //
  686. // See if this is a big block allocation. Iff we have not parsed
  687. // any other small blocks in here already.
  688. //
  689. if (FirstBlock == TRUE) {
  690. if (!PoolBigTableAddress) {
  691. PoolBigTableAddress = GetPointerValue ("nt!PoolBigPageTable");
  692. }
  693. PoolTableAddress = PoolBigTableAddress;
  694. if (PoolTableAddress) {
  695. dprintf ("%p is not a valid small pool allocation, checking large pool...\n", Pool);
  696. PoolBigPageTableSize = GetUlongValue ("nt!PoolBigPageTableSize");
  697. //
  698. // Scan the table looking for a match.
  699. //
  700. i = 0;
  701. ct = PageSize / BigPageSize;
  702. while (i < PoolBigPageTableSize) {
  703. ULONG64 Va=0;
  704. ULONG Key=0, NumberOfPages=0;
  705. if (PoolBigPageTableSize - i < ct) {
  706. ct = PoolBigPageTableSize - i;
  707. }
  708. if ( GetFieldValue( PoolTableAddress,
  709. "nt!_POOL_TRACKER_BIG_PAGES",
  710. "Va",
  711. Va) ) {
  712. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  713. return E_INVALIDARG;
  714. }
  715. for (j = 0; j < ct; j += 1) {
  716. if ( GetFieldValue( PoolTableAddress + BigPageSize*j,
  717. "nt!_POOL_TRACKER_BIG_PAGES",
  718. "Va",
  719. Va) ) {
  720. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  721. return E_INVALIDARG;
  722. }
  723. if (((Va & 0x1) == 0) && (Pool >= Va)) {
  724. GetFieldValue( PoolTableAddress + BigPageSize*j,
  725. "nt!_POOL_TRACKER_BIG_PAGES",
  726. "NumberOfPages",
  727. NumberOfPages);
  728. if (Pool < (Va + (NumberOfPages * PageSize))) {
  729. //
  730. // Match !
  731. //
  732. GetFieldValue( PoolTableAddress + BigPageSize*j,
  733. "nt!_POOL_TRACKER_BIG_PAGES",
  734. "Key",
  735. Key);
  736. PoolTag = Key;
  737. if (PoolData) {
  738. PoolData->Pool = PoolPageToDump;
  739. PoolData->Size = NumberOfPages*PageSize;
  740. PoolData->PoolTag = PoolTag;
  741. PoolData->LargePool = 1;
  742. PoolData->Free = (Pool & POOL_BIG_TABLE_ENTRY_FREE) ? 1 : 0;
  743. if (Flags & 0x80000000) {
  744. // do not print anything
  745. return S_OK;
  746. }
  747. }
  748. dprintf("*%p :%s large page allocation, Tag is %c%c%c%c, size is 0x%I64x bytes\n",
  749. (Pool & ~POOL_BIG_TABLE_ENTRY_FREE),
  750. (Pool & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
  751. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  752. PP(PoolTag),
  753. PP(PoolTag >> 8),
  754. PP(PoolTag >> 16),
  755. PP(PoolTag >> 24),
  756. (ULONG64)NumberOfPages * PageSize
  757. );
  758. #undef PP
  759. PrintPoolTagComponent(PoolTag);
  760. return S_OK;
  761. }
  762. }
  763. }
  764. i += ct;
  765. PoolTableAddress += (ct * BigPageSize);
  766. }
  767. //
  768. // No match in small or large pool, must be
  769. // freed or corrupt pool
  770. //
  771. dprintf("%p is freed (or corrupt) pool\n", Pool);
  772. return E_INVALIDARG;
  773. }
  774. dprintf("unable to get pool big page table - either wrong symbols or pool tagging is disabled\n");
  775. }
  776. if (BlockType == 1) {
  777. dprintf("Bad allocation size @%p, too large\n", Pool);
  778. } else if (BlockType == 2) {
  779. dprintf("Bad allocation size @%p, zero is invalid\n", Pool);
  780. } else if (BlockType == 3) {
  781. dprintf("Bad previous allocation size @%p, last size was %lx\n",
  782. Pool, Previous);
  783. }
  784. if (BlockType != 0) {
  785. //
  786. // Attempt to diagnose what is wrong with the pool page
  787. //
  788. DiagnosePoolPage(Pool);
  789. return E_INVALIDARG;
  790. }
  791. }
  792. switch (TargetMachine) {
  793. case IMAGE_FILE_MACHINE_IA64:
  794. case IMAGE_FILE_MACHINE_AMD64:
  795. GetFieldValue( Pool, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  796. break;
  797. default:
  798. if (QuotaProcessAtEndOfPoolBlock == TRUE) {
  799. ULONG SizeOfPvoid = 0;
  800. ULONG64 ProcessBillAddress;
  801. SizeOfPvoid = DBG_PTR_SIZE;
  802. if (SizeOfPvoid == 0) {
  803. dprintf ("Search: cannot get size of PVOID\n");
  804. return E_INVALIDARG;
  805. }
  806. ProcessBillAddress = Pool + ((ULONG64) BlockSize << POOL_BLOCK_SHIFT) - SizeOfPvoid;
  807. ProcessBilled = READ_PVOID (ProcessBillAddress);
  808. }
  809. else {
  810. GetFieldValue( Pool, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  811. }
  812. break;
  813. }
  814. GetFieldValue( Pool, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  815. if (!(Flags & 2) || c == '*') {
  816. if (PoolData) {
  817. PoolData->Pool = Pool;
  818. PoolData->PoolBlock = PoolPageToDump;
  819. PoolData->PoolTag = PoolTag & ~PROTECTED_POOL;
  820. PoolData->ProcessBilled = ProcessBilled;
  821. PoolData->PreviousSize = PreviousSize << POOL_BLOCK_SHIFT;
  822. PoolData->Size = BlockSize << POOL_BLOCK_SHIFT;
  823. PoolData->Free = ((PoolType != 0) && (!NewPool ?
  824. (PoolIndex & 0x80) : (PoolType & 0x04))) ? 0 : 1;
  825. PoolData->Protected = (PoolTag&PROTECTED_POOL) ? 1 : 0;
  826. if (Flags & 0x80000000) {
  827. // do not print anything
  828. return S_OK;
  829. }
  830. }
  831. dprintf("%c%p size: %4lx previous size: %4lx ",
  832. c,
  833. Pool,
  834. BlockSize << POOL_BLOCK_SHIFT,
  835. PreviousSize << POOL_BLOCK_SHIFT);
  836. if (PoolType == 0) {
  837. //
  838. // "Free " with a space after it before the parentheses means
  839. // it's been freed to a (pool manager internal) lookaside list.
  840. // We used to print "Lookaside" but that just confused driver
  841. // writers because they didn't know if this meant in use or not
  842. // and many would say "but I don't use lookaside lists - the
  843. // extension or kernel is broken".
  844. //
  845. // "Free" with no space after it before the parentheses means
  846. // it is not on a pool manager internal lookaside list and is
  847. // instead on the regular pool manager internal flink/blink
  848. // chains.
  849. //
  850. // Note to anyone using the pool package, these 2 terms are
  851. // equivalent. The fine distinction is only for those actually
  852. // writing pool internal code.
  853. //
  854. dprintf(" (Free)");
  855. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  856. dprintf(" %c%c%c%c%c\n",
  857. c,
  858. PP(PoolTag),
  859. PP(PoolTag >> 8),
  860. PP(PoolTag >> 16),
  861. PP((PoolTag&~PROTECTED_POOL) >> 24)
  862. );
  863. #undef PP
  864. if (c=='*') {
  865. PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
  866. }
  867. } else {
  868. if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
  869. dprintf(" (Allocated)");
  870. } else {
  871. //
  872. // "Free " with a space after it before the parentheses means
  873. // it's been freed to a (pool manager internal) lookaside list.
  874. // We used to print "Lookaside" but that just confused driver
  875. // writers because they didn't know if this meant in use or not
  876. // and many would say "but I don't use lookaside lists - the
  877. // extension or kernel is broken".
  878. //
  879. // "Free" with no space after it before the parentheses means
  880. // it is not on a pool manager internal lookaside list and is
  881. // instead on the regular pool manager internal flink/blink
  882. // chains.
  883. //
  884. // Note to anyone using the pool package, these 2 terms are
  885. // equivalent. The fine distinction is only for those actually
  886. // writing pool internal code.
  887. //
  888. dprintf(" (Free )");
  889. }
  890. if ((PoolType & POOL_QUOTA_MASK) == 0) {
  891. /*
  892. ULONG Key=0;
  893. if (AllocatorBackTraceIndex != 0 &&
  894. AllocatorBackTraceIndex & POOL_BACKTRACEINDEX_PRESENT
  895. ) {
  896. if ( GetFieldValue( PoolTrackTable + ( PoolTagHash&~(PROTECTED_POOL >> 16) )*GetTypeSize("nt!_POOL_TRACKER_TABLE"),
  897. "nt!_POOL_TRACKER_TABLE",
  898. "Key",
  899. Key) ) {
  900. PoolTag = 0;
  901. } else {
  902. PoolTag = Key;
  903. }
  904. if (PoolTagHash & (PROTECTED_POOL >> 16)) {
  905. PoolTag |= PROTECTED_POOL;
  906. }
  907. } else {
  908. PoolTag = PoolTag;
  909. }*/
  910. dprintf(" %c%c%c%c%c%s\n",
  911. c,
  912. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  913. PP(PoolTag),
  914. PP(PoolTag >> 8),
  915. PP(PoolTag >> 16),
  916. PP((PoolTag&~PROTECTED_POOL) >> 24),
  917. (PoolTag&PROTECTED_POOL) ? " (Protected)" : ""
  918. #undef PP
  919. );
  920. if (c=='*') {
  921. PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
  922. }
  923. } else {
  924. if ((QuotaProcessAtEndOfPoolBlock == TRUE) ||
  925. (TargetMachine != IMAGE_FILE_MACHINE_I386)) {
  926. dprintf(" %c%c%c%c%c%s",
  927. c,
  928. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  929. PP(PoolTag),
  930. PP(PoolTag >> 8),
  931. PP(PoolTag >> 16),
  932. PP((PoolTag&~PROTECTED_POOL) >> 24),
  933. (PoolTag&PROTECTED_POOL) ? " (Protected)" : ""
  934. #undef PP
  935. );
  936. if (ProcessBilled != 0) {
  937. dprintf(" Process: %0p\n", ProcessBilled );
  938. }
  939. else {
  940. dprintf("\n");
  941. }
  942. if (c=='*') {
  943. PrintPoolTagComponent(PoolTag & ~PROTECTED_POOL);
  944. }
  945. }
  946. else {
  947. if (ProcessBilled != 0) {
  948. dprintf(" Process: %0p", ProcessBilled );
  949. }
  950. dprintf("\n");
  951. }
  952. }
  953. }
  954. }
  955. if (Flags & 1) {
  956. PULONG Contents;
  957. ULONG Size;
  958. Size = BlockSize << POOL_BLOCK_SHIFT;
  959. //
  960. // the blocksize includes the size of the header,
  961. // so we want to account for the header size
  962. // when we determine how much data to display
  963. //
  964. Size -= SizeOfPoolHdr;
  965. if (Size > 0) {
  966. Contents = malloc(Size);
  967. if (Contents) {
  968. ULONG64 m;
  969. ULONG64 q;
  970. q = Pool + SizeOfPoolHdr;
  971. ReadMemory(q,
  972. Contents,
  973. Size,
  974. &i);
  975. for (m = 0; m < (Size / sizeof(Contents[0])); m++) {
  976. if (m % 4 == 0) {
  977. if (m > 0) {
  978. dprintf("\n");
  979. }
  980. dprintf(" %0p ", q + (m * sizeof(Contents[0])));
  981. }
  982. dprintf(" %08lx", Contents[m]);
  983. }
  984. dprintf("\n\n");
  985. free(Contents);
  986. }
  987. } else {
  988. dprintf("\n");
  989. }
  990. }
  991. Previous = BlockSize;
  992. Pool += ((ULONG64) Previous << POOL_BLOCK_SHIFT);
  993. FirstBlock = FALSE;
  994. }
  995. return S_OK;
  996. }
  997. DECLARE_API( pool )
  998. /*++
  999. Routine Description:
  1000. Dump kernel mode heap
  1001. Arguments:
  1002. args - Page Flags
  1003. Return Value:
  1004. None
  1005. --*/
  1006. {
  1007. ULONG64 PoolPageToDump;
  1008. ULONG Flags;
  1009. HRESULT Hr;
  1010. INIT_API();
  1011. if (PoolInitializeGlobals() == FALSE) {
  1012. Hr = E_INVALIDARG;
  1013. } else {
  1014. PoolPageToDump = 0;
  1015. Flags = 0;
  1016. if (GetExpressionEx(args, &PoolPageToDump, &args)) {
  1017. Flags = (ULONG) GetExpression (args);
  1018. }
  1019. if (PoolPageToDump == 0) {
  1020. DumpPool();
  1021. Hr = S_OK;;
  1022. } else {
  1023. Hr = ListPoolPage(PoolPageToDump, Flags, NULL);
  1024. }
  1025. }
  1026. EXIT_API();
  1027. return Hr;
  1028. }
  1029. //
  1030. // header info meta information
  1031. //
  1032. #define HEADER_BACK_LINK (0x1 << 0) // node has a valid backward link
  1033. #define HEADER_FORWARD_LINK (0x1 << 1) // node has a valid forward link
  1034. #define HEADER_FIXED_BACK_LINK (0x1 << 2) // an attempt was made to correct the backward link
  1035. #define HEADER_FIXED_FORWARD_LINK (0x1 << 3) // an attempt was made to correct the forward link
  1036. #define HEADER_FIRST_LINK (0x1 << 4) // node is the first of a contiguous linked list
  1037. #define HEADER_LAST_LINK (0x1 << 5) // node is the last of a contiguous linked list
  1038. #define HEADER_START_PAGE_BLOCK (0x1 << 6) // node is at the start of the pool page
  1039. #define HEADER_END_PAGE_BLOCK (0x1 << 7) // node refers to the end of the pool page - implies LAST_LINK
  1040. typedef struct _VALIDATE_POOL_HEADER_INFO {
  1041. UCHAR Info;
  1042. ULONG Pass;
  1043. UINT64 Node;
  1044. UINT64 ForwardLink;
  1045. UINT64 BackLink;
  1046. UINT64 FixedPreviousSize;
  1047. UINT64 FixedBlockSize;
  1048. } VALIDATE_POOL_HEADER_INFO, *PVALIDATE_POOL_HEADER_INFO;
  1049. #define IS_VALID_PASS(_x) ((_x > 0) && (_x < 0xff))
  1050. #define VERBOSE_SHOW_ERRORS_ONLY (0) //
  1051. #define VERBOSE_SHOW_LISTS (0x1 << 0) //
  1052. #define VERBOSE_SHOW_HEADER_INFO (0x1 << 1) //
  1053. #define VERBOSE_DUMP_HEADERS (0x1 << 2) //
  1054. #define VERBOSE_SHOW_ALL (0x1 << 7)
  1055. UCHAR
  1056. ValidatePoolHeaderBackLink(
  1057. IN ULONG64 Pool
  1058. )
  1059. /*++
  1060. Description:
  1061. This routine determines if the
  1062. back link of a given pool header as valid
  1063. Arguments:
  1064. Pool - header (node) to analyze
  1065. Returns:
  1066. Header info for the node
  1067. --*/
  1068. {
  1069. UCHAR HeaderInfo;
  1070. ULONG64 StartPage;
  1071. ULONG64 p;
  1072. ULONG tmpBlockSize;
  1073. ULONG PreviousSize;
  1074. //
  1075. // find where the page starts
  1076. //
  1077. StartPage = PAGE_ALIGN64(Pool);
  1078. //
  1079. // clear the header info
  1080. //
  1081. HeaderInfo = 0;
  1082. //
  1083. // get the previous size for the current node
  1084. //
  1085. GetFieldValue( Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  1086. //
  1087. // Validate Back link
  1088. //
  1089. if (Pool == StartPage) {
  1090. //
  1091. // ensure that the PreviousSize is 0 before
  1092. // we declare we have a valid back link
  1093. //
  1094. if (PreviousSize == 0) {
  1095. //
  1096. // the page always begins with a block
  1097. // and the back link is not used (0)
  1098. //
  1099. HeaderInfo |= HEADER_BACK_LINK;
  1100. }
  1101. HeaderInfo |= HEADER_START_PAGE_BLOCK;
  1102. } else {
  1103. p = Pool - ((ULONG64)PreviousSize << POOL_BLOCK_SHIFT);
  1104. if (PAGE_ALIGN64(p) == StartPage) {
  1105. GetFieldValue( p, "nt!_POOL_HEADER", "BlockSize", tmpBlockSize);
  1106. if ((tmpBlockSize == PreviousSize) && (tmpBlockSize != 0)) {
  1107. HeaderInfo |= HEADER_BACK_LINK;
  1108. }
  1109. }
  1110. }
  1111. return HeaderInfo;
  1112. }
  1113. UCHAR
  1114. ValidatePoolHeaderForwardLink(
  1115. IN ULONG64 Pool
  1116. )
  1117. /*++
  1118. Description:
  1119. This routine determines if the
  1120. forward link of a given pool header as valid
  1121. Arguments:
  1122. Pool - header (node) to analyze
  1123. Returns:
  1124. Header info for the node
  1125. --*/
  1126. {
  1127. UCHAR HeaderInfo;
  1128. ULONG64 StartPage;
  1129. ULONG64 p;
  1130. ULONG tmpPreviousSize;
  1131. ULONG BlockSize;
  1132. //
  1133. //
  1134. //
  1135. StartPage = PAGE_ALIGN64(Pool);
  1136. //
  1137. //
  1138. //
  1139. HeaderInfo = 0;
  1140. //
  1141. //
  1142. //
  1143. GetFieldValue( Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  1144. //
  1145. // Validate Forward link
  1146. //
  1147. p = Pool + ((ULONG64)BlockSize << POOL_BLOCK_SHIFT);
  1148. //
  1149. // If p is still on the same page,
  1150. // then see if the block we point to has its
  1151. // previousblocksize == blocksize
  1152. //
  1153. if (PAGE_ALIGN64(p) == StartPage) {
  1154. GetFieldValue( p, "nt!_POOL_HEADER", "PreviousSize", tmpPreviousSize);
  1155. if ((tmpPreviousSize == BlockSize) && (tmpPreviousSize != 0)) {
  1156. HeaderInfo |= HEADER_FORWARD_LINK;
  1157. }
  1158. } else {
  1159. //
  1160. // if p points to the beginning of the next page,
  1161. // then the block Pool refers to *may* be the last block
  1162. // on the page
  1163. //
  1164. if (p == (StartPage + POOL_PAGE_SIZE)) {
  1165. HeaderInfo |= HEADER_FORWARD_LINK;
  1166. HeaderInfo |= HEADER_END_PAGE_BLOCK;
  1167. }
  1168. }
  1169. return HeaderInfo;
  1170. }
  1171. UCHAR
  1172. ValidatePoolHeader(
  1173. IN ULONG64 Pool
  1174. )
  1175. /*++
  1176. Description:
  1177. This routine determines if a given pool header as valid
  1178. forward and backward links.
  1179. Arguments:
  1180. Pool - header (node) to analyze
  1181. Returns:
  1182. Header info for the node
  1183. --*/
  1184. {
  1185. UCHAR HeaderInfo;
  1186. HeaderInfo = 0;
  1187. HeaderInfo |= ValidatePoolHeaderBackLink(Pool);
  1188. HeaderInfo |= ValidatePoolHeaderForwardLink(Pool);
  1189. return HeaderInfo;
  1190. }
  1191. NTSTATUS
  1192. ScanPoolHeaders(
  1193. IN ULONG64 PoolPageToEnumerate,
  1194. IN OUT PVOID Data,
  1195. IN ULONG DataSize
  1196. )
  1197. /*++
  1198. Description:
  1199. This routine does the first pass analysis of the pool page headers.
  1200. The net result of this routine is that we end up with a set of
  1201. pool header meta information, where the information describes
  1202. the health of a node - if the forward and back links exist, etc.
  1203. Arguments:
  1204. PoolPageToEnumerate - page to analyze
  1205. Data - the pool header info
  1206. DataLength - the # of entries in the header info
  1207. Returns:
  1208. Status
  1209. --*/
  1210. {
  1211. NTSTATUS Status;
  1212. ULONG64 StartPage;
  1213. ULONG64 StartHeader;
  1214. ULONG64 Pool;
  1215. ULONG SizeOfPoolHdr;
  1216. ULONG PoolIndex;
  1217. PVALIDATE_POOL_HEADER_INFO p;
  1218. ULONG Pass;
  1219. BOOLEAN Done;
  1220. BOOLEAN Tracing;
  1221. //
  1222. // default
  1223. //
  1224. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1225. Pool = PAGE_ALIGN64 (PoolPageToEnumerate);
  1226. StartPage = Pool;
  1227. Status = STATUS_SUCCESS;
  1228. PoolIndex = 0;
  1229. p = (PVALIDATE_POOL_HEADER_INFO)Data;
  1230. StartHeader = StartPage;
  1231. Pass = 0;
  1232. Done = FALSE;
  1233. //
  1234. // iterate through the page and validate the headers
  1235. //
  1236. #if DBG_SCAN
  1237. dprintf("DataSize = %d, DataLength = %d\r\n", DataSize, DataSize / sizeof(VALIDATE_POOL_HEADER_INFO));
  1238. #endif
  1239. //
  1240. // algorithm:
  1241. //
  1242. // Consider each possible node in the pool page to be
  1243. // the start of a linked list. For each start node (head),
  1244. // attempt to follow the list by tracing forward links.
  1245. // All nodes that are part of a single list, are assigned
  1246. // the same pass value - they were all traced on the same pass.
  1247. // The net result is a set of linked lists grouped by pass.
  1248. //
  1249. // We skip nodes that have already been marked as being part
  1250. // of another linked list
  1251. //
  1252. //
  1253. while ((PAGE_ALIGN64(StartHeader) == StartPage) && !Done) {
  1254. //
  1255. // each iteration is a new pass
  1256. //
  1257. Pass += 1;
  1258. //
  1259. // start scanning from the new first node
  1260. //
  1261. Pool = StartHeader;
  1262. PoolIndex = (ULONG)((Pool - StartPage) / SizeOfPoolHdr);
  1263. //
  1264. // default: we have not found the start of a linked list
  1265. //
  1266. Tracing = FALSE;
  1267. //
  1268. // while we are still on the correct page
  1269. //
  1270. while ((PAGE_ALIGN64(Pool) == StartPage)) {
  1271. #if DBG_SCAN
  1272. dprintf("Pass = %d, PoolIndex = %d, Pool = %p\r\n", Pass, PoolIndex, Pool);
  1273. #endif
  1274. ASSERT(PoolIndex < (DataSize/sizeof(VALIDATE_POOL_HEADER_INFO)));
  1275. if ( CheckControlC() ) {
  1276. Done = TRUE;
  1277. break;
  1278. }
  1279. #if DBG_SCAN
  1280. dprintf("p[PoolIndex].Pass = %d\r\n", p[PoolIndex].Pass);
  1281. #endif
  1282. //
  1283. //
  1284. // Skip nodes that have already been marked as being part
  1285. // of another linked list
  1286. //
  1287. if (p[PoolIndex].Pass == 0) {
  1288. //
  1289. // determine the link info for this header
  1290. //
  1291. p[PoolIndex].Info = ValidatePoolHeader(Pool);
  1292. #if DBG_SCAN
  1293. dprintf("p[PoolIndex].Info = %d\r\n", p[PoolIndex].Info);
  1294. #endif
  1295. //
  1296. // if the node has any chance of being valid,
  1297. // then consider it
  1298. // otherwise mark it invalid
  1299. //
  1300. if ((p[PoolIndex].Info & HEADER_FORWARD_LINK) ||
  1301. (p[PoolIndex].Info & HEADER_BACK_LINK) ||
  1302. (p[PoolIndex].Info & HEADER_START_PAGE_BLOCK)
  1303. ) {
  1304. //
  1305. // if we are not already tracing,
  1306. // then we have found the first node of a linked list
  1307. //
  1308. if (!Tracing) {
  1309. //
  1310. // we have found a valid node,
  1311. // so we now consider ourselves tracing
  1312. // the links of a list
  1313. //
  1314. Tracing = TRUE;
  1315. //
  1316. // mark the current node as the start of the list
  1317. //
  1318. p[PoolIndex].Info |= HEADER_FIRST_LINK;
  1319. }
  1320. //
  1321. // the node has a valid link,
  1322. // so it is part of this pass
  1323. //
  1324. // if the back link is good and the forward link is bad
  1325. // then this is the end of a list
  1326. // if the back link is bad and the forward link is good
  1327. // then this is the start of a list
  1328. // if both are good,
  1329. // then this is the middle node of a list
  1330. //
  1331. p[PoolIndex].Pass = Pass;
  1332. //
  1333. // keep track of the node's address
  1334. //
  1335. p[PoolIndex].Node = Pool;
  1336. //
  1337. // keep track of what may or may not be a valid back link
  1338. // we use this value later when/if we need to correct broken links
  1339. //
  1340. {
  1341. ULONG PreviousSize;
  1342. //
  1343. // calculate the backward node
  1344. //
  1345. GetFieldValue( Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  1346. p[PoolIndex].BackLink = Pool - ((ULONG64)PreviousSize << POOL_BLOCK_SHIFT);
  1347. }
  1348. //
  1349. // keep track of what may or may not be a valid forward link
  1350. // we use this value later when/if we need to correct broken links
  1351. //
  1352. {
  1353. ULONG BlockSize;
  1354. //
  1355. // calculate the forward node
  1356. //
  1357. GetFieldValue( Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  1358. //
  1359. // keep track of the forward node
  1360. //
  1361. p[PoolIndex].ForwardLink = Pool + ((ULONG64)BlockSize << POOL_BLOCK_SHIFT);
  1362. }
  1363. //
  1364. // if the node has a valid forward link,
  1365. // then follow it as part of this pass
  1366. //
  1367. if (p[PoolIndex].Info & HEADER_FORWARD_LINK) {
  1368. //
  1369. // calculate the forward node
  1370. //
  1371. Pool = p[PoolIndex].ForwardLink;
  1372. //
  1373. // calculate the pool info index of the forward node
  1374. //
  1375. PoolIndex = (ULONG)((Pool - StartPage) / SizeOfPoolHdr);
  1376. continue;
  1377. } else {
  1378. //
  1379. // the forward link is broken,
  1380. // hence we are at the end of a list
  1381. //
  1382. p[PoolIndex].Info |= HEADER_LAST_LINK;
  1383. break;
  1384. }
  1385. } else {
  1386. //
  1387. // assert: if we got here and are tracing a list
  1388. // then the forward link of the previous node
  1389. // pointed to a node with no valid links
  1390. // this is impossible and probably implies
  1391. // that the code to determine the forward link
  1392. // is broken
  1393. //
  1394. if (Tracing) {
  1395. dprintf("error: forward link lead to invalid node! header = %p\r\n", Pool);
  1396. }
  1397. ASSERT(!Tracing);
  1398. //
  1399. // mark this as a NULL pass
  1400. //
  1401. p[PoolIndex].Pass = 0xff;
  1402. }
  1403. }
  1404. //
  1405. // assert: we should only reach here if we havent started
  1406. // tracing a list, otherwise we have landed on
  1407. // a node which we already explored!
  1408. //
  1409. if (Tracing) {
  1410. dprintf("error: two lists share a node! header = %p\r\n", Pool);
  1411. }
  1412. ASSERT(!Tracing);
  1413. //
  1414. //
  1415. //
  1416. Pool = Pool + SizeOfPoolHdr;
  1417. PoolIndex += 1;
  1418. }
  1419. //
  1420. // if we never started tracing a linked list,
  1421. // then we should bail because no further searches
  1422. // will yield a list
  1423. //
  1424. if (!Tracing) {
  1425. #if DBG_SCAN
  1426. dprintf("no new valid headers found: giving up poolheader scanning\n");
  1427. #endif
  1428. break;
  1429. }
  1430. StartHeader += SizeOfPoolHdr;
  1431. }
  1432. return Status;
  1433. }
  1434. NTSTATUS
  1435. ResolvePoolHeaders(
  1436. IN ULONG64 PoolPageToDump,
  1437. IN OUT PVOID Data,
  1438. IN ULONG DataLength
  1439. )
  1440. /*++
  1441. Description:
  1442. This routine does the main work of resolving broken links in
  1443. the pool header meta information. Given the raw pool header
  1444. info, this routine tries to fix broken forward and back links.
  1445. It also determines contiguous linked lists (passes) as well
  1446. as marking various pool header attributes.
  1447. Arguments:
  1448. PoolPageToDump - page to analyze
  1449. Data - the pool header info
  1450. DataLength - the # of entries in the header info
  1451. Returns:
  1452. None
  1453. --*/
  1454. {
  1455. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  1456. ULONG i;
  1457. ULONG j;
  1458. ULONG Pass;
  1459. BOOLEAN Found;
  1460. ULONG PoolHeaderInfoLength;
  1461. ULONG SizeOfPoolHdr;
  1462. UINT64 StartPage;
  1463. NTSTATUS Status;
  1464. //
  1465. // default: we were successful
  1466. //
  1467. Status = STATUS_SUCCESS;
  1468. //
  1469. //
  1470. //
  1471. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1472. StartPage = PAGE_ALIGN64(PoolPageToDump);
  1473. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  1474. PoolHeaderInfoLength = DataLength;
  1475. Pass = 0;
  1476. //
  1477. // while we continue to find linked lists,
  1478. // continue to process them.
  1479. //
  1480. // when the pool page was scanned, we marked each unique linked list
  1481. // with the pass # that it was found/traced on. Here, we
  1482. // are looking for all the nodes - i.e., the list which belong
  1483. // to our current pass.
  1484. //
  1485. // If we do not find (Found == FALSE) a linked list, then
  1486. // we have processed all the scanned lists.
  1487. //
  1488. do {
  1489. #if DBG_RESOLVE
  1490. dprintf("ResolvePoolHeaders: Pass = %d\n", Pass);
  1491. #endif
  1492. if ( CheckControlC() ) {
  1493. break;
  1494. }
  1495. //
  1496. // advance to the next pass
  1497. //
  1498. Pass += 1;
  1499. //
  1500. // default: there is no linked list in this pass
  1501. //
  1502. Found = FALSE;
  1503. //
  1504. // for every header in the pool page
  1505. // find the beginning of the linked list belonging to our pass
  1506. // if necessary, attempt to repair any broken nodes.
  1507. //
  1508. for (i = 0; i < PoolHeaderInfoLength; i++) {
  1509. #if DBG_RESOLVE
  1510. dprintf("ResolvePoolHeaders: PoolHeaderInfo[%d].Info = %d\n", i, PoolHeaderInfo[i].Info);
  1511. #endif
  1512. //
  1513. // Look for all the nodes which belong to our current pass
  1514. //
  1515. if (PoolHeaderInfo[i].Pass == Pass) {
  1516. //
  1517. // we found a linked list - of atleast 1 node
  1518. //
  1519. Found = TRUE;
  1520. //
  1521. // if the node is the head of a list
  1522. //
  1523. if (PoolHeaderInfo[i].Info & HEADER_FIRST_LINK) {
  1524. //
  1525. // start of list
  1526. //
  1527. if (PoolHeaderInfo[i].Info & HEADER_BACK_LINK) {
  1528. if (PoolHeaderInfo[i].Info & HEADER_START_PAGE_BLOCK) {
  1529. //
  1530. // back link is valid
  1531. //
  1532. NOTHING;
  1533. } else {
  1534. //
  1535. // invalid condition:
  1536. //
  1537. // this implies that the node is the first node of a list,
  1538. // it has a valid back link, but is not the first
  1539. // node of a pool page.
  1540. //
  1541. dprintf("\n");
  1542. dprintf("error: Inconsistent condition occured while resolving @ %p.\n", PoolHeaderInfo[i].Node);
  1543. dprintf("error: Node is the first node of a list and it has a valid back link,\n");
  1544. dprintf("error: but the node is not at the start of the page\n");
  1545. dprintf("\n");
  1546. Status = STATUS_UNSUCCESSFUL;
  1547. break;
  1548. }
  1549. } else {
  1550. ULONG k;
  1551. ULONG target;
  1552. BOOLEAN bHaveTarget;
  1553. bHaveTarget = FALSE;
  1554. //
  1555. // node does not have a valid back link
  1556. //
  1557. if (PoolHeaderInfo[i].Info & HEADER_START_PAGE_BLOCK) {
  1558. PoolHeaderInfo[i].Info |= HEADER_FIXED_BACK_LINK;
  1559. PoolHeaderInfo[i].FixedPreviousSize = 0;
  1560. continue;
  1561. }
  1562. //
  1563. // validate the forward link of the previous node:
  1564. //
  1565. // assume the back link of the current node (i) is broken:
  1566. // attempt to find a node that has a forward
  1567. // link that refers to this node
  1568. //
  1569. for (k = 0; k < i; k++) {
  1570. //
  1571. // see if the forward link refers to our node
  1572. //
  1573. bHaveTarget = (PoolHeaderInfo[k].ForwardLink == PoolHeaderInfo[i].Node);
  1574. //
  1575. // make sure the node has a broken forward link
  1576. //
  1577. bHaveTarget = bHaveTarget && (! (PoolHeaderInfo[k].Info & HEADER_FORWARD_LINK));
  1578. if (bHaveTarget) {
  1579. target = k;
  1580. break;
  1581. }
  1582. }
  1583. if (bHaveTarget) {
  1584. //
  1585. // we have found a node whose forward link refers to
  1586. // the current node.
  1587. // therefore, the current node's previous size is corrupted
  1588. // we can correct it using the previous node's blocksize
  1589. //
  1590. PoolHeaderInfo[i].Info |= HEADER_FIXED_BACK_LINK;
  1591. PoolHeaderInfo[i].FixedPreviousSize =
  1592. (PoolHeaderInfo[i].Node - PoolHeaderInfo[k].Node) >> POOL_BLOCK_SHIFT;
  1593. //
  1594. // we now know the forward link of the target node is correct
  1595. //
  1596. PoolHeaderInfo[k].Info |= HEADER_FORWARD_LINK;
  1597. continue;
  1598. }
  1599. //
  1600. // validate back link of this node:
  1601. //
  1602. // assume the forward link of a previous node (k) is broken:
  1603. // determine if the node that this node's back link
  1604. // refers to is valid
  1605. //
  1606. for (k = 0; k < i; k++) {
  1607. //
  1608. // see if the current node's back link refers to any previous node
  1609. //
  1610. bHaveTarget = (PoolHeaderInfo[k].Node == PoolHeaderInfo[i].BackLink);
  1611. //
  1612. // make sure the node has a broken forward link
  1613. //
  1614. bHaveTarget = bHaveTarget && (! (PoolHeaderInfo[k].Info & HEADER_FORWARD_LINK));
  1615. if (bHaveTarget) {
  1616. target = k;
  1617. break;
  1618. }
  1619. }
  1620. if (bHaveTarget) {
  1621. //
  1622. // we have found a node that the current node's backlink refers to.
  1623. // therefore, the current node's previous size is valid
  1624. // we can correct it using the previous node's blocksize
  1625. //
  1626. PoolHeaderInfo[k].Info |= HEADER_FIXED_FORWARD_LINK;
  1627. PoolHeaderInfo[k].FixedBlockSize =
  1628. (PoolHeaderInfo[i].Node - PoolHeaderInfo[k].Node) >> POOL_BLOCK_SHIFT;
  1629. //
  1630. // we now know the back link of our current node is correct
  1631. //
  1632. PoolHeaderInfo[i].Info |= HEADER_BACK_LINK;
  1633. continue;
  1634. }
  1635. //
  1636. // otherwise:
  1637. //
  1638. // the back link of this node is broken
  1639. // the forward link of the previous known good
  1640. // node is broken
  1641. //
  1642. // hence there is a corrupt region between
  1643. // and possibly including portions of these nodes
  1644. //
  1645. NOTHING;
  1646. }
  1647. }
  1648. //
  1649. // if the node is the tail of a list
  1650. //
  1651. if (PoolHeaderInfo[i].Info & HEADER_LAST_LINK) {
  1652. if (PoolHeaderInfo[i].Info & HEADER_END_PAGE_BLOCK) {
  1653. //
  1654. // the forward link of this node is valid
  1655. //
  1656. NOTHING;
  1657. } else {
  1658. ULONG k;
  1659. ULONG target;
  1660. BOOLEAN bHaveTarget;
  1661. bHaveTarget = FALSE;
  1662. //
  1663. // the last link of a list should always point
  1664. // to the page end, hence
  1665. // the forward link of this node is INVALID/corrupt
  1666. //
  1667. //
  1668. // validate the back link of the next node:
  1669. //
  1670. // assume the forward link for the current node (i) is bad:
  1671. // attempt to find a node that has a back
  1672. // link that refers to this node
  1673. //
  1674. for (k = i+1; k < PoolHeaderInfoLength; k++) {
  1675. //
  1676. // see if the a following node refers to the current node
  1677. //
  1678. bHaveTarget = (PoolHeaderInfo[k].BackLink == PoolHeaderInfo[i].Node);
  1679. //
  1680. // make sure the following node is missing it's back link
  1681. //
  1682. bHaveTarget = bHaveTarget && (! (PoolHeaderInfo[k].Info & HEADER_BACK_LINK));
  1683. if (bHaveTarget) {
  1684. target = k;
  1685. break;
  1686. }
  1687. }
  1688. if (bHaveTarget) {
  1689. //
  1690. // we have found a node whose forward link refers to
  1691. // the current node.
  1692. // therefore, the current node's previous size is corrupted
  1693. // we can correct it using the previous node's blocksize
  1694. //
  1695. PoolHeaderInfo[i].Info |= HEADER_FIXED_FORWARD_LINK;
  1696. PoolHeaderInfo[i].FixedBlockSize =
  1697. (PoolHeaderInfo[k].Node - PoolHeaderInfo[i].Node) >> POOL_BLOCK_SHIFT;
  1698. //
  1699. // we now know the back link of our target node is correct
  1700. //
  1701. PoolHeaderInfo[k].Info |= HEADER_BACK_LINK;
  1702. continue;
  1703. }
  1704. //
  1705. // validate forward link of this node:
  1706. //
  1707. // assume the back link for a following node (k) is bad:
  1708. // determine if the node that this node's forward link
  1709. // refers to is valid
  1710. //
  1711. for (k = i+1; k < PoolHeaderInfoLength; k++) {
  1712. //
  1713. // see if the a following node refers to the current node
  1714. //
  1715. bHaveTarget = (PoolHeaderInfo[k].Node == PoolHeaderInfo[i].ForwardLink);
  1716. //
  1717. // make sure the following node is missing it's back link
  1718. //
  1719. bHaveTarget = bHaveTarget && (! (PoolHeaderInfo[k].Info & HEADER_BACK_LINK));
  1720. if (bHaveTarget) {
  1721. target = k;
  1722. break;
  1723. }
  1724. }
  1725. if (bHaveTarget) {
  1726. //
  1727. // we have found a node whose forward link refers to
  1728. // the current node.
  1729. // therefore, the current node's previous size is corrupted
  1730. // we can correct it using the previous node's blocksize
  1731. //
  1732. PoolHeaderInfo[k].Info |= HEADER_FIXED_BACK_LINK;
  1733. PoolHeaderInfo[k].FixedPreviousSize =
  1734. (PoolHeaderInfo[k].Node - PoolHeaderInfo[i].Node) >> POOL_BLOCK_SHIFT;
  1735. //
  1736. // we now know the back link of our target node is correct
  1737. //
  1738. PoolHeaderInfo[i].Info |= HEADER_FORWARD_LINK;
  1739. continue;
  1740. }
  1741. //
  1742. // otherwise:
  1743. //
  1744. // the forward link of this node is broken
  1745. // the back link of the next known good
  1746. // node is broken
  1747. //
  1748. // hence there is a corrupt region between
  1749. // and possibly including portions of these nodes
  1750. //
  1751. NOTHING;
  1752. }
  1753. }
  1754. } else {
  1755. //
  1756. // Node was not part of linked list belonging to this pass
  1757. //
  1758. NOTHING;
  1759. }
  1760. }
  1761. if (! NT_SUCCESS(Status)) {
  1762. break;
  1763. }
  1764. } while ( Found );
  1765. return Status;
  1766. }
  1767. VOID
  1768. DumpPoolHeaderInfo(
  1769. IN ULONG64 PoolPageToDump,
  1770. IN OUT PVOID Data,
  1771. IN ULONG DataLength,
  1772. IN ULONG i,
  1773. IN UCHAR Verbose
  1774. )
  1775. /*++
  1776. Description:
  1777. Debug utility
  1778. dump a SINGLE pool header meta info structure that has been collected
  1779. Arguments:
  1780. PoolPageToDump - page to analyze
  1781. Data - the pool header info
  1782. DataLength - the # of entries in the header info
  1783. i - the structure to dump
  1784. Returns:
  1785. None
  1786. --*/
  1787. {
  1788. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  1789. ULONG PoolHeaderInfoLength;
  1790. UINT64 StartPage;
  1791. ULONG SizeOfPoolHdr;
  1792. //
  1793. //
  1794. //
  1795. StartPage = PAGE_ALIGN64(PoolPageToDump);
  1796. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1797. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  1798. PoolHeaderInfoLength = DataLength;
  1799. //
  1800. //
  1801. //
  1802. {
  1803. BOOLEAN First;
  1804. First = TRUE;
  1805. dprintf("[ %p ]:", StartPage + (i*SizeOfPoolHdr));
  1806. if (PoolHeaderInfo[i].Info & HEADER_FIRST_LINK) {
  1807. dprintf("%s FIRST_LINK", !First ? " |" : ""); First = FALSE;
  1808. }
  1809. if (PoolHeaderInfo[i].Info & HEADER_LAST_LINK) {
  1810. dprintf("%s LAST_LINK", !First ? " |" : ""); First = FALSE;
  1811. }
  1812. if (PoolHeaderInfo[i].Info & HEADER_START_PAGE_BLOCK) {
  1813. dprintf("%s START_PAGE_BLOCK", !First ? " |" : ""); First = FALSE;
  1814. }
  1815. if (PoolHeaderInfo[i].Info & HEADER_END_PAGE_BLOCK) {
  1816. dprintf("%s END_PAGE_BLOCK", !First ? " |" : ""); First = FALSE;
  1817. }
  1818. if (First) {
  1819. dprintf(" interior node");
  1820. }
  1821. dprintf("\n");
  1822. }
  1823. if (PoolHeaderInfo[i].Info & HEADER_BACK_LINK) {
  1824. dprintf(
  1825. "[ %p ]: back link [ %p ]\n",
  1826. PoolHeaderInfo[i].Node,
  1827. PoolHeaderInfo[i].BackLink
  1828. );
  1829. }
  1830. if (PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK) {
  1831. dprintf(
  1832. "[ %p ]: forward link [ %p ]\n",
  1833. PoolHeaderInfo[i].Node,
  1834. PoolHeaderInfo[i].ForwardLink
  1835. );
  1836. }
  1837. if (PoolHeaderInfo[i].Info & HEADER_FIXED_BACK_LINK) {
  1838. ULONG PreviousSize;
  1839. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  1840. dprintf(
  1841. "[ %p ]: invalid previous size [ %d ] should be [ %d ]\n",
  1842. PoolHeaderInfo[i].Node,
  1843. PreviousSize,
  1844. PoolHeaderInfo[i].FixedPreviousSize
  1845. );
  1846. }
  1847. if (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK) {
  1848. ULONG BlockSize;
  1849. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  1850. dprintf(
  1851. "[ %p ]: invalid block size [ %d ] should be [ %d ]\n",
  1852. PoolHeaderInfo[i].Node,
  1853. BlockSize,
  1854. PoolHeaderInfo[i].FixedBlockSize
  1855. );
  1856. }
  1857. }
  1858. VOID
  1859. DiagnosePoolHeadersDumpInfo(
  1860. IN ULONG64 PoolPageToDump,
  1861. IN OUT PVOID Data,
  1862. IN ULONG DataLength,
  1863. IN UCHAR Verbose
  1864. )
  1865. /*++
  1866. Description:
  1867. Debug utility
  1868. dump all of the pool header meta info that has been collected
  1869. Arguments:
  1870. PoolPageToDump - page to analyze
  1871. Data - the pool header info
  1872. DataLength - the # of entries in the header info
  1873. Returns:
  1874. None
  1875. --*/
  1876. {
  1877. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  1878. ULONG64 i;
  1879. ULONG PoolHeaderInfoLength;
  1880. UINT64 StartPage;
  1881. ULONG SizeOfPoolHdr;
  1882. //
  1883. //
  1884. //
  1885. StartPage = PAGE_ALIGN64(PoolPageToDump);
  1886. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1887. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  1888. PoolHeaderInfoLength = DataLength;
  1889. for (i = 0; i < PoolHeaderInfoLength; i++) {
  1890. if ( CheckControlC() ) {
  1891. break;
  1892. }
  1893. if (! IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  1894. continue;
  1895. }
  1896. DumpPoolHeaderInfo(
  1897. PoolPageToDump,
  1898. Data,
  1899. DataLength,
  1900. (ULONG)i,
  1901. Verbose
  1902. );
  1903. dprintf("\n");
  1904. }
  1905. }
  1906. BOOLEAN
  1907. DiagnosePoolHeadersIsValid(
  1908. IN ULONG64 PoolPageToDump,
  1909. IN OUT PVOID Data,
  1910. IN ULONG DataLength
  1911. )
  1912. /*++
  1913. Description:
  1914. Determines if a pool page is corrupt
  1915. Arguments:
  1916. PoolPageToDump - page to analyze
  1917. Data - the pool header info
  1918. DataLength - the # of entries in the header info
  1919. Returns:
  1920. TRUE - page is corrupt
  1921. FALSE - page is NOT corrupt
  1922. --*/
  1923. {
  1924. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  1925. ULONG64 i;
  1926. ULONG PoolHeaderInfoLength;
  1927. BOOLEAN IsValid;
  1928. UINT64 StartPage;
  1929. ULONG SizeOfPoolHdr;
  1930. //
  1931. //
  1932. //
  1933. StartPage = PAGE_ALIGN64(PoolPageToDump);
  1934. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1935. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  1936. PoolHeaderInfoLength = DataLength;
  1937. IsValid = TRUE;
  1938. i=0;
  1939. while ( i < PoolHeaderInfoLength ) {
  1940. if ( CheckControlC() ) {
  1941. break;
  1942. }
  1943. if (IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  1944. //
  1945. // if both links are valid,
  1946. // then follow the forward link
  1947. // else the list is invalid
  1948. //
  1949. if ((PoolHeaderInfo[i].Info & HEADER_BACK_LINK) &&
  1950. (PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK)) {
  1951. i = (PoolHeaderInfo[i].ForwardLink - StartPage) / SizeOfPoolHdr;
  1952. } else {
  1953. IsValid = FALSE;
  1954. break;
  1955. }
  1956. } else {
  1957. IsValid = FALSE;
  1958. break;
  1959. }
  1960. }
  1961. return IsValid;
  1962. }
  1963. VOID
  1964. DiagnosePoolHeadersDisplayLists(
  1965. IN ULONG64 PoolPageToDump,
  1966. IN OUT PVOID Data,
  1967. IN ULONG DataLength,
  1968. IN UCHAR Verbose
  1969. )
  1970. /*++
  1971. Description:
  1972. This routine displays all of the linked lists in a given pool page
  1973. Arguments:
  1974. PoolPageToDump - page to analyze
  1975. Data - the pool header info
  1976. DataLength - the # of entries in the header info
  1977. Returns:
  1978. none
  1979. --*/
  1980. {
  1981. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  1982. ULONG i;
  1983. ULONG j;
  1984. ULONG PoolHeaderInfoLength;
  1985. UINT64 StartPage;
  1986. ULONG SizeOfPoolHdr;
  1987. //
  1988. //
  1989. //
  1990. StartPage = PAGE_ALIGN64(PoolPageToDump);
  1991. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  1992. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  1993. PoolHeaderInfoLength = DataLength;
  1994. for (i = 0; i < PoolHeaderInfoLength; i++) {
  1995. if ( CheckControlC() ) {
  1996. break;
  1997. }
  1998. if (IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  1999. //
  2000. //
  2001. //
  2002. #if 0
  2003. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2004. dprintf("[ headerinfo = %02x @ %p ]: ", PoolHeaderInfo[i].Info, StartPage + (i*SizeOfPoolHdr));
  2005. } else {
  2006. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2007. }
  2008. for (j = 0; j < PoolHeaderInfo[i].Pass; j++) {
  2009. dprintf(" ");
  2010. }
  2011. dprintf("%02d\r\n", PoolHeaderInfo[i].Pass);
  2012. #else
  2013. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2014. DumpPoolHeaderInfo(
  2015. PoolPageToDump,
  2016. Data,
  2017. DataLength,
  2018. (ULONG)i,
  2019. Verbose
  2020. );
  2021. }
  2022. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2023. for (j = 0; j < PoolHeaderInfo[i].Pass; j++) {
  2024. dprintf(" ");
  2025. }
  2026. dprintf("%02d\r\n", PoolHeaderInfo[i].Pass);
  2027. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2028. dprintf("\n");
  2029. }
  2030. #endif
  2031. }
  2032. }
  2033. }
  2034. NTSTATUS
  2035. FindLongestList(
  2036. IN ULONG64 PoolPageToDump,
  2037. IN OUT PVOID Data,
  2038. IN ULONG DataLength,
  2039. OUT PULONG PassStart
  2040. )
  2041. /*++
  2042. Description:
  2043. Find the longest contiguous linked list in the pool page
  2044. Arguments:
  2045. PoolPageToDump - page to analyze
  2046. Data - the pool header info
  2047. DataLength - the # of entries in the header info
  2048. PassStart - List # we think is the start of the longest list
  2049. Returns:
  2050. status
  2051. --*/
  2052. {
  2053. NTSTATUS Status;
  2054. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  2055. ULONG64 i;
  2056. ULONG PoolHeaderInfoLength;
  2057. BOOLEAN InCorruptedRegion;
  2058. UINT64 CorruptedRegionStart;
  2059. ULONG CorruptedRegionPassStart;
  2060. UINT MaxListPassStart;
  2061. UINT MaxListLength;
  2062. BOOLEAN Found;
  2063. ULONG Pass;
  2064. ULONG SizeOfPoolHdr;
  2065. ULONG64 StartPage;
  2066. ULONG ListLength;
  2067. ULONG ListPassStart;
  2068. //
  2069. // default: we were successful
  2070. //
  2071. Status = STATUS_SUCCESS;
  2072. //
  2073. //
  2074. //
  2075. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  2076. PoolHeaderInfoLength = DataLength;
  2077. //
  2078. //
  2079. //
  2080. MaxListPassStart = 0;
  2081. MaxListLength = 0;
  2082. *PassStart = 0;
  2083. Pass = 0;
  2084. StartPage = PAGE_ALIGN64(PoolPageToDump);
  2085. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  2086. do {
  2087. if ( CheckControlC() ) {
  2088. break;
  2089. }
  2090. Pass++;
  2091. InCorruptedRegion = FALSE;
  2092. ListLength = 0;
  2093. ListPassStart = Pass;
  2094. Found = FALSE;
  2095. for (i = 0; i < PoolHeaderInfoLength; i++) {
  2096. if (PoolHeaderInfo[i].Pass == Pass) {
  2097. Found = TRUE;
  2098. break;
  2099. }
  2100. }
  2101. while (i < PoolHeaderInfoLength) {
  2102. if ( CheckControlC() ) {
  2103. break;
  2104. }
  2105. //
  2106. // make sure we arent in an infinite loop
  2107. //
  2108. // if we are, then we could be looking at memory
  2109. // that is not available - mini dump and PoolPageToDump = 0
  2110. //
  2111. if (ListLength > MAX_POOL_HEADER_COUNT) {
  2112. Status = STATUS_UNSUCCESSFUL;
  2113. break;
  2114. }
  2115. if (IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  2116. //
  2117. // if we are in a corrupt region,
  2118. // then determine if where we are in the region.
  2119. //
  2120. if (InCorruptedRegion) {
  2121. //
  2122. // ignore nodes that are clearly part of another
  2123. // linked list
  2124. // if we are tracing the longest list,
  2125. // then these nodes are considered spurious
  2126. //
  2127. if ((PoolHeaderInfo[i].Info & HEADER_BACK_LINK) ||
  2128. (PoolHeaderInfo[i].Info & HEADER_FIXED_BACK_LINK)) {
  2129. //
  2130. // we've hit the middle of another linked list so
  2131. // continue until we find the beginning of a
  2132. // list
  2133. //
  2134. i++;
  2135. continue;
  2136. } else {
  2137. //
  2138. // we've found the beginning of a new list
  2139. // and are no longer in a Corrupt region
  2140. //
  2141. InCorruptedRegion = FALSE;
  2142. }
  2143. }
  2144. //
  2145. //
  2146. //
  2147. if ((PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK) ||
  2148. (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK)) {
  2149. ListLength++;
  2150. if (PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK) {
  2151. i = (PoolHeaderInfo[i].ForwardLink - StartPage) / SizeOfPoolHdr;
  2152. } else if (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK) {
  2153. UINT64 offset;
  2154. offset = PoolHeaderInfo[i].FixedBlockSize << POOL_BLOCK_SHIFT;
  2155. i = ((PoolHeaderInfo[i].Node + offset) - StartPage ) / SizeOfPoolHdr;
  2156. }
  2157. continue;
  2158. } else {
  2159. //
  2160. //
  2161. //
  2162. CorruptedRegionStart = PoolHeaderInfo[i].Node;
  2163. CorruptedRegionPassStart = PoolHeaderInfo[i].Pass;
  2164. InCorruptedRegion = TRUE;
  2165. }
  2166. }
  2167. //
  2168. // if pool header was not valid,
  2169. // then increment by one header
  2170. //
  2171. i++;
  2172. }
  2173. if (! NT_SUCCESS(Status)) {
  2174. break;
  2175. }
  2176. if (ListLength > MaxListLength) {
  2177. MaxListLength = ListLength;
  2178. MaxListPassStart = ListPassStart;
  2179. }
  2180. } while ( Found );
  2181. if (NT_SUCCESS(Status)) {
  2182. //
  2183. // send back the max list start point
  2184. //
  2185. *PassStart = MaxListPassStart;
  2186. }
  2187. return Status;
  2188. }
  2189. NTSTATUS
  2190. AnalyzeLongestList(
  2191. IN ULONG64 PoolPageToDump,
  2192. IN OUT PVOID Data,
  2193. IN ULONG DataLength,
  2194. IN ULONG PassStart,
  2195. IN UCHAR Verbose
  2196. )
  2197. /*++
  2198. Description:
  2199. Attempt to diagnose the longest linked list.
  2200. Arguments:
  2201. PoolPageToDump - page to analyze
  2202. Data - the pool header info
  2203. DataLength - the # of entries in the header info
  2204. PassStart - the list # that we think is the beginning
  2205. of the longest list
  2206. Verbose - the level of spew
  2207. Returns:
  2208. None
  2209. --*/
  2210. {
  2211. NTSTATUS Status;
  2212. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  2213. ULONG64 i;
  2214. ULONG PoolHeaderInfoLength;
  2215. BOOLEAN InCorruptedRegion;
  2216. UINT64 CorruptedRegionStart;
  2217. ULONG CorruptedRegionPassStart;
  2218. ULONG Pass;
  2219. ULONG SizeOfPoolHdr;
  2220. ULONG64 StartPage;
  2221. //
  2222. // default: we were successful
  2223. //
  2224. Status = STATUS_SUCCESS;
  2225. //
  2226. //
  2227. //
  2228. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  2229. PoolHeaderInfoLength = DataLength;
  2230. Pass = PassStart;
  2231. if (PassStart > 0) {
  2232. Pass--;
  2233. }
  2234. StartPage = PAGE_ALIGN64(PoolPageToDump);
  2235. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  2236. Pass++;
  2237. InCorruptedRegion = FALSE;
  2238. for (i = 0; i < PoolHeaderInfoLength; i++) {
  2239. if (PoolHeaderInfo[i].Pass == Pass) {
  2240. break;
  2241. }
  2242. }
  2243. while (i < PoolHeaderInfoLength) {
  2244. if ( CheckControlC() ) {
  2245. break;
  2246. }
  2247. if (IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  2248. //
  2249. // if we are in a corrupt region,
  2250. // then determine if where we are in the region.
  2251. //
  2252. if (InCorruptedRegion) {
  2253. //
  2254. // ignore nodes that are clearly part of another
  2255. // linked list
  2256. // if we are tracing the longest list,
  2257. // then these nodes are considered spurious
  2258. //
  2259. if ((PoolHeaderInfo[i].Info & HEADER_BACK_LINK) ||
  2260. (PoolHeaderInfo[i].Info & HEADER_FIXED_BACK_LINK)) {
  2261. //
  2262. // we've hit the middle of another linked list so
  2263. // continue until we find the beginning of a
  2264. // list
  2265. //
  2266. if (Verbose & VERBOSE_SHOW_ALL) {
  2267. dprintf("[ %p ]: found middle node in Corrupt region\n", PoolHeaderInfo[i].Node);
  2268. }
  2269. i++;
  2270. continue;
  2271. } else {
  2272. //
  2273. // we've found the beginning of a new list
  2274. // and are no longer in a Corrupt region
  2275. //
  2276. if (Verbose & VERBOSE_SHOW_ALL) {
  2277. dprintf("[ %p ]: Corrupt region stopped\n", PoolHeaderInfo[i].Node);
  2278. }
  2279. dprintf("[ %p --> %p (size = 0x%x bytes)]: Corrupt region\n",
  2280. CorruptedRegionStart,
  2281. PoolHeaderInfo[i].Node,
  2282. PoolHeaderInfo[i].Node - CorruptedRegionStart
  2283. );
  2284. InCorruptedRegion = FALSE;
  2285. }
  2286. }
  2287. //
  2288. // emit
  2289. //
  2290. if (Verbose) {
  2291. //
  2292. // emit the current node info
  2293. //
  2294. {
  2295. ULONG j;
  2296. //
  2297. //
  2298. //
  2299. #if 1
  2300. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2301. dprintf("[ headerinfo = 0x%02x @ %p ]: ", PoolHeaderInfo[i].Info, StartPage + (i*SizeOfPoolHdr));
  2302. } else {
  2303. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2304. }
  2305. #else
  2306. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2307. #endif
  2308. for (j = 0; j < PoolHeaderInfo[i].Pass; j++) {
  2309. dprintf(" ");
  2310. }
  2311. dprintf("%02d\r\n", PoolHeaderInfo[i].Pass);
  2312. }
  2313. }
  2314. //
  2315. // if the back link is corrected,
  2316. // then display the correction
  2317. //
  2318. if (PoolHeaderInfo[i].Info & HEADER_FIXED_BACK_LINK) {
  2319. ULONG PreviousSize;
  2320. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  2321. dprintf(
  2322. "[ %p ]: invalid previous size [ 0x%x ] should be [ 0x%x ]\n",
  2323. PoolHeaderInfo[i].Node,
  2324. PreviousSize,
  2325. PoolHeaderInfo[i].FixedPreviousSize
  2326. );
  2327. }
  2328. //
  2329. //
  2330. //
  2331. if ((PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK) ||
  2332. (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK)) {
  2333. if (PoolHeaderInfo[i].Info & HEADER_FORWARD_LINK) {
  2334. // dprintf("using good forward link: %p\n", PoolHeaderInfo[i].ForwardLink);
  2335. i = (PoolHeaderInfo[i].ForwardLink - StartPage) / SizeOfPoolHdr;
  2336. } else if (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK) {
  2337. UINT64 offset;
  2338. ULONG BlockSize;
  2339. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  2340. dprintf(
  2341. "[ %p ]: invalid block size [ 0x%x ] should be [ 0x%x ]\n",
  2342. PoolHeaderInfo[i].Node,
  2343. BlockSize,
  2344. PoolHeaderInfo[i].FixedBlockSize
  2345. );
  2346. offset = PoolHeaderInfo[i].FixedBlockSize << POOL_BLOCK_SHIFT;
  2347. i = ((PoolHeaderInfo[i].Node + offset) - StartPage ) / SizeOfPoolHdr;
  2348. }
  2349. continue;
  2350. } else {
  2351. //
  2352. //
  2353. //
  2354. CorruptedRegionStart = PoolHeaderInfo[i].Node;
  2355. CorruptedRegionPassStart = PoolHeaderInfo[i].Pass;
  2356. if (Verbose & VERBOSE_SHOW_ALL) {
  2357. dprintf("[ %p ]: Corrupt region started\n", CorruptedRegionStart);
  2358. }
  2359. InCorruptedRegion = TRUE;
  2360. }
  2361. }
  2362. //
  2363. // if pool header was not valid,
  2364. // then increment by one header
  2365. //
  2366. i++;
  2367. }
  2368. return Status;
  2369. }
  2370. NTSTATUS
  2371. DiagnosePoolHeadersAnalyzeLongestList(
  2372. IN ULONG64 PoolPageToDump,
  2373. IN OUT PVOID Data,
  2374. IN ULONG DataLength,
  2375. IN UCHAR Verbose
  2376. )
  2377. /*++
  2378. Description:
  2379. Determines the longest contiguous linked list in the pool page.
  2380. We make the conclusion that the longest list is likely to be
  2381. the original, uncorrupted list.
  2382. Arguments:
  2383. PoolPageToDump - page to analyze
  2384. Data - the pool header info
  2385. DataLength - the # of entries in the header info
  2386. Verbose - level of verbosity
  2387. Returns:
  2388. None
  2389. --*/
  2390. {
  2391. NTSTATUS Status;
  2392. ULONG PassStart;
  2393. do {
  2394. //
  2395. // first, find the longest list
  2396. //
  2397. Status = FindLongestList(
  2398. PoolPageToDump,
  2399. Data,
  2400. DataLength,
  2401. &PassStart
  2402. );
  2403. if (! NT_SUCCESS(Status)) {
  2404. break;
  2405. }
  2406. //
  2407. // once we have found the longest list
  2408. // we then try to analyze it
  2409. //
  2410. Status = AnalyzeLongestList(
  2411. PoolPageToDump,
  2412. Data,
  2413. DataLength,
  2414. PassStart,
  2415. Verbose
  2416. );
  2417. } while ( FALSE );
  2418. return Status;
  2419. }
  2420. ULONG
  2421. GetHammingDistance(
  2422. ULONG a,
  2423. ULONG b
  2424. )
  2425. {
  2426. ULONG x;
  2427. ULONG r;
  2428. x = a ^ b;
  2429. x -= ((x >> 1) & 0x55555555);
  2430. x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
  2431. x = (((x >> 4) + x) & 0x0f0f0f0f);
  2432. x += (x >> 8);
  2433. x += (x >> 16);
  2434. r = (x & 0x0000003f);
  2435. // dprintf("a = %d, b = %d, r = %d\n", a, b, r);
  2436. return(r);
  2437. }
  2438. VOID
  2439. DiagnosePoolHeadersSingleBitErrors(
  2440. IN ULONG64 PoolPageToDump,
  2441. IN OUT PVOID Data,
  2442. IN ULONG DataLength,
  2443. IN UCHAR Verbose
  2444. )
  2445. /*++
  2446. Description:
  2447. Determins if & where there are any single bit errors in the pool headers.
  2448. Arguments:
  2449. PoolPageToDump - page to analyze
  2450. Data - the pool header info
  2451. DataLength - the # of entries in the header info
  2452. Returns:
  2453. None
  2454. --*/
  2455. {
  2456. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  2457. ULONG i;
  2458. ULONG PoolHeaderInfoLength;
  2459. UINT64 StartPage;
  2460. BOOLEAN Found;
  2461. ULONG SizeOfPoolHdr;
  2462. //
  2463. //
  2464. //
  2465. StartPage = PAGE_ALIGN64(PoolPageToDump);
  2466. SizeOfPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  2467. PoolHeaderInfo = (PVALIDATE_POOL_HEADER_INFO)Data;
  2468. PoolHeaderInfoLength = DataLength;
  2469. Found = FALSE;
  2470. for (i = 0; i < PoolHeaderInfoLength; i++) {
  2471. if ( CheckControlC() ) {
  2472. break;
  2473. }
  2474. if (IS_VALID_PASS(PoolHeaderInfo[i].Pass)) {
  2475. //
  2476. //
  2477. //
  2478. if (PoolHeaderInfo[i].Info & HEADER_FIXED_BACK_LINK) {
  2479. ULONG PreviousSize;
  2480. ULONG HammingDistance;
  2481. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  2482. //
  2483. //
  2484. //
  2485. HammingDistance = GetHammingDistance(
  2486. PreviousSize,
  2487. (ULONG)PoolHeaderInfo[i].FixedPreviousSize
  2488. );
  2489. if (HammingDistance == 1) {
  2490. Found = TRUE;
  2491. //
  2492. //
  2493. //
  2494. #if 0
  2495. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2496. dprintf("[ headerinfo = 0x%02x @ %p ]: ", PoolHeaderInfo[i].Info, StartPage + (i*SizeOfPoolHdr));
  2497. } else {
  2498. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2499. }
  2500. dprintf(
  2501. "previous size [ 0x%x ] should be [ 0x%x ]\n",
  2502. PreviousSize,
  2503. PoolHeaderInfo[i].FixedPreviousSize
  2504. );
  2505. #else
  2506. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2507. dprintf(
  2508. "previous size [ 0x%x ] should be [ 0x%x ]\n",
  2509. PreviousSize,
  2510. PoolHeaderInfo[i].FixedPreviousSize
  2511. );
  2512. #endif
  2513. }
  2514. }
  2515. if (PoolHeaderInfo[i].Info & HEADER_FIXED_FORWARD_LINK) {
  2516. ULONG BlockSize;
  2517. ULONG HammingDistance;
  2518. GetFieldValue( PoolHeaderInfo[i].Node, "nt!_POOL_HEADER", "BlockSize", BlockSize);
  2519. //
  2520. //
  2521. //
  2522. HammingDistance = GetHammingDistance(
  2523. BlockSize,
  2524. (ULONG)PoolHeaderInfo[i].FixedPreviousSize
  2525. );
  2526. if (HammingDistance == 1) {
  2527. Found = TRUE;
  2528. #if 0
  2529. if (Verbose & VERBOSE_SHOW_HEADER_INFO) {
  2530. dprintf("[ headerinfo = 0x%02x @ %p ]: ", PoolHeaderInfo[i].Info, StartPage + (i*SizeOfPoolHdr));
  2531. } else {
  2532. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2533. }
  2534. dprintf(
  2535. "previous size [ 0x%x ] should be [ 0x%x ]\n",
  2536. PreviousSize,
  2537. PoolHeaderInfo[i].FixedPreviousSize
  2538. );
  2539. #else
  2540. dprintf("[ %p ]: ", StartPage + (i*SizeOfPoolHdr));
  2541. dprintf(
  2542. "block size [ 0x%x ] should be [ 0x%x ]\n",
  2543. BlockSize,
  2544. PoolHeaderInfo[i].FixedBlockSize
  2545. );
  2546. #endif
  2547. }
  2548. }
  2549. }
  2550. }
  2551. if (!Found) {
  2552. dprintf("\n");
  2553. dprintf("None found\n");
  2554. }
  2555. dprintf("\n");
  2556. }
  2557. NTSTATUS
  2558. ValidatePoolPage(
  2559. IN ULONG64 PoolPageToDump,
  2560. IN UCHAR Verbose
  2561. )
  2562. /*++
  2563. Description:
  2564. Provides the core, high level, functionality of analyzing the pool page
  2565. Arguments:
  2566. PoolPageToDump - page to analyze
  2567. Verbose - diagnostic level
  2568. Returns:
  2569. Status
  2570. --*/
  2571. {
  2572. PVALIDATE_POOL_HEADER_INFO PoolHeaderInfo;
  2573. NTSTATUS Status;
  2574. ULONG PoolHeaderInfoSize;
  2575. ULONG PoolHeaderInfoLength;
  2576. ULONG SizeofPoolHdr;
  2577. ULONG64 StartPage;
  2578. BOOLEAN IsValid;
  2579. //
  2580. //
  2581. //
  2582. Status = STATUS_SUCCESS;
  2583. SizeofPoolHdr = GetTypeSize("nt!_POOL_HEADER");
  2584. StartPage = PAGE_ALIGN64(PoolPageToDump);
  2585. PoolHeaderInfo = NULL;
  2586. PoolHeaderInfoSize = 0;
  2587. do {
  2588. //
  2589. // Allocate the pool header info array
  2590. //
  2591. PoolHeaderInfoLength = (POOL_PAGE_SIZE / SizeofPoolHdr);
  2592. PoolHeaderInfoSize = sizeof(VALIDATE_POOL_HEADER_INFO) * PoolHeaderInfoLength;
  2593. PoolHeaderInfo = malloc(PoolHeaderInfoSize);
  2594. if (PoolHeaderInfo == NULL) {
  2595. Status = STATUS_INSUFFICIENT_RESOURCES;
  2596. break;
  2597. }
  2598. RtlZeroMemory(PoolHeaderInfo, PoolHeaderInfoSize);
  2599. //
  2600. // Construct the first layer of meta info:
  2601. //
  2602. // determine the link status for each pool header
  2603. // in the page
  2604. //
  2605. Status = ScanPoolHeaders(
  2606. PoolPageToDump,
  2607. PoolHeaderInfo,
  2608. PoolHeaderInfoSize
  2609. );
  2610. if (! NT_SUCCESS(Status)) {
  2611. break;
  2612. }
  2613. //
  2614. // Construct the second layer of meta info:
  2615. //
  2616. // attempt to resolve the linked lists found
  2617. // in the pool page
  2618. //
  2619. Status = ResolvePoolHeaders(
  2620. PoolPageToDump,
  2621. PoolHeaderInfo,
  2622. PoolHeaderInfoLength
  2623. );
  2624. if (! NT_SUCCESS(Status)) {
  2625. break;
  2626. }
  2627. //
  2628. // begin diagnosis output
  2629. //
  2630. dprintf("\n");
  2631. IsValid = DiagnosePoolHeadersIsValid(
  2632. PoolPageToDump,
  2633. PoolHeaderInfo,
  2634. PoolHeaderInfoLength
  2635. );
  2636. dprintf("Pool page [ %p ] is %sVALID.\n",
  2637. StartPage,
  2638. IsValid ? "" : "IN"
  2639. );
  2640. if (! IsValid) {
  2641. if (Verbose & VERBOSE_DUMP_HEADERS) {
  2642. //
  2643. //
  2644. //
  2645. dprintf("\n\n");
  2646. dprintf("Displaying all POOL_HEADER meta info...\n");
  2647. DiagnosePoolHeadersDumpInfo(
  2648. PoolPageToDump,
  2649. PoolHeaderInfo,
  2650. PoolHeaderInfoLength,
  2651. Verbose
  2652. );
  2653. }
  2654. if (Verbose & VERBOSE_SHOW_LISTS) {
  2655. //
  2656. //
  2657. //
  2658. dprintf("\n");
  2659. dprintf("Displaying linked lists...\n");
  2660. DiagnosePoolHeadersDisplayLists(
  2661. PoolPageToDump,
  2662. PoolHeaderInfo,
  2663. PoolHeaderInfoLength,
  2664. Verbose
  2665. );
  2666. }
  2667. //
  2668. //
  2669. //
  2670. dprintf("\n");
  2671. if (Verbose & VERBOSE_SHOW_LISTS) {
  2672. dprintf("Analyzing longest linked list...\n");
  2673. } else {
  2674. dprintf("Analyzing linked list...\n");
  2675. }
  2676. Status = DiagnosePoolHeadersAnalyzeLongestList(
  2677. PoolPageToDump,
  2678. PoolHeaderInfo,
  2679. PoolHeaderInfoLength,
  2680. Verbose
  2681. );
  2682. if (! NT_SUCCESS(Status)) {
  2683. break;
  2684. }
  2685. //
  2686. //
  2687. //
  2688. dprintf("\n\n");
  2689. dprintf("Scanning for single bit errors...\n");
  2690. DiagnosePoolHeadersSingleBitErrors(
  2691. PoolPageToDump,
  2692. PoolHeaderInfo,
  2693. PoolHeaderInfoLength,
  2694. Verbose
  2695. );
  2696. } else {
  2697. dprintf("\n");
  2698. }
  2699. } while ( FALSE );
  2700. if (! NT_SUCCESS(Status)) {
  2701. dprintf("\n");
  2702. dprintf("Failed to diagnose pool page\n");
  2703. dprintf("\n");
  2704. }
  2705. if (PoolHeaderInfo) {
  2706. free(PoolHeaderInfo);
  2707. }
  2708. return Status;
  2709. }
  2710. NTSTATUS
  2711. DiagnosePoolPage(
  2712. ULONG64 PoolPageToDump
  2713. )
  2714. /*++
  2715. Routine Description:
  2716. Diagnose a pool page for the !pool command.
  2717. This routine is called if the !pool command detects an error while
  2718. traversing a pool page.
  2719. Arguments:
  2720. PoolPageToDump - the page !pool was examining
  2721. Return Value:
  2722. Status
  2723. --*/
  2724. {
  2725. NTSTATUS Status;
  2726. DEBUG_POOL_REGION Region;
  2727. //
  2728. // determine the pool region
  2729. //
  2730. Region = GetPoolRegion(PoolPageToDump);
  2731. //
  2732. // we only try to diagnose known pool regions
  2733. //
  2734. // you can manually diagnose using !poolval
  2735. //
  2736. //
  2737. // Note: if someone passes us a 0 pool address,
  2738. // then we proactively fail the diagnosis process
  2739. //
  2740. if ((Region == DbgPoolRegionUnknown) || (PoolPageToDump == 0)) {
  2741. dprintf("\n");
  2742. dprintf("***\n");
  2743. dprintf("*** An error (or corruption) in the pool was detected;\n");
  2744. dprintf("*** Pool Region unkown (0x%I64X)\n", PoolPageToDump);
  2745. dprintf("***\n");
  2746. dprintf("*** Use !poolval %p for more details.\n", PAGE_ALIGN64(PoolPageToDump));
  2747. dprintf("***\n");
  2748. dprintf("\n");
  2749. Status = STATUS_SUCCESS;
  2750. } else {
  2751. dprintf("\n");
  2752. dprintf("***\n");
  2753. dprintf("*** An error (or corruption) in the pool was detected;\n");
  2754. dprintf("*** Attempting to diagnose the problem.\n");
  2755. dprintf("***\n");
  2756. dprintf("*** Use !poolval %p for more details.\n", PAGE_ALIGN64(PoolPageToDump));
  2757. dprintf("***\n");
  2758. Status = ValidatePoolPage(
  2759. PoolPageToDump,
  2760. VERBOSE_SHOW_ERRORS_ONLY
  2761. );
  2762. }
  2763. return Status;
  2764. }
  2765. DECLARE_API( poolval )
  2766. /*++
  2767. Routine Description:
  2768. Provide in-depth heap diagnosis.
  2769. Given a suspect pool page, the primary purpose of this command
  2770. is to analyze the page and determine:
  2771. 1. where in the page the corruption exists.
  2772. 2. single bit errors in page headers (previous/block sizes)
  2773. 3. what the correct link list should be
  2774. Arguments:
  2775. args - the page to analyze
  2776. Return Value:
  2777. None
  2778. --*/
  2779. {
  2780. ULONG64 PoolPageToDump;
  2781. ULONG Flags;
  2782. HRESULT Hr;
  2783. INIT_API();
  2784. Status = STATUS_SUCCESS;
  2785. if (PoolInitializeGlobals() == FALSE) {
  2786. Hr = E_INVALIDARG;
  2787. } else {
  2788. PoolPageToDump = 0;
  2789. Flags = 0;
  2790. if (GetExpressionEx(args, &PoolPageToDump, &args)) {
  2791. Flags = (ULONG) GetExpression (args);
  2792. }
  2793. if (PoolPageToDump == 0) {
  2794. Hr = S_OK;;
  2795. } else {
  2796. UCHAR Verbose;
  2797. //
  2798. //
  2799. //
  2800. dprintf("Pool page %p region is ", PoolPageToDump);
  2801. PrintPoolRegion(PoolPageToDump);
  2802. //
  2803. //
  2804. //
  2805. dprintf("\n");
  2806. dprintf("Validating Pool headers for pool page: %p\n", PoolPageToDump);
  2807. //
  2808. //
  2809. //
  2810. Verbose = VERBOSE_SHOW_ERRORS_ONLY;
  2811. switch (Flags) {
  2812. case 2: Verbose |= VERBOSE_SHOW_LISTS | VERBOSE_SHOW_HEADER_INFO; break;
  2813. case 3: Verbose |= VERBOSE_SHOW_LISTS | VERBOSE_SHOW_HEADER_INFO | VERBOSE_DUMP_HEADERS; break;
  2814. case 1: Verbose |= VERBOSE_SHOW_LISTS;
  2815. default:
  2816. break;
  2817. }
  2818. //
  2819. // Attempt to Analyze and Diagnose the specified poolpage
  2820. //
  2821. Status = ValidatePoolPage(
  2822. PoolPageToDump,
  2823. Verbose
  2824. );
  2825. }
  2826. }
  2827. EXIT_API();
  2828. if (NT_SUCCESS(Status)) {
  2829. Hr = S_OK;
  2830. } else {
  2831. Hr = E_FAIL;
  2832. }
  2833. return Hr;
  2834. }
  2835. DECLARE_API( poolused )
  2836. /*++
  2837. Routine Description:
  2838. Dump usage by pool tag
  2839. Arguments:
  2840. args -
  2841. Flags : Bitfield with the following meaning:
  2842. 0x1: Dump both allocations & frees (instead of the difference)
  2843. 0x2: Sort by nonpaged pool consumption
  2844. 0x4: Sort by paged pool consumption
  2845. 0x8: Dump session space consumption
  2846. Return Value:
  2847. None
  2848. --*/
  2849. {
  2850. ULONG PoolTrackTableSize;
  2851. ULONG PoolTrackTableSizeInBytes;
  2852. ULONG PoolTrackTableExpansionSize;
  2853. ULONG PoolTrackTableExpansionSizeInBytes;
  2854. PPOOLTRACK_READ p;
  2855. PPOOLTRACK_READ pentry;
  2856. PPOOLTRACK_READ PoolTrackTableData;
  2857. ULONG Flags;
  2858. ULONG i;
  2859. ULONG result;
  2860. ULONG ct;
  2861. ULONG TagName;
  2862. CHAR TagNameX[4] = {'*','*','*','*'};
  2863. ULONG SizeOfPoolTracker;
  2864. ULONG64 PoolTableAddress;
  2865. ULONG64 PoolTrackTable;
  2866. ULONG64 PoolTrackTableExpansion;
  2867. ULONG NonPagedAllocsTotal,NonPagedFreesTotal,PagedAllocsTotal,PagedFreesTotal;
  2868. ULONG64 NonPagedBytesTotal, PagedBytesTotal;
  2869. ULONG Processor, MaxProcessors;
  2870. ULONG64 ExPoolTagTables;
  2871. POOLTRACK_READ PoolTrackEntry;
  2872. ULONG64 Location;
  2873. ExPoolTagTables = GetExpression("nt!ExPoolTagTables");
  2874. if (PoolInitializeGlobals() == FALSE) {
  2875. return E_INVALIDARG;
  2876. }
  2877. Flags = 0;
  2878. if (!sscanf(args,"%lx %c%c%c%c", &Flags, &TagNameX[0],
  2879. &TagNameX[1], &TagNameX[2], &TagNameX[3])) {
  2880. Flags = 0;
  2881. }
  2882. TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
  2883. PoolTrackTableExpansionSize = 0;
  2884. if (!(SizeOfPoolTracker = GetTypeSize("nt!_POOL_TRACKER_TABLE"))) {
  2885. dprintf("Unable to get _POOL_TRACKER_TABLE : probably wrong symbols.\n");
  2886. return E_INVALIDARG;
  2887. }
  2888. if (Flags & 0x8) {
  2889. Location = GetExpression ("ExpSessionPoolTrackTable");
  2890. if (!Location) {
  2891. dprintf("Unable to get ExpSessionPoolTrackTable\n");
  2892. return E_INVALIDARG;
  2893. }
  2894. ReadPointer(Location, &PoolTrackTable);
  2895. PoolTrackTableSize = 0;
  2896. PoolTrackTableSize = GetUlongValue ("nt!ExpSessionPoolTrackTableSize");
  2897. }
  2898. else {
  2899. PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
  2900. PoolTrackTableSize = GetUlongValue ("nt!PoolTrackTableSize");
  2901. PoolTrackTableExpansionSize = GetUlongValue ("nt!PoolTrackTableExpansionSize");
  2902. }
  2903. if (PoolTrackTable == 0) {
  2904. dprintf ("unable to get PoolTrackTable - ");
  2905. if (GetExpression("nt!PoolTrackTable")) {
  2906. dprintf ("pool tagging is disabled, enable it to use this command\n");
  2907. dprintf ("Use gflags.exe and check the box that says \"Enable pool tagging\".\n");
  2908. } else {
  2909. dprintf ("symbols could be worng\n");
  2910. }
  2911. return E_INVALIDARG;
  2912. }
  2913. if (Flags & 2) {
  2914. SortBy = NONPAGED_USED;
  2915. dprintf(" Sorting by %s NonPaged Pool Consumed\n", Flags & 0x8 ? "Session" : "");
  2916. } else if (Flags & 4) {
  2917. SortBy = PAGED_USED;
  2918. dprintf(" Sorting by %s Paged Pool Consumed\n", Flags & 0x8 ? "Session" : "");
  2919. } else {
  2920. SortBy = TAG;
  2921. dprintf(" Sorting by %s Tag\n", Flags & 0x8 ? "Session" : "");
  2922. }
  2923. dprintf("\n Pool Used:\n");
  2924. if (!(Flags & 1)) {
  2925. dprintf(" NonPaged Paged\n");
  2926. dprintf(" Tag Allocs Used Allocs Used\n");
  2927. } else {
  2928. dprintf(" NonPaged Paged\n");
  2929. dprintf(" Tag Allocs Frees Diff Used Allocs Frees Diff Used\n");
  2930. }
  2931. //
  2932. // Allocate a temp buffer, read the data, then free the data.
  2933. // (KD will cache the data).
  2934. //
  2935. PoolTrackTableSizeInBytes = PoolTrackTableSize * SizeOfPoolTracker;
  2936. PoolTrackTableExpansionSizeInBytes = PoolTrackTableExpansionSize * SizeOfPoolTracker;
  2937. PoolTrackTableData = malloc (PoolTrackTableSizeInBytes);
  2938. if (PoolTrackTableData == NULL) {
  2939. dprintf("unable to allocate memory for tag table.\n");
  2940. return E_INVALIDARG;
  2941. }
  2942. PoolTableAddress = PoolTrackTable;
  2943. if ( !ReadMemory( PoolTableAddress,
  2944. &PoolTrackTableData[0],
  2945. PoolTrackTableSizeInBytes,
  2946. &result) ) {
  2947. dprintf("%08p: Unable to get contents of pool block\n", PoolTableAddress );
  2948. dprintf("\nThe current process probably is not a session process.\n");
  2949. dprintf("Note the system, idle and smss processes are non-session processes.\n");
  2950. free (PoolTrackTableData);
  2951. return E_INVALIDARG;
  2952. }
  2953. ct = PageSize / SizeOfPoolTracker;
  2954. i = 0;
  2955. PoolTableAddress = PoolTrackTable;
  2956. free (PoolTrackTableData);
  2957. //
  2958. // Create array of POOL_TRACKER_TABLE addresses and sort the addresses
  2959. //
  2960. PoolTrackTableData = malloc ((PoolTrackTableSize + PoolTrackTableExpansionSize) * sizeof(POOLTRACK_READ));
  2961. if (PoolTrackTableData == NULL) {
  2962. dprintf("unable to allocate memory for tag table.\n");
  2963. return E_INVALIDARG;
  2964. }
  2965. if (Flags & 0x8) {
  2966. MaxProcessors = 1;
  2967. }
  2968. else {
  2969. MaxProcessors = (UCHAR) GetUlongValue ("KeNumberProcessors");
  2970. }
  2971. Processor = 0;
  2972. NonPagedAllocsTotal = 0;
  2973. NonPagedFreesTotal = 0;
  2974. NonPagedBytesTotal = 0;
  2975. PagedAllocsTotal = 0;
  2976. PagedFreesTotal = 0;
  2977. PagedBytesTotal = 0;
  2978. p = PoolTrackTableData;
  2979. do {
  2980. pentry = &PoolTrackEntry;
  2981. for (i = 0; i < PoolTrackTableSize; i += 1) {
  2982. if (Processor == 0) {
  2983. pentry->Address = PoolTableAddress + i * SizeOfPoolTracker;
  2984. }
  2985. else {
  2986. pentry->Address = PoolTrackTable + i * SizeOfPoolTracker;
  2987. }
  2988. #define TrackFld(Fld) GetFieldValue(pentry->Address, "nt!_POOL_TRACKER_TABLE", #Fld, pentry->Fld)
  2989. TrackFld(Key);
  2990. TrackFld(NonPagedAllocs);
  2991. TrackFld(NonPagedBytes);
  2992. TrackFld(PagedBytes);
  2993. TrackFld(NonPagedFrees);
  2994. TrackFld(PagedAllocs);
  2995. TrackFld(PagedFrees);
  2996. #undef TrackFld
  2997. #if 0
  2998. if (pentry->Key != 0) {
  2999. dprintf("%c%c%c%c %8x %8x %8I64x %8x %8x %8I64x\n",
  3000. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3001. PP(pentry->Key),
  3002. PP(pentry->Key >> 8),
  3003. PP(pentry->Key >> 16),
  3004. PP(pentry->Key >> 24),
  3005. pentry->NonPagedAllocs,
  3006. pentry->NonPagedFrees,
  3007. pentry->NonPagedBytes,
  3008. pentry->PagedAllocs,
  3009. pentry->PagedFrees,
  3010. pentry->PagedBytes);
  3011. }
  3012. #endif
  3013. if (Processor == 0) {
  3014. p[i].Address = pentry->Address;
  3015. p[i].Key = pentry->Key;
  3016. p[i].NonPagedAllocs = pentry->NonPagedAllocs;
  3017. p[i].NonPagedFrees = pentry->NonPagedFrees;
  3018. p[i].NonPagedBytes = pentry->NonPagedBytes;
  3019. p[i].PagedAllocs = pentry->PagedAllocs;
  3020. p[i].PagedBytes = pentry->PagedBytes;
  3021. p[i].PagedFrees = pentry->PagedFrees;
  3022. }
  3023. if ((pentry->Key != 0) &&
  3024. (CheckSingleFilter ((PCHAR)&pentry->Key, (PCHAR)&TagName))) {
  3025. if (Processor != 0) {
  3026. p[i].NonPagedAllocs += pentry->NonPagedAllocs;
  3027. p[i].NonPagedFrees += pentry->NonPagedFrees;
  3028. p[i].NonPagedBytes += pentry->NonPagedBytes;
  3029. p[i].PagedAllocs += pentry->PagedAllocs;
  3030. p[i].PagedFrees += pentry->PagedFrees;
  3031. p[i].PagedBytes += pentry->PagedBytes;
  3032. }
  3033. }
  3034. if (!IsPtr64()) {
  3035. p[i].NonPagedBytes &= (LONG64) 0xFFFFFFFF;
  3036. p[i].PagedBytes &= (LONG64) 0xFFFFFFFF;
  3037. }
  3038. }
  3039. Processor += 1;
  3040. if (Processor >= MaxProcessors) {
  3041. break;
  3042. }
  3043. if (ExPoolTagTables == 0) {
  3044. break;
  3045. }
  3046. ReadPointer (ExPoolTagTables+DBG_PTR_SIZE*Processor, &PoolTrackTable);
  3047. } while (TRUE);
  3048. //
  3049. // Add the expansion table too (if there is one).
  3050. //
  3051. if (PoolTrackTableExpansionSize != 0) {
  3052. //
  3053. // Allocate a temp buffer, read the data, then free the data.
  3054. // (KD will cache the data).
  3055. //
  3056. pentry = malloc (PoolTrackTableExpansionSizeInBytes);
  3057. if (pentry == NULL) {
  3058. dprintf("unable to allocate memory for expansion tag table.\n");
  3059. }
  3060. else {
  3061. PoolTrackTableExpansion = GetPointerValue("nt!PoolTrackTableExpansion");
  3062. PoolTableAddress = PoolTrackTableExpansion;
  3063. if ( !ReadMemory( PoolTableAddress,
  3064. pentry,
  3065. PoolTrackTableExpansionSizeInBytes,
  3066. &result) ) {
  3067. dprintf("%08p: Unable to get contents of expansion tag table\n", PoolTableAddress );
  3068. }
  3069. else {
  3070. PoolTrackTableSize += PoolTrackTableExpansionSize;
  3071. ct = 0;
  3072. for ( ; i < PoolTrackTableSize; i += 1, ct += 1) {
  3073. p[i].Address = PoolTableAddress + ct * SizeOfPoolTracker;
  3074. #define TrackFld(Fld) GetFieldValue(p[i].Address, "nt!_POOL_TRACKER_TABLE", #Fld, p[i].Fld)
  3075. TrackFld(Key);
  3076. TrackFld(NonPagedAllocs);
  3077. TrackFld(NonPagedBytes);
  3078. TrackFld(PagedBytes);
  3079. TrackFld(NonPagedFrees);
  3080. TrackFld(PagedAllocs);
  3081. TrackFld(PagedFrees);
  3082. #if 0
  3083. if (p[i].Key != 0) {
  3084. dprintf("%c%c%c%c %8x %8x %8I64x %8x %8x %8I64x\n",
  3085. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3086. PP(p[i].Key),
  3087. PP(p[i].Key >> 8),
  3088. PP(p[i].Key >> 16),
  3089. PP(p[i].Key >> 24),
  3090. p[i].NonPagedAllocs,
  3091. p[i].NonPagedFrees,
  3092. p[i].NonPagedBytes,
  3093. p[i].PagedAllocs,
  3094. p[i].PagedFrees,
  3095. p[i].PagedBytes);
  3096. }
  3097. #endif
  3098. }
  3099. }
  3100. free (pentry);
  3101. }
  3102. }
  3103. qsort((void *)PoolTrackTableData,
  3104. (size_t)PoolTrackTableSize,
  3105. (size_t)sizeof(POOLTRACK_READ),
  3106. ulcomp);
  3107. i = 0;
  3108. p = PoolTrackTableData;
  3109. for ( ; i < PoolTrackTableSize; i += 1) {
  3110. if ((p[i].Key != 0) &&
  3111. (CheckSingleFilter ((PCHAR)&p[i].Key, (PCHAR)&TagName))) {
  3112. if (!(Flags & 1)) {
  3113. if ((p[i].NonPagedBytes != 0) || (p[i].PagedBytes != 0)) {
  3114. dprintf(" %c%c%c%c %8ld %8I64ld %8ld %8I64ld\n",
  3115. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3116. PP(p[i].Key),
  3117. PP(p[i].Key >> 8),
  3118. PP(p[i].Key >> 16),
  3119. PP(p[i].Key >> 24),
  3120. p[i].NonPagedAllocs - p[i].NonPagedFrees,
  3121. p[i].NonPagedBytes,
  3122. p[i].PagedAllocs - p[i].PagedFrees,
  3123. p[i].PagedBytes);
  3124. NonPagedAllocsTotal += p[i].NonPagedAllocs;
  3125. NonPagedFreesTotal += p[i].NonPagedFrees;
  3126. NonPagedBytesTotal += p[i].NonPagedBytes;
  3127. PagedAllocsTotal += p[i].PagedAllocs;
  3128. PagedFreesTotal += p[i].PagedFrees;
  3129. PagedBytesTotal += p[i].PagedBytes;
  3130. }
  3131. } else {
  3132. dprintf(" %c%c%c%c %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
  3133. PP(p[i].Key),
  3134. PP(p[i].Key >> 8),
  3135. PP(p[i].Key >> 16),
  3136. PP(p[i].Key >> 24),
  3137. p[i].NonPagedAllocs,
  3138. p[i].NonPagedFrees,
  3139. p[i].NonPagedAllocs - p[i].NonPagedFrees,
  3140. p[i].NonPagedBytes,
  3141. p[i].PagedAllocs,
  3142. p[i].PagedFrees,
  3143. p[i].PagedAllocs - p[i].PagedFrees,
  3144. p[i].PagedBytes);
  3145. #undef PP
  3146. NonPagedAllocsTotal += p[i].NonPagedAllocs;
  3147. NonPagedFreesTotal += p[i].NonPagedFrees;
  3148. NonPagedBytesTotal += p[i].NonPagedBytes;
  3149. PagedAllocsTotal += p[i].PagedAllocs;
  3150. PagedFreesTotal += p[i].PagedFrees;
  3151. PagedBytesTotal += p[i].PagedBytes;
  3152. }
  3153. }
  3154. }
  3155. if (!(Flags & 1)) {
  3156. dprintf(" TOTAL %8ld %8I64ld %8ld %8I64ld\n",
  3157. NonPagedAllocsTotal - NonPagedFreesTotal,
  3158. NonPagedBytesTotal,
  3159. PagedAllocsTotal - PagedFreesTotal,
  3160. PagedBytesTotal);
  3161. } else {
  3162. dprintf(" TOTAL %8ld %8ld %8ld %8I64ld %8ld %8ld %8ld %8I64ld\n",
  3163. NonPagedAllocsTotal,
  3164. NonPagedFreesTotal,
  3165. NonPagedAllocsTotal - NonPagedFreesTotal,
  3166. NonPagedBytesTotal,
  3167. PagedAllocsTotal,
  3168. PagedFreesTotal,
  3169. PagedAllocsTotal - PagedFreesTotal,
  3170. PagedBytesTotal);
  3171. }
  3172. free (PoolTrackTableData);
  3173. return S_OK;
  3174. }
  3175. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3176. BOOLEAN WINAPI
  3177. CheckSingleFilterAndPrint (
  3178. PCHAR Tag,
  3179. PCHAR Filter,
  3180. ULONG Flags,
  3181. ULONG64 PoolHeader,
  3182. ULONG64 BlockSize,
  3183. ULONG64 Data,
  3184. PVOID Context
  3185. )
  3186. /*++
  3187. Routine Description:
  3188. Callback to check a piece of pool and print out information about it
  3189. if it matches the specified tag.
  3190. Arguments:
  3191. Tag - Supplies the tag to search for.
  3192. Filter - Supplies the filter string to match against.
  3193. Flags - Supplies 0 if a nonpaged pool search is desired.
  3194. Supplies 1 if a paged pool search is desired.
  3195. Supplies 2 if a special pool search is desired.
  3196. Supplies 4 if a pool is a large pool
  3197. PoolHeader - Supplies the pool header.
  3198. BlockSize - Supplies the size of the pool block in bytes.
  3199. Data - Supplies the address of the pool block.
  3200. Context - Unused.
  3201. Return Value:
  3202. TRUE for a match, FALSE if not.
  3203. --*/
  3204. {
  3205. ULONG UTag = *((PULONG)Tag);
  3206. ULONG HdrUlong1=0, HdrPoolSize ;
  3207. LOGICAL QuotaProcessAtEndOfPoolBlock = FALSE;
  3208. UNREFERENCED_PARAMETER (Context);
  3209. if (CheckSingleFilter (Tag, Filter) == FALSE) {
  3210. return FALSE;
  3211. }
  3212. HdrPoolSize = GetTypeSize("nt!_POOL_HEADER");
  3213. if ((BlockSize >= (PageSize-2*HdrPoolSize)) || (Flags & 0x8)) {
  3214. dprintf("*%p :%slarge page allocation, Tag %3s %c%c%c%c, size %3s 0x%I64x bytes\n",
  3215. (Data & ~POOL_BIG_TABLE_ENTRY_FREE),
  3216. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "free " : "",
  3217. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
  3218. PP(UTag),
  3219. PP(UTag >> 8),
  3220. PP(UTag >> 16),
  3221. PP(UTag >> 24),
  3222. (Data & POOL_BIG_TABLE_ENTRY_FREE) ? "was" : "is",
  3223. BlockSize
  3224. );
  3225. } else if (Flags & 0x2) {
  3226. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  3227. dprintf("*%p size: %4lx %s special pool, Tag is %c%c%c%c\n",
  3228. Data,
  3229. BlockSize,
  3230. HdrUlong1 & MI_SPECIAL_POOL_PAGABLE ? "pagable" : "non-paged",
  3231. PP(UTag),
  3232. PP(UTag >> 8),
  3233. PP(UTag >> 16),
  3234. PP(UTag >> 24)
  3235. );
  3236. } else {
  3237. ULONG BlockSizeR, PreviousSize, PoolType, PoolIndex, AllocatorBackTraceIndex;
  3238. ULONG PoolTagHash, PoolTag;
  3239. ULONG64 ProcessBilled;
  3240. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", BlockSizeR);
  3241. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType);
  3242. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTagHash", PoolTagHash);
  3243. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  3244. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex);
  3245. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PreviousSize", PreviousSize);
  3246. if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
  3247. if (GetExpression ("nt!ExGetPoolTagInfo") != 0) {
  3248. //
  3249. // This is a kernel where the quota process pointer is at
  3250. // the end of the pool block instead of overlaid on the
  3251. // tag field.
  3252. //
  3253. QuotaProcessAtEndOfPoolBlock = TRUE;
  3254. if (QuotaProcessAtEndOfPoolBlock == TRUE) {
  3255. ULONG SizeOfPvoid = 0;
  3256. ULONG64 ProcessBillAddress;
  3257. SizeOfPvoid = DBG_PTR_SIZE;
  3258. if (SizeOfPvoid == 0) {
  3259. dprintf ("Search: cannot get size of PVOID\n");
  3260. return FALSE;
  3261. }
  3262. ProcessBillAddress = PoolHeader + ((ULONG64) BlockSizeR << POOL_BLOCK_SHIFT) - SizeOfPvoid;
  3263. ProcessBilled = READ_PVOID (ProcessBillAddress);
  3264. }
  3265. }
  3266. else {
  3267. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  3268. }
  3269. }
  3270. else {
  3271. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled);
  3272. }
  3273. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "AllocatorBackTraceIndex", AllocatorBackTraceIndex);
  3274. dprintf("%p size: %4lx previous size: %4lx ",
  3275. Data - HdrPoolSize,
  3276. BlockSizeR << POOL_BLOCK_SHIFT,
  3277. PreviousSize << POOL_BLOCK_SHIFT);
  3278. if (PoolType == 0) {
  3279. //
  3280. // "Free " with a space after it before the parentheses means
  3281. // it's been freed to a (pool manager internal) lookaside list.
  3282. // We used to print "Lookaside" but that just confused driver
  3283. // writers because they didn't know if this meant in use or not
  3284. // and many would say "but I don't use lookaside lists - the
  3285. // extension or kernel is broken".
  3286. //
  3287. // "Free" with no space after it before the parentheses means
  3288. // it is not on a pool manager internal lookaside list and is
  3289. // instead on the regular pool manager internal flink/blink
  3290. // chains.
  3291. //
  3292. // Note to anyone using the pool package, these 2 terms are
  3293. // equivalent. The fine distinction is only for those actually
  3294. // writing pool internal code.
  3295. //
  3296. dprintf(" (Free)");
  3297. dprintf(" %c%c%c%c\n",
  3298. PP(UTag),
  3299. PP(UTag >> 8),
  3300. PP(UTag >> 16),
  3301. PP(UTag >> 24)
  3302. );
  3303. } else {
  3304. if (!NewPool ? (PoolIndex & 0x80) : (PoolType & 0x04)) {
  3305. dprintf(" (Allocated)");
  3306. } else {
  3307. //
  3308. // "Free " with a space after it before the parentheses means
  3309. // it's been freed to a (pool manager internal) lookaside list.
  3310. // We used to print "Lookaside" but that just confused driver
  3311. // writers because they didn't know if this meant in use or not
  3312. // and many would say "but I don't use lookaside lists - the
  3313. // extension or kernel is broken".
  3314. //
  3315. // "Free" with no space after it before the parentheses means
  3316. // it is not on a pool manager internal lookaside list and is
  3317. // instead on the regular pool manager internal flink/blink
  3318. // chains.
  3319. //
  3320. // Note to anyone using the pool package, these 2 terms are
  3321. // equivalent. The fine distinction is only for those actually
  3322. // writing pool internal code.
  3323. //
  3324. dprintf(" (Free )");
  3325. }
  3326. if ((PoolType & POOL_QUOTA_MASK) == 0) {
  3327. UTag = PoolTag;
  3328. dprintf(" %c%c%c%c%s\n",
  3329. PP(UTag),
  3330. PP(UTag >> 8),
  3331. PP(UTag >> 16),
  3332. PP((UTag &~PROTECTED_POOL) >> 24),
  3333. (UTag & PROTECTED_POOL) ? " (Protected)" : ""
  3334. );
  3335. } else {
  3336. if ((QuotaProcessAtEndOfPoolBlock == TRUE) ||
  3337. (TargetMachine != IMAGE_FILE_MACHINE_I386)) {
  3338. UTag = PoolTag;
  3339. dprintf(" %c%c%c%c%s",
  3340. PP(UTag),
  3341. PP(UTag >> 8),
  3342. PP(UTag >> 16),
  3343. PP((UTag &~PROTECTED_POOL) >> 24),
  3344. (UTag & PROTECTED_POOL) ? " (Protected)" : ""
  3345. );
  3346. }
  3347. if (ProcessBilled != 0) {
  3348. dprintf(" Process: %08p\n", ProcessBilled );
  3349. }
  3350. else {
  3351. dprintf("\n");
  3352. }
  3353. }
  3354. }
  3355. }
  3356. return TRUE;
  3357. } // CheckSingleFilterAndPrint
  3358. #undef PP
  3359. ULONG64
  3360. GetNextResidentAddress (
  3361. ULONG64 VirtualAddress,
  3362. ULONG64 MaximumVirtualAddress
  3363. )
  3364. {
  3365. ULONG64 PointerPde;
  3366. ULONG64 PointerPte;
  3367. ULONG SizeOfPte;
  3368. ULONG Valid;
  3369. //
  3370. // Note this code will need to handle one more level of indirection for
  3371. // WIN64.
  3372. //
  3373. if (!(SizeOfPte=GetTypeSize("nt!_MMPTE"))) {
  3374. dprintf("Cannot get MMPTE type.\n");
  3375. return 0;
  3376. }
  3377. top:
  3378. PointerPde = DbgGetPdeAddress (VirtualAddress);
  3379. while (GetFieldValue(PointerPde,
  3380. "nt!_MMPTE",
  3381. "u.Hard.Valid",
  3382. Valid) ||
  3383. (Valid == 0)) {
  3384. //
  3385. // Note that on 32-bit systems, the PDE should always be readable.
  3386. // If the PDE is not valid then increment to the next PDE's VA.
  3387. //
  3388. PointerPde = (PointerPde + SizeOfPte);
  3389. VirtualAddress = DbgGetVirtualAddressMappedByPte (PointerPde);
  3390. VirtualAddress = DbgGetVirtualAddressMappedByPte (VirtualAddress);
  3391. if (VirtualAddress >= MaximumVirtualAddress) {
  3392. return VirtualAddress;
  3393. }
  3394. if (CheckControlC()) {
  3395. return VirtualAddress;
  3396. }
  3397. continue;
  3398. }
  3399. PointerPte = DbgGetPteAddress (VirtualAddress);
  3400. while (GetFieldValue(PointerPde,
  3401. "nt!_MMPTE",
  3402. "u.Hard.Valid",
  3403. Valid) ||
  3404. (Valid == 0)) {
  3405. //
  3406. // If the PTE cannot be read then increment by PAGE_SIZE.
  3407. //
  3408. VirtualAddress = (VirtualAddress + PageSize);
  3409. if (CheckControlC()) {
  3410. return VirtualAddress;
  3411. }
  3412. PointerPte = (PointerPte + SizeOfPte);
  3413. if ((PointerPte & (PageSize - 1)) == 0) {
  3414. goto top;
  3415. }
  3416. if (VirtualAddress >= MaximumVirtualAddress) {
  3417. return VirtualAddress;
  3418. }
  3419. }
  3420. return VirtualAddress;
  3421. }
  3422. VOID
  3423. SearchPool(
  3424. ULONG TagName,
  3425. ULONG Flags,
  3426. ULONG64 RestartAddr,
  3427. POOLFILTER Filter,
  3428. PVOID Context
  3429. )
  3430. /*++
  3431. Routine Description:
  3432. Engine to search the pool.
  3433. Arguments:
  3434. TagName - Supplies the tag to search for.
  3435. Flags - Supplies 0 if a nonpaged pool search is desired.
  3436. Supplies 1 if a paged pool search is desired.
  3437. Supplies 2 if a special pool search is desired.
  3438. Supplies 4 if a session pool search is desired.
  3439. RestartAddr - Supplies the address to restart the search from.
  3440. Filter - Supplies the filter routine to use.
  3441. Context - Supplies the user defined context blob.
  3442. Return Value:
  3443. None.
  3444. --*/
  3445. {
  3446. ULONG64 Location;
  3447. LOGICAL PhysicallyContiguous;
  3448. ULONG64 PoolBlockSize;
  3449. ULONG64 PoolHeader;
  3450. ULONG PoolTag;
  3451. ULONG Result;
  3452. ULONG64 PoolPage;
  3453. ULONG64 StartPage;
  3454. ULONG64 Pool;
  3455. ULONG Previous;
  3456. ULONG64 PoolStart;
  3457. ULONG64 PoolPteAddress;
  3458. ULONG64 PoolEnd;
  3459. ULONG64 ExpandedPoolStart;
  3460. ULONG64 ExpandedPoolEnd;
  3461. ULONG InitialPoolSize;
  3462. ULONG SkipSize;
  3463. BOOLEAN TwoPools;
  3464. ULONG64 DataPageReal;
  3465. ULONG64 DataStartReal;
  3466. LOGICAL Found;
  3467. ULONG i;
  3468. ULONG j;
  3469. ULONG ct;
  3470. ULONG PoolBigPageTableSize;
  3471. ULONG64 PoolTableAddress;
  3472. UCHAR FastTag[4];
  3473. ULONG TagLength;
  3474. ULONG SizeOfBigPages;
  3475. ULONG PoolTypeFlags = Flags & 0x7;
  3476. ULONG Ulong1;
  3477. ULONG HdrSize;
  3478. if (PoolInitializeGlobals() == FALSE) {
  3479. return;
  3480. }
  3481. if (PoolTypeFlags == 2) {
  3482. if (RestartAddr && (RestartAddr >= SpecialPoolStart) && (RestartAddr <= SpecialPoolEnd)) {
  3483. Pool = RestartAddr;
  3484. } else {
  3485. Pool = SpecialPoolStart;
  3486. }
  3487. dprintf("\nSearching special pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
  3488. Pool,
  3489. SpecialPoolEnd,
  3490. TagName,
  3491. TagName >> 8,
  3492. TagName >> 16,
  3493. TagName >> 24);
  3494. Found = FALSE;
  3495. SkipSize = PageSize;
  3496. if (SpecialPoolStart && SpecialPoolEnd) {
  3497. //
  3498. // Search special pool for the tag.
  3499. //
  3500. while (Pool < SpecialPoolEnd) {
  3501. if ( CheckControlC() ) {
  3502. dprintf("\n...terminating - searched pool to %p\n",
  3503. Pool);
  3504. return;
  3505. }
  3506. DataStartReal = Pool;
  3507. DataPageReal = Pool;
  3508. if ( !ReadMemory( Pool,
  3509. &DataPage[0],
  3510. min(PageSize, sizeof(DataPage)),
  3511. &Result) ) {
  3512. ULONG64 PteLong=0, PageFileHigh;
  3513. if (SkipSize != 2 * PageSize) {
  3514. // dprintf("SP skip %x", Pool);
  3515. PoolPteAddress = DbgGetPteAddress (Pool);
  3516. if (!GetFieldValue(PoolPteAddress,
  3517. "nt!_MMPTE",
  3518. "u.Soft.PageFileHigh",
  3519. PageFileHigh) ) {
  3520. if ((PageFileHigh == 0) ||
  3521. (PageFileHigh == MI_SPECIAL_POOL_PTE_PAGABLE) ||
  3522. (PageFileHigh == MI_SPECIAL_POOL_PTE_NONPAGABLE)) {
  3523. //
  3524. // Found a NO ACCESS PTE - skip these from
  3525. // here on to speed up the search.
  3526. //
  3527. // dprintf("SP skip double %p", PoolPteAddress);
  3528. SkipSize = 2 * PageSize;
  3529. Pool += PageSize;
  3530. // dprintf("SP skip final %p", Pool);
  3531. continue;
  3532. }
  3533. }
  3534. }
  3535. Pool += SkipSize;
  3536. continue;
  3537. }
  3538. //
  3539. // Determine whether this is a valid special pool block.
  3540. //
  3541. PoolHeader = GetSpecialPoolHeader (DataPage,
  3542. DataPageReal,
  3543. &DataStartReal);
  3544. if (PoolHeader != 0) {
  3545. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolTag", PoolTag);
  3546. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", Ulong1);
  3547. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(Ulong1);
  3548. Found = Filter( (PCHAR)&PoolTag,
  3549. (PCHAR)&TagName,
  3550. Flags,
  3551. PoolHeader,
  3552. PoolBlockSize,
  3553. DataStartReal,
  3554. Context );
  3555. } else {
  3556. dprintf( "No pool header for page: 0x%p\n", Pool );
  3557. }
  3558. Pool += SkipSize;
  3559. }
  3560. }
  3561. if (Found == FALSE) {
  3562. dprintf("The %c%c%c%c tag could not be found in special pool.\n",
  3563. #define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
  3564. PP(TagName),
  3565. PP(TagName >> 8),
  3566. PP(TagName >> 16),
  3567. PP(TagName >> 24)
  3568. );
  3569. #undef PP
  3570. }
  3571. return;
  3572. }
  3573. if (PoolTypeFlags == 0) {
  3574. PhysicallyContiguous = TRUE;
  3575. } else {
  3576. PhysicallyContiguous = FALSE;
  3577. }
  3578. __try {
  3579. TwoPools = FALSE;
  3580. if (((PoolTypeFlags & 0x4)== 0) || (BuildNo <= 2600)) {
  3581. PoolBigTableAddress = GetPointerValue ("nt!PoolBigPageTable");
  3582. PoolBigPageTableSize = GetUlongValue ("nt!PoolBigPageTableSize");
  3583. }
  3584. else {
  3585. PoolBigTableAddress = GetPointerValue ("ExpSessionPoolBigPageTable");
  3586. PoolBigPageTableSize = GetUlongValue ("ExpSessionPoolBigPageTableSize");
  3587. }
  3588. PoolTableAddress = PoolBigTableAddress;
  3589. if (PoolTableAddress) {
  3590. ULONG VaOffset;
  3591. ULONG NumPagesOffset;
  3592. ULONG PtrSize;
  3593. ULONG KeyOffset;
  3594. //
  3595. // Scan the table looking for a match. We read close to a page at a time
  3596. // physical page / sizeof ( pool_tracker_big_page ) * sizeof ( pool_tracker_big_page )
  3597. // on x86 this works out to ffc
  3598. //
  3599. i = 0;
  3600. SizeOfBigPages = GetTypeSize ("nt!_POOL_TRACKER_BIG_PAGES");
  3601. if (!SizeOfBigPages) {
  3602. dprintf("Cannot get _POOL_TRACKER_BIG_PAGES type size\n");
  3603. __leave;
  3604. }
  3605. ct = PageSize / SizeOfBigPages;
  3606. dprintf( "\nScanning large pool allocation table for Tag: %c%c%c%c (%p : %p)\n\n\r",
  3607. TagName,
  3608. TagName >> 8,
  3609. TagName >> 16,
  3610. TagName >> 24,
  3611. PoolBigTableAddress,
  3612. PoolBigTableAddress + PoolBigPageTableSize * SizeOfBigPages );
  3613. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Va", &VaOffset );
  3614. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "NumberOfPages", &NumPagesOffset );
  3615. GetFieldOffset( "nt!_POOL_TRACKER_BIG_PAGES", "Key", &KeyOffset );
  3616. PtrSize = IsPtr64() ? 8 : 4;
  3617. while (i < PoolBigPageTableSize) {
  3618. if (PoolBigPageTableSize - i < ct) {
  3619. ct = PoolBigPageTableSize - i;
  3620. }
  3621. if ( !ReadMemory( PoolTableAddress,
  3622. &DataPage[0],
  3623. min(ct * SizeOfBigPages, sizeof(DataPage)),
  3624. &Result) ) {
  3625. dprintf( "%08lx: Unable to get contents of big pool block\r\n", PoolTableAddress );
  3626. break;
  3627. }
  3628. for (j = 0; j < ct; j += 1) {
  3629. ULONG64 Va = 0;
  3630. memcpy( &Va, (PCHAR)DataPage + (SizeOfBigPages * j) + VaOffset, PtrSize );
  3631. Filter( ((PCHAR)DataPage + (SizeOfBigPages * j) + KeyOffset),
  3632. (PCHAR)&TagName,
  3633. Flags | 0x8, // To assist filter routine to recognize this as large pool
  3634. PoolTableAddress + SizeOfBigPages * j,
  3635. (ULONG64)(*((PULONG)((PCHAR)DataPage + (SizeOfBigPages * j) + NumPagesOffset))) * PageSize,
  3636. Va,
  3637. Context );
  3638. if ( CheckControlC() ) {
  3639. dprintf("\n...terminating - searched pool to %p\n",
  3640. PoolTableAddress + j * SizeOfBigPages);
  3641. __leave;
  3642. }
  3643. }
  3644. i += ct;
  3645. PoolTableAddress += (ct * SizeOfBigPages);
  3646. if ( CheckControlC() ) {
  3647. dprintf("\n...terminating - searched pool to %p\n",
  3648. PoolTableAddress);
  3649. __leave;
  3650. }
  3651. }
  3652. } else {
  3653. dprintf("unable to get large pool allocation table - either wrong symbols or pool tagging is disabled\n");
  3654. }
  3655. if (PoolTypeFlags == 0) {
  3656. PoolStart = GetNtDebuggerDataPtrValue( MmNonPagedPoolStart );
  3657. if (0 == PoolStart) {
  3658. dprintf( "Unable to get MmNonPagedPoolStart\n" );
  3659. }
  3660. PoolEnd =
  3661. PoolStart + GetNtDebuggerDataPtrValue( MmMaximumNonPagedPoolInBytes );
  3662. ExpandedPoolEnd = GetNtDebuggerDataPtrValue( MmNonPagedPoolEnd );
  3663. if (PoolEnd != ExpandedPoolEnd) {
  3664. InitialPoolSize = (ULONG)GetUlongValue( "MmSizeOfNonPagedPoolInBytes" );
  3665. PoolEnd = PoolStart + InitialPoolSize;
  3666. ExpandedPoolStart = GetPointerValue( "MmNonPagedPoolExpansionStart" );
  3667. TwoPools = TRUE;
  3668. }
  3669. for (TagLength = 0;TagLength < 3; TagLength++) {
  3670. if ((*(((PCHAR)&TagName)+TagLength) == '?') ||
  3671. (*(((PCHAR)&TagName)+TagLength) == '*')) {
  3672. break;
  3673. }
  3674. FastTag[TagLength] = *(((PCHAR)&TagName)+TagLength);
  3675. }
  3676. } else if (PoolTypeFlags == 1) {
  3677. PoolStart = GetNtDebuggerDataPtrValue( MmPagedPoolStart );
  3678. PoolEnd =
  3679. PoolStart + GetNtDebuggerDataPtrValue( MmSizeOfPagedPoolInBytes );
  3680. } else {
  3681. Location = GetExpression ("MiSessionPoolStart");
  3682. if (!Location) {
  3683. dprintf("Unable to get MiSessionPoolStart\n");
  3684. __leave;
  3685. }
  3686. ReadPointer(Location, &PoolStart);
  3687. Location = GetExpression ("MiSessionPoolEnd");
  3688. if (!Location) {
  3689. dprintf("Unable to get MiSessionPoolEnd\n");
  3690. __leave;
  3691. }
  3692. ReadPointer(Location, &PoolEnd);
  3693. }
  3694. if (RestartAddr) {
  3695. PoolStart = RestartAddr;
  3696. if (TwoPools == TRUE) {
  3697. if (PoolStart > PoolEnd) {
  3698. TwoPools = FALSE;
  3699. PoolStart = RestartAddr;
  3700. PoolEnd = ExpandedPoolEnd;
  3701. }
  3702. }
  3703. }
  3704. dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\r\n\n",
  3705. (PoolTypeFlags == 0) ? "NonPaged" : PoolTypeFlags == 1 ? "Paged": "SessionPaged",
  3706. PoolStart,
  3707. PoolEnd,
  3708. TagName,
  3709. TagName >> 8,
  3710. TagName >> 16,
  3711. TagName >> 24);
  3712. PoolPage = PoolStart;
  3713. HdrSize = GetTypeSize("nt!_POOL_HEADER");
  3714. while (PoolPage < PoolEnd) {
  3715. //
  3716. // Optimize things by ioctl'ing over to the other side to
  3717. // do a fast search and start with that page.
  3718. //
  3719. if ((PoolTypeFlags == 0) &&
  3720. PhysicallyContiguous &&
  3721. (TagLength > 0)) {
  3722. SEARCHMEMORY Search;
  3723. Search.SearchAddress = PoolPage;
  3724. Search.SearchLength = PoolEnd-PoolPage;
  3725. Search.PatternLength = TagLength;
  3726. Search.Pattern = FastTag;
  3727. Search.FoundAddress = 0;
  3728. if ((Ioctl(IG_SEARCH_MEMORY, &Search, sizeof(Search))) &&
  3729. (Search.FoundAddress != 0)) {
  3730. //
  3731. // Got a hit, search the whole page
  3732. //
  3733. PoolPage = PAGE_ALIGN64(Search.FoundAddress);
  3734. } else {
  3735. //
  3736. // The tag was not found at all, so we can just skip
  3737. // this chunk entirely.
  3738. //
  3739. PoolPage = PoolEnd;
  3740. goto skiprange;
  3741. }
  3742. }
  3743. Pool = PAGE_ALIGN64 (PoolPage);
  3744. StartPage = Pool;
  3745. Previous = 0;
  3746. while (PAGE_ALIGN64(Pool) == StartPage) {
  3747. ULONG HdrPoolTag, BlockSize, PreviousSize, AllocatorBackTraceIndex, PoolTagHash;
  3748. ULONG PoolType;
  3749. if ( GetFieldValue(Pool,
  3750. "nt!_POOL_HEADER",
  3751. "PoolTag",
  3752. HdrPoolTag) ) {
  3753. PoolPage = GetNextResidentAddress (Pool, PoolEnd);
  3754. //
  3755. // If we're half resident - half non-res then we'll get back
  3756. // that are starting address is the next resident page. In that
  3757. // case just go on to the next page
  3758. //
  3759. if (PoolPage == Pool) {
  3760. PoolPage = PoolPage + PageSize;
  3761. }
  3762. goto nextpage;
  3763. }
  3764. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTag",HdrPoolTag);
  3765. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolType", PoolType);
  3766. GetFieldValue(Pool,"nt!_POOL_HEADER","BlockSize",BlockSize);
  3767. GetFieldValue(Pool,"nt!_POOL_HEADER","PoolTagHash",PoolTagHash);
  3768. GetFieldValue(Pool,"nt!_POOL_HEADER","PreviousSize",PreviousSize);
  3769. GetFieldValue(Pool,"nt!_POOL_HEADER","AllocatorBackTraceIndex",AllocatorBackTraceIndex);
  3770. if ((BlockSize << POOL_BLOCK_SHIFT) > POOL_PAGE_SIZE) {
  3771. //dprintf("Bad allocation size @%lx, too large\n", Pool);
  3772. break;
  3773. }
  3774. if (BlockSize == 0) {
  3775. //dprintf("Bad allocation size @%lx, zero is invalid\n", Pool);
  3776. break;
  3777. }
  3778. if (PreviousSize != Previous) {
  3779. //dprintf("Bad previous allocation size @%lx, last size was %lx\n",Pool, Previous);
  3780. break;
  3781. }
  3782. PoolTag = HdrPoolTag;
  3783. Filter((PCHAR)&PoolTag,
  3784. (PCHAR)&TagName,
  3785. Flags,
  3786. Pool,
  3787. (ULONG64)BlockSize << POOL_BLOCK_SHIFT,
  3788. Pool + HdrSize,
  3789. Context );
  3790. Previous = BlockSize;
  3791. Pool += ((ULONG64) Previous << POOL_BLOCK_SHIFT);
  3792. if ( CheckControlC() ) {
  3793. dprintf("\n...terminating - searched pool to %p\n",
  3794. PoolPage);
  3795. __leave;
  3796. }
  3797. }
  3798. PoolPage = (PoolPage + PageSize);
  3799. nextpage:
  3800. if ( CheckControlC() ) {
  3801. dprintf("\n...terminating - searched pool to %p\n",
  3802. PoolPage);
  3803. __leave;
  3804. }
  3805. skiprange:
  3806. if (TwoPools == TRUE) {
  3807. if (PoolPage == PoolEnd) {
  3808. TwoPools = FALSE;
  3809. PoolStart = ExpandedPoolStart;
  3810. PoolEnd = ExpandedPoolEnd;
  3811. PoolPage = PoolStart;
  3812. PhysicallyContiguous = FALSE;
  3813. dprintf("\nSearching %s pool (%p : %p) for Tag: %c%c%c%c\n\n",
  3814. "NonPaged",
  3815. PoolStart,
  3816. PoolEnd,
  3817. TagName,
  3818. TagName >> 8,
  3819. TagName >> 16,
  3820. TagName >> 24);
  3821. }
  3822. }
  3823. }
  3824. } __finally {
  3825. }
  3826. return;
  3827. } // SearchPool
  3828. DECLARE_API( poolfind )
  3829. /*++
  3830. Routine Description:
  3831. flags == 0 means finds a tag in nonpaged pool.
  3832. flags == 1 means finds a tag in paged pool.
  3833. flags == 2 means finds a tag in special pool.
  3834. flags == 4 means finds a tag in session pool.
  3835. Arguments:
  3836. args -
  3837. Return Value:
  3838. None
  3839. --*/
  3840. {
  3841. ULONG Flags;
  3842. CHAR TagNameX[4] = {' ',' ',' ',' '};
  3843. ULONG TagName;
  3844. ULONG64 PoolTrackTable;
  3845. Flags = 0;
  3846. if (!sscanf(args,"%c%c%c%c %lx", &TagNameX[0],
  3847. &TagNameX[1], &TagNameX[2], &TagNameX[3], &Flags)) {
  3848. Flags = 0;
  3849. }
  3850. if (TagNameX[0] == '0' && TagNameX[1] == 'x') {
  3851. if (!sscanf( args, "%lx %lx", &TagName, &Flags )) {
  3852. TagName = 0;
  3853. }
  3854. } else {
  3855. TagName = TagNameX[0] | (TagNameX[1] << 8) | (TagNameX[2] << 16) | (TagNameX[3] << 24);
  3856. }
  3857. PoolTrackTable = GetNtDebuggerDataPtrValue( PoolTrackTable );
  3858. if (PoolTrackTable == 0) {
  3859. dprintf ("unable to get PoolTrackTable - probably pool tagging disabled or wrong symbols\n");
  3860. }
  3861. SearchPool( TagName, Flags, 0, CheckSingleFilterAndPrint, NULL );
  3862. return S_OK;
  3863. }
  3864. BOOLEAN
  3865. CheckSingleFilter (
  3866. PCHAR Tag,
  3867. PCHAR Filter
  3868. )
  3869. {
  3870. ULONG i;
  3871. UCHAR tc;
  3872. UCHAR fc;
  3873. for ( i = 0; i < 4; i++ ) {
  3874. tc = (UCHAR) *Tag++;
  3875. fc = (UCHAR) *Filter++;
  3876. if ( fc == '*' ) return TRUE;
  3877. if ( fc == '?' ) continue;
  3878. if (i == 3 && (tc & ~(PROTECTED_POOL >> 24)) == fc) continue;
  3879. if ( tc != fc ) return FALSE;
  3880. }
  3881. return TRUE;
  3882. }
  3883. ULONG64
  3884. GetSpecialPoolHeader (
  3885. IN PVOID pDataPage,
  3886. IN ULONG64 RealDataPage,
  3887. OUT PULONG64 ReturnedDataStart
  3888. )
  3889. /*++
  3890. Routine Description:
  3891. Examine a page of data to determine if it is a special pool block.
  3892. Arguments:
  3893. pDataPage - Supplies a pointer to a page of data to examine.
  3894. ReturnedDataStart - Supplies a pointer to return the start of the data.
  3895. Only valid if this routine returns non-NULL.
  3896. Return Value:
  3897. Returns a pointer to the pool header for this special pool block or
  3898. NULL if the block is not valid special pool.
  3899. --*/
  3900. {
  3901. ULONG PoolBlockSize;
  3902. ULONG PoolHeaderSize;
  3903. ULONG PoolBlockPattern;
  3904. PUCHAR p;
  3905. PUCHAR PoolDataEnd;
  3906. PUCHAR DataStart;
  3907. ULONG64 PoolHeader;
  3908. ULONG HdrUlong1;
  3909. PoolHeader = RealDataPage;
  3910. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  3911. //
  3912. // Determine whether the data is at the start or end of the page.
  3913. // Start off by assuming the data is at the end, in this case the
  3914. // header will be at the start.
  3915. //
  3916. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
  3917. if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
  3918. PoolHeaderSize = POOL_OVERHEAD;
  3919. if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
  3920. PoolHeaderSize += GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
  3921. }
  3922. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
  3923. DataStart = (PUCHAR)pDataPage + PageSize - PoolBlockSize;
  3924. p = (PUCHAR)pDataPage + PoolHeaderSize;
  3925. for ( ; p < DataStart; p += 1) {
  3926. if (*p != PoolBlockPattern) {
  3927. break;
  3928. }
  3929. }
  3930. if (p == DataStart || p >= (PUCHAR)pDataPage + PoolHeaderSize + 0x10) {
  3931. //
  3932. // For this page, the data is at the end of the block.
  3933. // The 0x10 is just to give corrupt blocks some slack.
  3934. // All pool allocations are quadword aligned.
  3935. //
  3936. DataStart = (PUCHAR)pDataPage + ((PageSize - PoolBlockSize) & ~(sizeof(QUAD)-1));
  3937. *ReturnedDataStart = RealDataPage + (ULONG64) ((PUCHAR) DataStart - (PUCHAR) pDataPage);
  3938. return PoolHeader;
  3939. }
  3940. //
  3941. // The data must be at the front or the block is corrupt.
  3942. //
  3943. }
  3944. //
  3945. // Try for the data at the front. Checks are necessary as
  3946. // the page could be corrupt on both ends.
  3947. //
  3948. PoolHeader = (RealDataPage + PageSize - POOL_OVERHEAD);
  3949. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "Ulong1", HdrUlong1);
  3950. PoolBlockSize = SPECIAL_POOL_BLOCK_SIZE(HdrUlong1);
  3951. if ((PoolBlockSize != 0) && (PoolBlockSize < PageSize - POOL_OVERHEAD)) {
  3952. PoolDataEnd = (PUCHAR)PoolHeader;
  3953. if (HdrUlong1 & MI_SPECIAL_POOL_VERIFIER) {
  3954. PoolDataEnd -= GetTypeSize ("nt!_MI_VERIFIER_POOL_HEADER");
  3955. }
  3956. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockPattern);
  3957. DataStart = (PUCHAR)pDataPage;
  3958. p = DataStart + PoolBlockSize;
  3959. for ( ; p < PoolDataEnd; p += 1) {
  3960. if (*p != PoolBlockPattern) {
  3961. break;
  3962. }
  3963. }
  3964. if (p == (PUCHAR)PoolDataEnd || p > (PUCHAR)pDataPage + PoolBlockSize + 0x10) {
  3965. //
  3966. // For this page, the data is at the front of the block.
  3967. // The 0x10 is just to give corrupt blocks some slack.
  3968. // All pool allocations are quadword aligned.
  3969. //
  3970. *ReturnedDataStart = RealDataPage + (ULONG64)( (PUCHAR)DataStart - (PUCHAR) pDataPage);
  3971. return PoolHeader;
  3972. }
  3973. }
  3974. //
  3975. // Not valid special pool.
  3976. //
  3977. return 0;
  3978. }
  3979. #define BYTE(u,n) ((u & (0xff << 8*n)) >> 8*n)
  3980. #define LOCHAR_BYTE(u,n) (tolower(BYTE(u,n)) & 0xff)
  3981. #define REVERSE_ULONGBYTES(u) (LOCHAR_BYTE(u,3) | (LOCHAR_BYTE(u,2) << 8) | (LOCHAR_BYTE(u,1) << 16) | (LOCHAR_BYTE(u,0) << 24))
  3982. EXTENSION_API ( GetPoolRegion )(
  3983. PDEBUG_CLIENT Client,
  3984. ULONG64 Pool,
  3985. DEBUG_POOL_REGION *PoolData
  3986. )
  3987. {
  3988. INIT_API();
  3989. *PoolData = GetPoolRegion(Pool);
  3990. EXIT_API();
  3991. return S_OK;
  3992. }
  3993. EXTENSION_API ( GetPoolData )(
  3994. PDEBUG_CLIENT Client,
  3995. ULONG64 Pool,
  3996. PDEBUG_POOL_DATA PoolData
  3997. )
  3998. {
  3999. PCHAR Desc;
  4000. HRESULT Hr;
  4001. PGET_POOL_TAG_DESCRIPTION GetPoolTagDescription;
  4002. INIT_API();
  4003. if (!PoolInitializeGlobals()) {
  4004. EXIT_API();
  4005. return E_INVALIDARG;
  4006. }
  4007. Hr = ListPoolPage(Pool, 0x80000002, PoolData);
  4008. if (Hr != S_OK) {
  4009. EXIT_API();
  4010. return Hr;
  4011. }
  4012. GetPoolTagDescription = NULL;
  4013. #ifndef _EXTFNS_H
  4014. if (!GetExtensionFunction("GetPoolTagDescription", (FARPROC*) &GetPoolTagDescription)) {
  4015. EXIT_API();
  4016. return E_INVALIDARG;
  4017. }
  4018. (*GetPoolTagDescription)(PoolData->PoolTag, &Desc);
  4019. if (Desc) {
  4020. ULONG strsize = strlen(Desc);
  4021. if (strsize > sizeof(PoolData->PoolTagDescription)) {
  4022. strsize = sizeof(PoolData->PoolTagDescription);
  4023. }
  4024. strncpy(PoolData->PoolTagDescription, Desc, strsize);
  4025. PoolData->PoolTagDescription[strsize] = 0;
  4026. }
  4027. #endif
  4028. EXIT_API();
  4029. return Hr;
  4030. }