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.

4522 lines
129 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. session.cxx
  5. Abstract:
  6. This file contains the routines to handle session.
  7. Author:
  8. Jason Hartman (JasonHa) 2000-09-28
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "precomp.h"
  13. #define STRSAFE_NO_DEPRECATE
  14. #include "strsafe.h"
  15. //
  16. // Special defines
  17. //
  18. // ddk\inc\ntddk.h:
  19. #define PROTECTED_POOL 0x80000000
  20. // base\ntos\inc\pool.h:
  21. #define POOL_QUOTA_MASK 8
  22. // Information about how to handle a process listing
  23. // and status about how it was handled.
  24. class CProcessListing
  25. {
  26. public:
  27. IN ULONG m_cListLimit;
  28. IN OUT ULONG m_cTotal;
  29. IN OUT ULONG m_cProcessed;
  30. IN OUT ULONG64 m_oStartProcess;
  31. OUT ULONG64 m_oLastProcess;
  32. public:
  33. CProcessListing(ULONG cListLimit = -1) {
  34. m_cListLimit = cListLimit;
  35. m_cTotal = 0;
  36. m_cProcessed = 0;
  37. m_oStartProcess = 0;
  38. m_oLastProcess = 0;
  39. }
  40. void PrepareForNextListing()
  41. {
  42. m_oStartProcess = m_oLastProcess;
  43. }
  44. BOOL Unprocessed()
  45. {
  46. return (m_cTotal > m_cProcessed);
  47. }
  48. };
  49. #define SESSION_SEARCH_LIMIT 50
  50. ULONG SessionId = CURRENT_SESSION;
  51. CHAR SessionStr[16] = "CURRENT";
  52. CachedType HwPte = { FALSE, "NT!HARDWARE_PTE", 0, 0, 0 };
  53. #define NUM_CACHED_SESSIONS 8
  54. struct {
  55. BOOL Valid;
  56. ULONG64 SessionSpaceAddr;
  57. ULONG64 SessionProcess;
  58. } CachedSession[NUM_CACHED_SESSIONS+1] = { { 0, 0 } };
  59. ULONG ExtraCachedSessionId;
  60. #define NUM_CACHED_DIR_BASES 8
  61. struct {
  62. BOOL Valid;
  63. ULONG64 PageDirBase;
  64. } CachedDirBase[NUM_CACHED_DIR_BASES+1] = { { FALSE, 0} };
  65. struct {
  66. BOOL Valid;
  67. ULONG64 PhysAddr;
  68. ULONG64 Data;
  69. } CachedPhysAddr[2] = { { 0, 0, 0} };
  70. class BitFieldInfo {
  71. public:
  72. BitFieldInfo() { Valid = FALSE; };
  73. BitFieldInfo(ULONG InitBitPos, ULONG InitBits) {
  74. Valid = Compose(InitBitPos, InitBits);
  75. }
  76. BOOL Compose(ULONG CBitPos, ULONG CBits)
  77. {
  78. BitPos = CBitPos;
  79. Bits = CBits;
  80. Mask = (((((ULONG64) 1) << Bits) - 1) << BitPos);
  81. return TRUE;
  82. }
  83. BOOL Valid;
  84. ULONG BitPos;
  85. ULONG Bits;
  86. ULONG64 Mask;
  87. };
  88. BitFieldInfo *MMPTEValid = NULL;
  89. BitFieldInfo *MMPTEProto = NULL;
  90. BitFieldInfo *MMPTETrans = NULL;
  91. BitFieldInfo *MMPTEX86LargePage = NULL;
  92. BitFieldInfo *MMPTEpfn = NULL;
  93. HRESULT
  94. GetBitMap(
  95. PDEBUG_CLIENT Client,
  96. ULONG64 pBitMap,
  97. PRTL_BITMAP *pBitMapOut
  98. );
  99. HRESULT
  100. FreeBitMap(
  101. PRTL_BITMAP pBitMap
  102. );
  103. HRESULT
  104. OutputSessionProcesses(
  105. PDEBUG_CLIENT Client,
  106. ULONG Session,
  107. PCSTR args,
  108. CProcessListing *pProcessListing
  109. );
  110. /**************************************************************************\
  111. *
  112. * Routine Name:
  113. *
  114. * SessionInit
  115. *
  116. * Routine Description:
  117. *
  118. * Initialize or reinitialize information to be read from symbols files
  119. *
  120. * Arguments:
  121. *
  122. * Client - PDEBUG_CLIENT
  123. *
  124. * Return Value:
  125. *
  126. * none
  127. *
  128. \**************************************************************************/
  129. void SessionInit(PDEBUG_CLIENT Client)
  130. {
  131. for (int s = 0; s < sizeof(CachedSession)/sizeof(CachedSession[0]); s++)
  132. {
  133. CachedSession[s].Valid = FALSE;
  134. }
  135. ExtraCachedSessionId = INVALID_SESSION;
  136. for (int s = 0; s < sizeof(CachedDirBase)/sizeof(CachedDirBase[0]); s++)
  137. {
  138. CachedDirBase[s].Valid = INVALID_UNIQUE_STATE;
  139. }
  140. if (MMPTEValid != NULL) MMPTEValid->Valid = FALSE;
  141. if (MMPTEProto != NULL) MMPTEProto->Valid = FALSE;
  142. if (MMPTETrans != NULL) MMPTETrans->Valid = FALSE;
  143. if (MMPTEX86LargePage != NULL) MMPTEX86LargePage->Valid = FALSE;
  144. if (MMPTEpfn != NULL) MMPTEpfn->Valid = FALSE;
  145. CachedPhysAddr[0].Valid = FALSE;
  146. CachedPhysAddr[1].Valid = FALSE;
  147. return;
  148. }
  149. /**************************************************************************\
  150. *
  151. * Routine Name:
  152. *
  153. * SessionExit
  154. *
  155. * Routine Description:
  156. *
  157. * Clean up any outstanding allocations or references
  158. *
  159. * Arguments:
  160. *
  161. * none
  162. *
  163. * Return Value:
  164. *
  165. * none
  166. *
  167. \**************************************************************************/
  168. void SessionExit()
  169. {
  170. if (MMPTEValid != NULL)
  171. {
  172. delete MMPTEValid;
  173. MMPTEValid = NULL;
  174. }
  175. if (MMPTEProto != NULL)
  176. {
  177. delete MMPTEProto;
  178. MMPTEProto = NULL;
  179. }
  180. if (MMPTETrans != NULL)
  181. {
  182. delete MMPTETrans;
  183. MMPTETrans = NULL;
  184. }
  185. if (MMPTEX86LargePage != NULL)
  186. {
  187. delete MMPTEX86LargePage;
  188. MMPTEX86LargePage = NULL;
  189. }
  190. if (MMPTEpfn != NULL)
  191. {
  192. delete MMPTEpfn;
  193. MMPTEpfn = NULL;
  194. }
  195. return;
  196. }
  197. #if 0
  198. /**************************************************************************\
  199. *
  200. * Routine Name:
  201. *
  202. * GetMMPTEValid
  203. *
  204. * Routine Description:
  205. *
  206. * Extract Valid value from MMPTE
  207. *
  208. \**************************************************************************/
  209. HRESULT
  210. GetMMPTEValid(
  211. PDEBUG_CLIENT Client,
  212. ULONG64 MMPTE64,
  213. PULONG64 Valid
  214. )
  215. {
  216. HRESULT hr = S_FALSE;
  217. if (MMPTEValid == NULL)
  218. {
  219. MMPTEValid = new BitFieldInfo;
  220. }
  221. if (MMPTEValid == NULL)
  222. {
  223. hr = E_OUTOFMEMORY;
  224. }
  225. else if (MMPTEValid->Valid)
  226. {
  227. hr = S_OK;
  228. }
  229. else
  230. {
  231. ULONG VaildOffset, ValidBits;
  232. if (GetBitFieldOffset("nt!HARDWARE_PTE", "Valid", &VaildOffset, &ValidBits) == S_OK)
  233. {
  234. MMPTEValid->Valid = MMPTEValid->Compose(VaildOffset, ValidBits);
  235. hr = MMPTEValid->Valid ? S_OK : S_FALSE;
  236. }
  237. }
  238. if (Valid != NULL)
  239. {
  240. if (hr == S_OK)
  241. {
  242. *Valid = (MMPTE64 & MMPTEValid->Mask) >> MMPTEValid->BitPos;
  243. }
  244. else
  245. {
  246. *Valid = 0;
  247. }
  248. }
  249. return hr;
  250. }
  251. /**************************************************************************\
  252. *
  253. * Routine Name:
  254. *
  255. * GetMMPTEProto
  256. *
  257. * Routine Description:
  258. *
  259. * Extract Prototype value from MMPTE
  260. *
  261. \**************************************************************************/
  262. HRESULT
  263. GetMMPTEProto(
  264. PDEBUG_CLIENT Client,
  265. ULONG64 MMPTE64,
  266. PULONG64 Proto
  267. )
  268. {
  269. HRESULT hr = S_FALSE;
  270. if (MMPTEProto == NULL)
  271. {
  272. MMPTEProto = new BitFieldInfo;
  273. }
  274. if (MMPTEProto == NULL)
  275. {
  276. hr = E_OUTOFMEMORY;
  277. }
  278. else if (MMPTEProto->Valid)
  279. {
  280. hr = S_OK;
  281. }
  282. else
  283. {
  284. ULONG ProtoOffset, ProtoBits;
  285. if (GetBitFieldOffset("nt!MMPTE_PROTOTYPE", "Prototype", &ProtoOffset, &ProtoBits) == S_OK)
  286. {
  287. MMPTEProto->Valid = MMPTEProto->Compose(ProtoOffset, ProtoBits);
  288. hr = MMPTEProto->Valid ? S_OK : S_FALSE;
  289. }
  290. }
  291. if (Proto != NULL)
  292. {
  293. if (hr == S_OK)
  294. {
  295. *Proto = (MMPTE64 & MMPTEProto->Mask) >> MMPTEProto->BitPos;
  296. }
  297. else
  298. {
  299. *Proto = 0;
  300. }
  301. }
  302. return hr;
  303. }
  304. /**************************************************************************\
  305. *
  306. * Routine Name:
  307. *
  308. * GetMMPTETrans
  309. *
  310. * Routine Description:
  311. *
  312. * Extract Transition value from MMPTE
  313. *
  314. \**************************************************************************/
  315. HRESULT
  316. GetMMPTETrans(
  317. PDEBUG_CLIENT Client,
  318. ULONG64 MMPTE64,
  319. PULONG64 Trans
  320. )
  321. {
  322. HRESULT hr = S_FALSE;
  323. if (MMPTETrans == NULL)
  324. {
  325. MMPTETrans = new BitFieldInfo;
  326. }
  327. if (MMPTETrans == NULL)
  328. {
  329. hr = E_OUTOFMEMORY;
  330. }
  331. else if (MMPTETrans->Valid)
  332. {
  333. hr = S_OK;
  334. }
  335. else
  336. {
  337. ULONG TransOffset, TransBits;
  338. if (GetBitFieldOffset("nt!MMPTE_PROTOTYPE", "Transition", &TransOffset, &TransBits) == S_OK)
  339. {
  340. MMPTETrans->Valid = MMPTETrans->Compose(TransOffset, TransBits);
  341. hr = MMPTETrans->Valid ? S_OK : S_FALSE;
  342. }
  343. }
  344. if (Trans != NULL)
  345. {
  346. if (hr == S_OK)
  347. {
  348. *Trans = (MMPTE64 & MMPTETrans->Mask) >> MMPTETrans->BitPos;
  349. }
  350. else
  351. {
  352. *Trans = 0;
  353. }
  354. }
  355. return hr;
  356. }
  357. /**************************************************************************\
  358. *
  359. * Routine Name:
  360. *
  361. * GetMMPTEX86LargePage
  362. *
  363. * Routine Description:
  364. *
  365. * Extract LargePage value from X86 MMPTE
  366. *
  367. \**************************************************************************/
  368. HRESULT
  369. GetMMPTEX86LargePage(
  370. PDEBUG_CLIENT Client,
  371. ULONG64 MMPTE64,
  372. PULONG64 X86LargePage
  373. )
  374. {
  375. HRESULT hr = S_FALSE;
  376. if (TargetMachine != IMAGE_FILE_MACHINE_I386)
  377. {
  378. if (X86LargePage != NULL) *X86LargePage = 0;
  379. return hr;
  380. }
  381. if (MMPTEX86LargePage == NULL)
  382. {
  383. MMPTEX86LargePage = new BitFieldInfo;
  384. }
  385. if (MMPTEX86LargePage == NULL)
  386. {
  387. hr = E_OUTOFMEMORY;
  388. }
  389. else if (MMPTEX86LargePage->Valid)
  390. {
  391. hr = S_OK;
  392. }
  393. else
  394. {
  395. ULONG LrPgOffset, LrPgBits;
  396. if (GetBitFieldOffset("nt!HARDWARE_PTE", "LargePage", &LrPgOffset, &LrPgBits) == S_OK)
  397. {
  398. MMPTEX86LargePage->Valid = MMPTEX86LargePage->Compose(LrPgOffset, LrPgBits);
  399. hr = MMPTEX86LargePage->Valid ? S_OK : S_FALSE;
  400. }
  401. }
  402. if (X86LargePage != NULL)
  403. {
  404. if (hr == S_OK)
  405. {
  406. *X86LargePage = (MMPTE64 & MMPTEX86LargePage->Mask) >> MMPTEX86LargePage->BitPos;
  407. }
  408. else
  409. {
  410. *X86LargePage = 0;
  411. }
  412. }
  413. return hr;
  414. }
  415. /**************************************************************************\
  416. *
  417. * Routine Name:
  418. *
  419. * GetMMPTEpfn
  420. *
  421. * Routine Description:
  422. *
  423. * Extract Page Frame Number value from MMPTE
  424. *
  425. \**************************************************************************/
  426. #define GET_BITS_UNSHIFTED 1
  427. HRESULT
  428. GetMMPTEpfn(
  429. PDEBUG_CLIENT Client,
  430. ULONG64 MMPTE64,
  431. PULONG64 pfn,
  432. FLONG Flags
  433. )
  434. {
  435. HRESULT hr = S_FALSE;
  436. if (MMPTEpfn == NULL)
  437. {
  438. MMPTEpfn = new BitFieldInfo;
  439. }
  440. if (MMPTEpfn == NULL)
  441. {
  442. hr = E_OUTOFMEMORY;
  443. }
  444. else if (MMPTEpfn->Valid)
  445. {
  446. hr = S_OK;
  447. }
  448. else
  449. {
  450. ULONG pfnPosition, pfnBits;
  451. if (GetBitFieldOffset("nt!HARDWARE_PTE", "PageFrameNumber", &pfnPosition, &pfnBits) == S_OK)
  452. {
  453. MMPTEpfn->Valid = MMPTEpfn->Compose(pfnPosition, pfnBits);
  454. hr = MMPTEpfn->Valid ? S_OK : S_FALSE;
  455. }
  456. }
  457. if (pfn != NULL)
  458. {
  459. if (hr == S_OK)
  460. {
  461. *pfn = (MMPTE64 & MMPTEpfn->Mask);
  462. if (!(Flags & GET_BITS_UNSHIFTED))
  463. {
  464. *pfn >>= MMPTEpfn->BitPos;
  465. }
  466. }
  467. else
  468. {
  469. *pfn = 0;
  470. }
  471. }
  472. return hr;
  473. }
  474. #endif // 0
  475. // Copied from nt\base\ntos\rtl\bitmap.c
  476. static CONST ULONG FillMaskUlong[] = {
  477. 0x00000000, 0x00000001, 0x00000003, 0x00000007,
  478. 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
  479. 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
  480. 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
  481. 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
  482. 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
  483. 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
  484. 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
  485. 0xffffffff
  486. };
  487. ULONG
  488. OSCompat_RtlFindLastBackwardRunClear (
  489. IN PRTL_BITMAP BitMapHeader,
  490. IN ULONG FromIndex,
  491. IN PULONG StartingRunIndex
  492. )
  493. {
  494. ULONG Start;
  495. ULONG End;
  496. PULONG PHunk;
  497. ULONG Hunk;
  498. //
  499. // Take care of the boundary case of the null bitmap
  500. //
  501. if (BitMapHeader->SizeOfBitMap == 0) {
  502. *StartingRunIndex = FromIndex;
  503. return 0;
  504. }
  505. //
  506. // Scan backwards for the first clear bit
  507. //
  508. End = FromIndex;
  509. //
  510. // Build pointer to the ULONG word in the bitmap
  511. // containing the End bit, then read in the bitmap
  512. // hunk. Set the rest of the bits in this word, NOT
  513. // inclusive of the FromIndex bit.
  514. //
  515. PHunk = BitMapHeader->Buffer + (End / 32);
  516. Hunk = *PHunk | ~FillMaskUlong[(End % 32) + 1];
  517. //
  518. // If the first subword is set then we can proceed to
  519. // take big steps in the bitmap since we are now ULONG
  520. // aligned in the search
  521. //
  522. if (Hunk == (ULONG)~0) {
  523. //
  524. // Adjust the pointers backwards
  525. //
  526. End -= (End % 32) + 1;
  527. PHunk--;
  528. while ( PHunk > BitMapHeader->Buffer ) {
  529. //
  530. // Stop at first word with set bits
  531. //
  532. if (*PHunk != (ULONG)~0) break;
  533. PHunk--;
  534. End -= 32;
  535. }
  536. }
  537. //
  538. // Bitwise search backward for the clear bit
  539. //
  540. while ((End != MAXULONG) && (RtlCheckBit( BitMapHeader, End ) == 1)) { End -= 1; }
  541. //
  542. // Scan backwards for the first set bit
  543. //
  544. Start = End;
  545. //
  546. // We know that the clear bit was in the last word we looked at,
  547. // so continue from there to find the next set bit, clearing the
  548. // previous bits in the word.
  549. //
  550. Hunk = *PHunk & FillMaskUlong[Start % 32];
  551. //
  552. // If the subword is unset then we can proceed in big steps
  553. //
  554. if (Hunk == (ULONG)0) {
  555. //
  556. // Adjust the pointers backward
  557. //
  558. Start -= (Start % 32) + 1;
  559. PHunk--;
  560. while ( PHunk > BitMapHeader->Buffer ) {
  561. //
  562. // Stop at first word with set bits
  563. //
  564. if (*PHunk != (ULONG)0) break;
  565. PHunk--;
  566. Start -= 32;
  567. }
  568. }
  569. //
  570. // Bitwise search backward for the set bit
  571. //
  572. while ((Start != MAXULONG) && (RtlCheckBit( BitMapHeader, Start ) == 0)) { Start -= 1; }
  573. //
  574. // Compute the index and return the length
  575. //
  576. *StartingRunIndex = Start + 1;
  577. return (End - Start);
  578. }
  579. HRESULT
  580. GetSessionNumbers(
  581. IN PDEBUG_CLIENT Client,
  582. OUT PULONG CurrentSession,
  583. OUT PULONG DefaultSession,
  584. OUT PULONG TotalSessions,
  585. OUT PRTL_BITMAP *SessionList
  586. )
  587. {
  588. HRESULT hr = S_FALSE;
  589. if (CurrentSession != NULL)
  590. {
  591. ULONG Processor;
  592. ULONG64 Process=0;
  593. Process = GetExpression("@$Proc");
  594. if (!Process || !GetProcessSessionId(Process, CurrentSession))
  595. {
  596. *CurrentSession = INVALID_SESSION;
  597. } else
  598. {
  599. hr = S_OK;
  600. }
  601. }
  602. if (DefaultSession != NULL)
  603. {
  604. *DefaultSession = SessionId;
  605. hr = S_OK;
  606. }
  607. if ((TotalSessions != NULL) ||
  608. (SessionList != NULL))
  609. {
  610. ULONG SessionCount = 0;
  611. PRTL_BITMAP SessionListBitMap = NULL;
  612. ULONG64 SessionIdListPointerAddr = 0;
  613. ULONG64 SessionIdListAddr = 0;
  614. PDEBUG_SYMBOLS Symbols;
  615. PDEBUG_DATA_SPACES Data;
  616. if (TotalSessions)
  617. {
  618. *TotalSessions = 0;
  619. }
  620. if (SessionList)
  621. {
  622. *SessionList = NULL;
  623. }
  624. if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  625. (void **)&Symbols)) != S_OK)
  626. {
  627. return hr;
  628. }
  629. if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  630. (void **)&Data)) != S_OK)
  631. {
  632. Symbols->Release();
  633. return hr;
  634. }
  635. CHAR PointerName[] = "NT!MiSessionIdBitmap";
  636. hr = Symbols->GetOffsetByName(PointerName, &SessionIdListPointerAddr);
  637. if (hr != S_OK)
  638. {
  639. ExtErr("Unable to locate %s\n", PointerName);
  640. }
  641. else
  642. {
  643. hr = Data->ReadPointersVirtual(1, SessionIdListPointerAddr, &SessionIdListAddr);
  644. if ((hr == S_OK) && (SessionIdListAddr != 0))
  645. {
  646. hr = GetBitMap(Client, SessionIdListAddr, &SessionListBitMap);
  647. if (hr == S_OK)
  648. {
  649. SessionCount = RtlNumberOfSetBits(SessionListBitMap);
  650. }
  651. } else
  652. {
  653. ExtErr("Unable to read MiSessionIdBitmap @ %p\n", SessionIdListPointerAddr);
  654. }
  655. }
  656. if (TotalSessions)
  657. {
  658. *TotalSessions = SessionCount;
  659. }
  660. // Free or return BitMap
  661. if (SessionListBitMap)
  662. {
  663. if (SessionList)
  664. {
  665. *SessionList = SessionListBitMap;
  666. }
  667. else
  668. {
  669. FreeBitMap(SessionListBitMap);
  670. }
  671. }
  672. Data->Release();
  673. Symbols->Release();
  674. }
  675. return hr;
  676. }
  677. HRESULT
  678. SetDefaultSession(
  679. IN PDEBUG_CLIENT Client,
  680. IN ULONG NewSession,
  681. OUT OPTIONAL PULONG OldSession
  682. )
  683. {
  684. HRESULT hr = S_FALSE;
  685. ULONG64 SessionProcess;
  686. ULONG PrevSession;
  687. GetSessionNumbers(Client, NULL, &PrevSession, NULL, NULL);
  688. if (OldSession)
  689. {
  690. *OldSession = PrevSession;
  691. }
  692. if ((NewSession == CURRENT_SESSION) ||
  693. (GetSessionSpace(NewSession, NULL, &SessionProcess) == S_OK))
  694. {
  695. if (GetProcessSessionId(SessionProcess, &SessionId) &&
  696. (SessionId != PrevSession))
  697. {
  698. CHAR SetImplicitProcess[100];
  699. hr = StringCbPrintfA(SetImplicitProcess, sizeof(SetImplicitProcess),
  700. ".process %p", SessionProcess);
  701. if (hr == S_OK)
  702. {
  703. hr = g_ExtControl->Execute(DEBUG_OUTCTL_AMBIENT,
  704. SetImplicitProcess, DEBUG_EXECUTE_DEFAULT );
  705. }
  706. if (SessionId == CURRENT_SESSION)
  707. {
  708. strcpy(SessionStr, "CURRENT");
  709. }
  710. else
  711. {
  712. _ultoa(SessionId, SessionStr, 10);
  713. }
  714. }
  715. hr = S_OK;
  716. }
  717. return hr;
  718. }
  719. typedef (WINAPI* PENUM_SESSION_CB)(ULONG64 Process, ULONG SessionId, PVOID Context);
  720. BOOL
  721. EnumerateSessionProcesses(
  722. IN ULONG Session,
  723. IN PVOID Context,
  724. IN PENUM_SESSION_CB Callback
  725. )
  726. {
  727. ULONG TotalSessions;
  728. ULONG WsListEntryOffset;
  729. ULONG SessionOffset;
  730. ULONG SessionProcessLinksOffset;
  731. ULONG64 MiSessionWsList;
  732. ULONG64 SessionWsListStart;
  733. ULONG64 Next;
  734. ULONG64 SessionSpace;
  735. ULONG SessionId;
  736. MiSessionWsList = GetExpression("nt!MiSessionWsList");
  737. if (!MiSessionWsList || !ReadPointer(MiSessionWsList, &SessionWsListStart))
  738. {
  739. dprintf("Cannot get nt!MiSessionWsList\n");
  740. return FALSE;
  741. }
  742. if (GetFieldOffset("nt!_MM_SESSION_SPACE", "WsListEntry", &WsListEntryOffset) ||
  743. GetFieldOffset("nt!_MM_SESSION_SPACE", "Session", &SessionOffset))
  744. {
  745. dprintf("Cannot find nt!_MM_SESSION_SPACE type.\n");
  746. return FALSE;
  747. }
  748. if (GetFieldOffset("nt!_EPROCESS", "SessionProcessLinks", &SessionProcessLinksOffset))
  749. {
  750. dprintf("Cannot find nt!_EPROCESS type.\n");
  751. return FALSE;
  752. }
  753. SessionSpace = SessionWsListStart-WsListEntryOffset;
  754. do
  755. {
  756. if (GetFieldValue(SessionSpace, "nt!_MM_SESSION_SPACE", "SessionId", SessionId) ||
  757. !ReadPointer(SessionSpace+WsListEntryOffset, &Next) ||
  758. InitTypeRead(SessionSpace, nt!_MM_SESSION_SPACE) )
  759. {
  760. dprintf("Cannot read nt!_MM_SESSION_SPACE @ %p\n", SessionSpace);
  761. return FALSE;
  762. }
  763. if (CheckControlC())
  764. {
  765. break;
  766. }
  767. if (Session == SessionId || Session == -1)
  768. {
  769. ULONG64 SessionProcessList = ReadField(ProcessList.Flink);
  770. ULONG64 NextProcess = 0;
  771. ULONG64 Process;
  772. CHAR ImageFileName[64];
  773. Process = SessionProcessList - SessionProcessLinksOffset;
  774. if (!ReadPointer(SessionProcessList, &NextProcess))
  775. {
  776. dprintf("Cannot read memory SessionProcessLinks for rocess %p\n", Process);
  777. NextProcess = 0;
  778. break;
  779. }
  780. while (NextProcess && NextProcess != SessionProcessList)
  781. {
  782. if (CheckControlC())
  783. {
  784. break;
  785. }
  786. (*Callback)(Process, SessionId, Context);
  787. Process = NextProcess - SessionProcessLinksOffset;
  788. if (!ReadPointer(NextProcess, &NextProcess))
  789. {
  790. dprintf("Cannot read memory SessionProcessLinks for rocess %p\n", Process);
  791. break;
  792. }
  793. }
  794. }
  795. SessionSpace = Next - WsListEntryOffset;
  796. } while (Next && (Next != MiSessionWsList));
  797. return TRUE;
  798. }
  799. BOOL
  800. DumpSessionInfo(
  801. IN ULONG Flags,
  802. IN ULONG SessionIdToDump,
  803. IN PCHAR ProcessName
  804. )
  805. {
  806. ULONG TotalSessions;
  807. ULONG WsListEntryOffset;
  808. ULONG SessionOffset;
  809. ULONG SessionProcessLinksOffset;
  810. ULONG64 MiSessionWsList;
  811. ULONG64 SessionWsListStart;
  812. ULONG64 Next;
  813. ULONG64 SessionSpace;
  814. ULONG CurrentSessionId;
  815. PCHAR Pad = " ";
  816. if (SessionIdToDump == DEFAULT_SESSION)
  817. {
  818. SessionId = SessionId;
  819. }
  820. if (!(Flags & 1) && (SessionIdToDump == CURRENT_SESSION))
  821. {
  822. GetCurrentSession(&SessionSpace, &SessionIdToDump);
  823. }
  824. if (SessionIdToDump != -1)
  825. {
  826. dprintf("Dumping Session %lx\n", SessionIdToDump);
  827. Pad = "";
  828. }
  829. else
  830. {
  831. PRTL_BITMAP pSessionIdBitmap;
  832. ULONG Id;
  833. pSessionIdBitmap = GetBitmap(GetPointerValue("nt!MiSessionIdBitmap"));
  834. TotalSessions = 0;
  835. if (pSessionIdBitmap)
  836. {
  837. for (Id = 0; Id < pSessionIdBitmap->SizeOfBitMap; ++Id)
  838. {
  839. if (RtlCheckBit(pSessionIdBitmap, Id))
  840. {
  841. TotalSessions++;
  842. }
  843. }
  844. HeapFree( GetProcessHeap(), 0, pSessionIdBitmap );
  845. }
  846. if (TotalSessions)
  847. {
  848. dprintf("Total sessions : %lx\n", TotalSessions);
  849. } else
  850. {
  851. // GetPointerValue already printed error, We might still be able to get
  852. // MiSessionWsList so continue
  853. }
  854. }
  855. MiSessionWsList = GetExpression("nt!MiSessionWsList");
  856. if (!MiSessionWsList || !ReadPointer(MiSessionWsList, &SessionWsListStart))
  857. {
  858. dprintf("Cannot get nt!MiSessionWsList\n");
  859. return FALSE;
  860. }
  861. if (GetFieldOffset("nt!_MM_SESSION_SPACE", "WsListEntry", &WsListEntryOffset) ||
  862. GetFieldOffset("nt!_MM_SESSION_SPACE", "Session", &SessionOffset))
  863. {
  864. dprintf("Cannot find nt!_MM_SESSION_SPACE type.\n");
  865. return FALSE;
  866. }
  867. if (GetFieldOffset("nt!_EPROCESS", "SessionProcessLinks", &SessionProcessLinksOffset))
  868. {
  869. dprintf("Cannot find nt!_EPROCESS type.\n");
  870. return FALSE;
  871. }
  872. SessionSpace = SessionWsListStart-WsListEntryOffset;
  873. do
  874. {
  875. if (GetFieldValue(SessionSpace, "nt!_MM_SESSION_SPACE", "SessionId", CurrentSessionId) ||
  876. !ReadPointer(SessionSpace+WsListEntryOffset, &Next) ||
  877. InitTypeRead(SessionSpace, nt!_MM_SESSION_SPACE) )
  878. {
  879. dprintf("Cannot read nt!_MM_SESSION_SPACE @ %p\n", SessionSpace);
  880. return FALSE;
  881. }
  882. if (CheckControlC())
  883. {
  884. break;
  885. }
  886. if (SessionIdToDump == CurrentSessionId || SessionIdToDump == -1)
  887. {
  888. // Dump Session
  889. dprintf("\n");
  890. if (SessionIdToDump == -1)
  891. {
  892. dprintf("%sSession %lx\n", Pad, CurrentSessionId);
  893. }
  894. dprintf("%s_MM_SESSION_SPACE %p\n", Pad, SessionSpace);
  895. dprintf("%s_MMSESSION %p\n", Pad, SessionSpace+SessionOffset);
  896. if (Flags & 2)
  897. {
  898. // Dump Process in the session
  899. ULONG64 SessionProcessList = ReadField(ProcessList.Flink);
  900. ULONG64 NextProcess = 0;
  901. ULONG64 Process;
  902. CHAR ImageFileName[64];
  903. Process = SessionProcessList - SessionProcessLinksOffset;
  904. if (!ReadPointer(SessionProcessList, &NextProcess))
  905. {
  906. dprintf("Cannot read memory SessionProcessLinks for rocess %p\n", Process);
  907. NextProcess = 0;
  908. break;
  909. }
  910. while (NextProcess && NextProcess != SessionProcessList)
  911. {
  912. if (CheckControlC())
  913. {
  914. break;
  915. }
  916. ZeroMemory(ImageFileName, sizeof(ImageFileName));
  917. if (ProcessName && *ProcessName)
  918. {
  919. if (!GetFieldValue(Process, "nt!_EPROCESS", "ImageFileName", ImageFileName) &&
  920. !_stricmp(ImageFileName, ProcessName))
  921. {
  922. DumpProcess(Pad, Process, Flags >> 2, NULL);
  923. }
  924. } else
  925. {
  926. DumpProcess(Pad, Process, Flags >> 2, NULL);
  927. }
  928. Process = NextProcess - SessionProcessLinksOffset;
  929. if (!ReadPointer(NextProcess, &NextProcess))
  930. {
  931. dprintf("Cannot read memory SessionProcessLinks for rocess %p\n", Process);
  932. break;
  933. }
  934. }
  935. }
  936. }
  937. SessionSpace = Next - WsListEntryOffset;
  938. } while (Next && (Next != MiSessionWsList));
  939. return TRUE;
  940. }
  941. HRESULT
  942. GetCurrentSession(
  943. PULONG64 CurSessionSpace,
  944. PULONG CurSessionId
  945. )
  946. {
  947. static DEBUG_VALUE LastSessionSpace = { 0, DEBUG_VALUE_INVALID };
  948. static DEBUG_VALUE LastSessionId = { INVALID_SESSION, DEBUG_VALUE_INVALID };
  949. ULONG64 SessionSpaceAddr;
  950. HRESULT hr = S_OK;
  951. ULONG CurrentSession;
  952. if (CurSessionSpace != NULL) *CurSessionSpace = 0;
  953. if (CurSessionId != NULL) *CurSessionId = INVALID_SESSION;
  954. // Get the current session space
  955. if (LastSessionSpace.Type == DEBUG_VALUE_INVALID)
  956. {
  957. ULONG Processor;
  958. ULONG64 Process=0, Start;
  959. ULONG SessionProcessLinksOffset;
  960. // Get current process
  961. Process = GetExpression("@$Proc");
  962. Start = 0;
  963. GetFieldOffset("nt!_EPROCESS", "SessionProcessLinks", &SessionProcessLinksOffset);
  964. hr = S_FALSE;
  965. if (!GetProcessSessionId(Process, &CurrentSession))
  966. {
  967. hr = E_FAIL;
  968. } else
  969. {
  970. hr = GetFieldValue(Process, "nt!_EPROCESS", "Session", SessionSpaceAddr);
  971. }
  972. if ((hr != S_OK) || (SessionSpaceAddr == 0))
  973. {
  974. // This process doesn't belong to a session, look for a process is 0 session
  975. hr = GetSessionSpace(0, &SessionSpaceAddr, NULL);
  976. }
  977. }
  978. if (hr == S_OK)
  979. {
  980. if (CurSessionSpace != NULL) *CurSessionSpace = SessionSpaceAddr;
  981. if (CurSessionId != NULL) *CurSessionId = CurrentSession;
  982. }
  983. return hr;
  984. }
  985. HRESULT
  986. GetSessionSpace(
  987. ULONG Session,
  988. PULONG64 pSessionSpace,
  989. PULONG64 pSessionProcess
  990. )
  991. {
  992. ULONG TotalSessions;
  993. ULONG WsListEntryOffset;
  994. ULONG SessionOffset;
  995. ULONG64 MiSessionWsList;
  996. ULONG64 SessionWsListStart;
  997. ULONG64 Next;
  998. ULONG64 SessionSpace;
  999. ULONG SessionIdLookup;
  1000. HRESULT hr;
  1001. if (Session == DEFAULT_SESSION)
  1002. {
  1003. Session = SessionId;
  1004. }
  1005. if (Session == CURRENT_SESSION)
  1006. {
  1007. ULONG64 CurSessionSpace;
  1008. ULONG CurSessionId;
  1009. hr = GetCurrentSession(&SessionSpace, &SessionIdLookup);
  1010. if (hr == S_OK)
  1011. {
  1012. if (pSessionSpace)
  1013. {
  1014. *pSessionSpace = SessionSpace;
  1015. }
  1016. return hr;
  1017. }
  1018. }
  1019. else
  1020. {
  1021. if (Session < NUM_CACHED_SESSIONS)
  1022. {
  1023. if (CachedSession[Session].Valid &&
  1024. CachedSession[Session].SessionSpaceAddr != 0)
  1025. {
  1026. if (pSessionSpace != NULL) *pSessionSpace = CachedSession[Session].SessionSpaceAddr;
  1027. if (pSessionProcess != NULL) *pSessionProcess = CachedSession[Session].SessionProcess;
  1028. return S_OK;
  1029. }
  1030. }
  1031. else if (ExtraCachedSessionId != INVALID_SESSION &&
  1032. Session == ExtraCachedSessionId)
  1033. {
  1034. if (CachedSession[NUM_CACHED_SESSIONS].Valid &&
  1035. CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr != 0)
  1036. {
  1037. if (pSessionSpace != NULL) *pSessionSpace = CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr;
  1038. if (pSessionProcess != NULL) *pSessionProcess = CachedSession[NUM_CACHED_SESSIONS].SessionProcess;
  1039. return S_OK;
  1040. }
  1041. }
  1042. }
  1043. MiSessionWsList = GetExpression("nt!MiSessionWsList");
  1044. if (!MiSessionWsList || !ReadPointer(MiSessionWsList, &SessionWsListStart))
  1045. {
  1046. dprintf("Cannot get nt!MiSessionWsList\n");
  1047. return FALSE;
  1048. }
  1049. if (GetFieldOffset("nt!_MM_SESSION_SPACE", "WsListEntry", &WsListEntryOffset) ||
  1050. GetFieldOffset("nt!_MM_SESSION_SPACE", "Session", &SessionOffset))
  1051. {
  1052. dprintf("Cannot find nt!_MM_SESSION_SPACE type.\n");
  1053. return FALSE;
  1054. }
  1055. SessionSpace = SessionWsListStart-WsListEntryOffset;
  1056. do
  1057. {
  1058. if (GetFieldValue(SessionSpace, "nt!_MM_SESSION_SPACE", "SessionId", SessionIdLookup) ||
  1059. !ReadPointer(SessionSpace+WsListEntryOffset, &Next) ||
  1060. InitTypeRead(SessionSpace, nt!_MM_SESSION_SPACE) )
  1061. {
  1062. dprintf("Cannot read nt!_MM_SESSION_SPACE @ %p\n", SessionSpace);
  1063. return FALSE;
  1064. }
  1065. if (CheckControlC())
  1066. {
  1067. break;
  1068. }
  1069. if (Session == SessionIdLookup)
  1070. {
  1071. ULONG SessionProcessLinksOffset;
  1072. ULONG64 SessionProcessList = ReadField(ProcessList.Flink);
  1073. if (pSessionSpace)
  1074. {
  1075. *pSessionSpace = SessionSpace;
  1076. }
  1077. ExtVerb("Session %ld lookup found Session @ 0x%p.\n",
  1078. Session, SessionSpace);
  1079. if (GetFieldOffset("nt!_EPROCESS", "SessionProcessLinks", &SessionProcessLinksOffset))
  1080. {
  1081. dprintf("Cannot find nt!_EPROCESS type.\n");
  1082. return E_FAIL;
  1083. }
  1084. if (Session < NUM_CACHED_SESSIONS)
  1085. {
  1086. CachedSession[Session].Valid = TRUE;
  1087. CachedSession[Session].SessionSpaceAddr = SessionSpace;
  1088. CachedSession[Session].SessionProcess = SessionProcessList - SessionProcessLinksOffset;
  1089. }
  1090. else
  1091. {
  1092. ExtraCachedSessionId = Session;
  1093. CachedSession[NUM_CACHED_SESSIONS].Valid = TRUE;
  1094. CachedSession[NUM_CACHED_SESSIONS].SessionSpaceAddr = SessionSpace;
  1095. CachedSession[NUM_CACHED_SESSIONS].SessionProcess = SessionProcessList - SessionProcessLinksOffset;
  1096. }
  1097. if (pSessionProcess)
  1098. {
  1099. *pSessionProcess = SessionProcessList - SessionProcessLinksOffset;
  1100. }
  1101. return S_OK;
  1102. }
  1103. SessionSpace = Next - WsListEntryOffset;
  1104. } while (Next && (Next != MiSessionWsList));
  1105. return E_FAIL;
  1106. }
  1107. HRESULT
  1108. GetSessionDirBase(
  1109. PDEBUG_CLIENT Client,
  1110. ULONG Session,
  1111. PULONG64 PageDirBase
  1112. )
  1113. {
  1114. HRESULT hr = S_FALSE;
  1115. ULONG64 SessionSpaceOffset;
  1116. ULONG64 Process = -1;
  1117. ULONG SessionIdCheck;
  1118. ULONG64 dvPageDirBase;
  1119. CHAR szCommand[MAX_PATH];
  1120. static ULONG LastSession = -2;
  1121. static ULONG64 LastSessionPageDirBase = 0;
  1122. if (Session == DEFAULT_SESSION)
  1123. {
  1124. Session = SessionId;
  1125. }
  1126. if (Session == LastSession &&
  1127. LastSessionPageDirBase != 0)
  1128. {
  1129. *PageDirBase = LastSessionPageDirBase;
  1130. return S_OK;
  1131. }
  1132. *PageDirBase = 0;
  1133. if ((hr == GetSessionSpace(Session, &SessionSpaceOffset, NULL)) == S_OK)
  1134. {
  1135. ULONG SessionProcessLinksOffset;
  1136. if ((hr = GetFieldOffset("nt!_EPROCESS", "SessionProcessLinks", &SessionProcessLinksOffset)) == S_OK)
  1137. {
  1138. dprintf("Cannot find nt!_EPROCESS type.\n");
  1139. return E_FAIL;
  1140. }
  1141. ULONG64 SessionProcessListAddr;
  1142. if (GetFieldValue(SessionSpaceOffset, "nt!_MM_SESSION_SPACE",
  1143. "ProcessList.Flink", SessionProcessListAddr) == S_OK)
  1144. {
  1145. Process = SessionProcessListAddr - SessionProcessLinksOffset;
  1146. } else
  1147. {
  1148. dprintf("Cannot read nt!_MM_SESSION_SPACE @ %p\n", SessionSpaceOffset);
  1149. return E_FAIL;
  1150. }
  1151. }
  1152. else
  1153. {
  1154. dprintf("GetSessionSpace returned HRESULT 0x%lx.\n", hr);
  1155. }
  1156. if (GetFieldValue(Process, "nt!_KPROCESS", "DirectoryTableBase[0]", dvPageDirBase) == S_OK &&
  1157. GetProcessSessionId(Process, &SessionIdCheck) == S_OK)
  1158. {
  1159. *PageDirBase = dvPageDirBase;
  1160. if (Session != CURRENT_SESSION &&
  1161. Session != SessionIdCheck)
  1162. {
  1163. hr = S_FALSE;
  1164. }
  1165. else
  1166. {
  1167. LastSession = Session;
  1168. LastSessionPageDirBase = dvPageDirBase;
  1169. }
  1170. }
  1171. return hr;
  1172. }
  1173. #if 0
  1174. HRESULT
  1175. ReadPageTableEntry(
  1176. PDEBUG_DATA_SPACES Data,
  1177. ULONG64 PageTableBase,
  1178. ULONG64 PageTableIndex,
  1179. PULONG64 PageTableEntry
  1180. )
  1181. {
  1182. HRESULT hr;
  1183. ULONG64 PhysAddr = PageTableBase + PageTableIndex * HwPte.Size;
  1184. ULONG BytesRead;
  1185. *PageTableEntry = 0;
  1186. if (CachedPhysAddr[0].Valid &&
  1187. CachedPhysAddr[0].PhysAddr == PhysAddr)
  1188. {
  1189. *PageTableEntry = CachedPhysAddr[0].Data;
  1190. return S_OK;
  1191. }
  1192. else if (CachedPhysAddr[1].Valid &&
  1193. CachedPhysAddr[1].PhysAddr == PhysAddr)
  1194. {
  1195. *PageTableEntry = CachedPhysAddr[1].Data;
  1196. return S_OK;
  1197. }
  1198. hr = Data->ReadPhysical(PhysAddr,
  1199. PageTableEntry,
  1200. HwPte.Size,
  1201. &BytesRead);
  1202. if (hr == S_OK)
  1203. {
  1204. if (BytesRead < HwPte.Size)
  1205. {
  1206. hr = S_FALSE;
  1207. }
  1208. else
  1209. {
  1210. static CacheToggle = 1;
  1211. CacheToggle = (CacheToggle+1) % 2;
  1212. CachedPhysAddr[CacheToggle].Valid = TRUE;
  1213. CachedPhysAddr[CacheToggle].PhysAddr = *PageTableEntry;
  1214. }
  1215. }
  1216. return hr;
  1217. }
  1218. HRESULT
  1219. GetPageFrameNumber(
  1220. PDEBUG_CLIENT Client,
  1221. PDEBUG_DATA_SPACES Data,
  1222. ULONG64 PageTableBase,
  1223. ULONG64 PageTableIndex,
  1224. PULONG64 PageFrameNumber,
  1225. PBOOL Large
  1226. )
  1227. {
  1228. HRESULT hr;
  1229. ULONG64 PageTableEntry;
  1230. ULONG64 Valid, Proto, Trans, LargePage;
  1231. ULONG64 pfn;
  1232. if ((hr = ReadPageTableEntry(Data, PageTableBase, PageTableIndex, &PageTableEntry)) == S_OK)
  1233. {
  1234. if ((hr = GetMMPTEValid(Client, PageTableEntry, &Valid)) == S_OK)
  1235. {
  1236. if (Valid)
  1237. {
  1238. hr = GetMMPTEpfn(Client, PageTableEntry, PageFrameNumber, GET_BITS_UNSHIFTED);
  1239. if (hr == S_OK)
  1240. {
  1241. if (GetMMPTEX86LargePage(Client, PageTableEntry, &LargePage) == S_OK &&
  1242. LargePage != 0)
  1243. {
  1244. // Large pages map 4MB of space - there shouldn't
  1245. // be any bits set below that.
  1246. if (*PageFrameNumber & (4*1024*1024 - 1))
  1247. {
  1248. #if DBG
  1249. DbgPrint("Found large X86 page with bad frame number.\n");
  1250. DbgBreakPoint();
  1251. #endif
  1252. }
  1253. if (Large == NULL)
  1254. {
  1255. #if DBG
  1256. DbgPrint("Unexpected large X86 page found.\n");
  1257. DbgBreakPoint();
  1258. #endif
  1259. }
  1260. else
  1261. {
  1262. *Large = TRUE;
  1263. }
  1264. }
  1265. else if (Large != NULL)
  1266. {
  1267. *Large = FALSE;
  1268. }
  1269. }
  1270. }
  1271. else
  1272. {
  1273. if ((hr = GetMMPTEProto(Client, PageTableEntry, &Proto)) == S_OK &&
  1274. (hr = GetMMPTETrans(Client, PageTableEntry, &Trans)) == S_OK)
  1275. {
  1276. if (Proto == 0 && Trans == 1)
  1277. {
  1278. hr = GetMMPTEpfn(Client, PageTableEntry, PageFrameNumber, GET_BITS_UNSHIFTED);
  1279. }
  1280. else
  1281. {
  1282. hr = S_FALSE;
  1283. }
  1284. }
  1285. }
  1286. }
  1287. }
  1288. return hr;
  1289. }
  1290. HRESULT
  1291. GetNextResidentPage(
  1292. PDEBUG_CLIENT Client,
  1293. ULONG64 PageDirBase,
  1294. ULONG64 VirtAddrStart,
  1295. ULONG64 VirtAddrLimit,
  1296. PULONG64 VirtPage,
  1297. PULONG64 PhysPage
  1298. )
  1299. {
  1300. HRESULT hr;
  1301. BOOL Interrupted = FALSE;
  1302. PDEBUG_CONTROL Control = NULL;
  1303. PDEBUG_DATA_SPACES Data = NULL;
  1304. ULONG64 PageDirIndex;
  1305. ULONG64 PageTableIndex;
  1306. ULONG64 PageDirIndexLimit;
  1307. ULONG64 PageTableIndexLimit;
  1308. ULONG64 PageTableBase;
  1309. BOOL LargePage;
  1310. ULONG64 TempAddr;
  1311. if (VirtPage == NULL) VirtPage = &TempAddr;
  1312. if (PhysPage == NULL) PhysPage = &TempAddr;
  1313. *VirtPage = 0;
  1314. *PhysPage = 0;
  1315. if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  1316. (void **)&Data)) == S_OK &&
  1317. (hr = Client->QueryInterface(__uuidof(IDebugControl),
  1318. (void **)&Control)) == S_OK)
  1319. {
  1320. if (!HwPte.Valid)
  1321. {
  1322. PDEBUG_SYMBOLS Symbols;
  1323. if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  1324. (void **)&Symbols)) == S_OK)
  1325. {
  1326. if ((hr = Symbols->GetSymbolTypeId(HwPte.Type, &HwPte.TypeId, &HwPte.Module)) == S_OK &&
  1327. (hr = Symbols->GetTypeSize(HwPte.Module, HwPte.TypeId, &HwPte.Size)) == S_OK &&
  1328. HwPte.Size != 0)
  1329. {
  1330. HwPte.Valid = TRUE;
  1331. }
  1332. else if (hr == S_OK)
  1333. {
  1334. hr = E_FAIL;
  1335. }
  1336. Symbols->Release();
  1337. }
  1338. }
  1339. if (HwPte.Valid)
  1340. {
  1341. ULONG TableEntries = PageSize / HwPte.Size;
  1342. ULONG64 Addr;
  1343. *VirtPage = PAGE_ALIGN64(VirtAddrStart);
  1344. Addr = VirtAddrStart >> PageShift;
  1345. PageTableIndex = Addr % TableEntries;
  1346. PageDirIndex = (Addr / TableEntries) % TableEntries;
  1347. Addr = VirtAddrLimit >> PageShift;
  1348. PageTableIndexLimit = Addr % TableEntries;
  1349. PageDirIndexLimit = (Addr / TableEntries) % TableEntries;
  1350. if (VirtAddrLimit & (PageSize-1))
  1351. {
  1352. PageTableIndexLimit++;
  1353. }
  1354. hr = S_FALSE;
  1355. while (PageDirIndex < PageDirIndexLimit && hr != S_OK)
  1356. {
  1357. if ((hr = GetPageFrameNumber(Client, Data,
  1358. PageDirBase, PageDirIndex,
  1359. &PageTableBase, &LargePage)) == S_OK)
  1360. {
  1361. if (LargePage)
  1362. {
  1363. *PhysPage = PageTableBase;
  1364. }
  1365. else
  1366. {
  1367. do
  1368. {
  1369. if ((hr = GetPageFrameNumber(Client, Data,
  1370. PageTableBase, PageTableIndex,
  1371. PhysPage, NULL)) != S_OK)
  1372. {
  1373. hr = Control->GetInterrupt();
  1374. if (hr == S_OK)
  1375. {
  1376. Interrupted = TRUE;
  1377. Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  1378. }
  1379. else
  1380. {
  1381. PageTableIndex++;
  1382. *VirtPage += PageSize;
  1383. }
  1384. }
  1385. } while (PageTableIndex < TableEntries && hr != S_OK);
  1386. }
  1387. }
  1388. else
  1389. {
  1390. *VirtPage += PageSize * (TableEntries - PageTableIndex);
  1391. }
  1392. if (hr != S_OK)
  1393. {
  1394. hr = Control->GetInterrupt();
  1395. if (hr == S_OK)
  1396. {
  1397. Interrupted = TRUE;
  1398. Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  1399. }
  1400. else
  1401. {
  1402. PageTableIndex = 0;
  1403. PageDirIndex++;
  1404. }
  1405. }
  1406. }
  1407. if (PageDirIndex == PageDirIndexLimit &&
  1408. PageTableIndex < PageTableIndexLimit &&
  1409. hr != S_OK)
  1410. {
  1411. if ((hr = GetPageFrameNumber(Client, Data,
  1412. PageDirBase, PageDirIndex,
  1413. &PageTableBase, &LargePage)) == S_OK)
  1414. {
  1415. if (LargePage)
  1416. {
  1417. *PhysPage = PageTableBase;
  1418. }
  1419. else
  1420. {
  1421. do
  1422. {
  1423. if ((hr = GetPageFrameNumber(Client, Data,
  1424. PageTableBase, PageTableIndex,
  1425. PhysPage, NULL)) != S_OK)
  1426. {
  1427. hr = Control->GetInterrupt();
  1428. if (hr == S_OK)
  1429. {
  1430. Interrupted = TRUE;
  1431. Control->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  1432. }
  1433. else
  1434. {
  1435. PageTableIndex++;
  1436. *VirtPage += PageSize;
  1437. }
  1438. }
  1439. } while (PageTableIndex < PageTableIndexLimit && hr != S_OK);
  1440. }
  1441. }
  1442. }
  1443. }
  1444. }
  1445. if (Control != NULL) Control->Release();
  1446. if (Data != NULL) Data->Release();
  1447. return ((Interrupted) ? E_ABORT : hr);
  1448. }
  1449. HRESULT
  1450. GetNextResidentAddress(
  1451. PDEBUG_CLIENT Client,
  1452. ULONG Session,
  1453. ULONG64 VirtAddrStart,
  1454. ULONG64 VirtAddrLimit,
  1455. PULONG64 VirtAddr,
  1456. PULONG64 PhysAddr
  1457. )
  1458. {
  1459. if (Client == NULL) return E_INVALIDARG;
  1460. HRESULT hr = S_OK;
  1461. ULONG64 PageDirBase;
  1462. if (Session == DEFAULT_SESSION)
  1463. {
  1464. Session = SessionId;
  1465. }
  1466. if (Session < NUM_CACHED_DIR_BASES &&
  1467. CachedDirBase[Session].Valid)
  1468. {
  1469. PageDirBase = CachedDirBase[Session].PageDirBase;
  1470. }
  1471. else if (SessionId == CURRENT_SESSION &&
  1472. CachedDirBase[NUM_CACHED_DIR_BASES].Valid)
  1473. {
  1474. PageDirBase = CachedDirBase[NUM_CACHED_DIR_BASES].PageDirBase;
  1475. }
  1476. else
  1477. {
  1478. DEBUG_VALUE SessionIdCheck;
  1479. DEBUG_VALUE dvPageDirBase;
  1480. BOOL ShortProcessList = (Session == CURRENT_SESSION);
  1481. ULONG Processor;
  1482. ULONG64 Process=0;
  1483. ULONG64 ProcessListHead = 0;
  1484. ULONG64 ProcessListNext = 0;
  1485. ULONG ActiveProcessLinksOff;
  1486. ULONG CurrentSession;
  1487. if (!GetCurrentProcessor(g_ExtClient, &Processor, NULL))
  1488. {
  1489. Processor = 0;
  1490. }
  1491. GetCurrentProcessAddr(Processor, 0, &Process);
  1492. GetProcessHead(&ProcessListHead, &ProcessListNext);
  1493. if (GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActiveProcessLinksOff))
  1494. {
  1495. dprintf("Unable to get EPROCESS.ActiveProcessLinks offset\n");
  1496. hr = E_FAIL;;
  1497. ProcessListNext = 0;
  1498. }
  1499. hr = S_FALSE;
  1500. while ((ProcessListNext != ProcessListHead) && ProcessListNext &&
  1501. (hr != S_OK))
  1502. {
  1503. if (!ShortProcessList)
  1504. {
  1505. Process = ProcessListNext - ActiveProcessLinksOff;
  1506. if (!ReadPointer(ProcessListNext, &ProcessListNext))
  1507. {
  1508. dprintf("Cannot read EPROCESS at %p\n", Process);
  1509. hr = E_FAIL;
  1510. break;
  1511. }
  1512. if (CheckControlC())
  1513. {
  1514. hr = E_FAIL;
  1515. break;
  1516. }
  1517. }
  1518. if (!GetProcessSessionId(Process, &CurrentSession))
  1519. {
  1520. hr = E_FAIL;
  1521. break;
  1522. }
  1523. GetFieldValue(Process, "nt!_KPROCESS", "DirectoryTableBase[0]", PageDirBase);
  1524. if (!IsPtr64())
  1525. {
  1526. PageDirBase = (ULONG64) (LONG64) (LONG) PageDirBase;
  1527. }
  1528. if ((Session == CurrentSession) || ShortProcessList)
  1529. {
  1530. hr = S_OK;
  1531. if (Session < NUM_CACHED_DIR_BASES)
  1532. {
  1533. CachedDirBase[Session].Valid = TRUE;
  1534. CachedDirBase[Session].PageDirBase = PageDirBase;
  1535. }
  1536. else if (Session == CURRENT_SESSION)
  1537. {
  1538. CachedDirBase[NUM_CACHED_DIR_BASES].Valid = TRUE;
  1539. CachedDirBase[NUM_CACHED_DIR_BASES].PageDirBase = PageDirBase;
  1540. }
  1541. }
  1542. }
  1543. }
  1544. if (hr == S_OK)
  1545. {
  1546. hr = GetNextResidentPage(Client,
  1547. PageDirBase,
  1548. VirtAddrStart,
  1549. VirtAddrLimit,
  1550. VirtAddr,
  1551. PhysAddr);
  1552. }
  1553. else
  1554. {
  1555. ExtVerb("Page Directory Base lookup failed.\n");
  1556. }
  1557. return hr;
  1558. }
  1559. #endif
  1560. DECLARE_API( dss )
  1561. /*++
  1562. Routine Description:
  1563. Dumps the session space structure
  1564. Arguments:
  1565. None.
  1566. Return Value:
  1567. None.
  1568. --*/
  1569. {
  1570. ULONG Result;
  1571. ULONG64 MmSessionSpace;
  1572. ULONG64 MmSessionSpacePtr = 0;
  1573. ULONG64 Wsle;
  1574. MmSessionSpacePtr = GetExpression(args);
  1575. if( MmSessionSpacePtr == 0 ) {
  1576. MmSessionSpacePtr = GetExpression("nt!MmSessionSpace");
  1577. if( !MmSessionSpacePtr ) {
  1578. dprintf("Unable to get address of MmSessionSpace\n");
  1579. return E_INVALIDARG;
  1580. }
  1581. if (!ReadPointer( MmSessionSpacePtr, &MmSessionSpace)) {
  1582. dprintf("Unable to get value of MmSessionSpace\n");
  1583. return E_INVALIDARG;
  1584. }
  1585. } else {
  1586. MmSessionSpace = MmSessionSpacePtr;
  1587. }
  1588. dprintf("MM_SESSION_SPACE at 0x%p\n",
  1589. MmSessionSpace
  1590. );
  1591. if (GetFieldValue(MmSessionSpace, "MM_SESSION_SPACE", "Wsle", Wsle)) {
  1592. dprintf("Unable to get value of MM_SESSION_SPACE at 0x%p\n",MmSessionSpace);
  1593. return E_INVALIDARG;
  1594. }
  1595. GetFieldOffset("MM_SESSION_SPACE", "PageTables", &Result);
  1596. dprintf("&PageTables %p\n",
  1597. MmSessionSpace + Result
  1598. );
  1599. GetFieldOffset("MM_SESSION_SPACE", "PagedPoolInfo", &Result);
  1600. dprintf("&MM_PAGED_POOL_INFO %x\n",
  1601. MmSessionSpace + Result
  1602. );
  1603. GetFieldOffset("MM_SESSION_SPACE", "Vm", &Result);
  1604. dprintf("&MMSUPPORT %p\n",
  1605. MmSessionSpace + Result
  1606. );
  1607. GetFieldOffset("MM_SESSION_SPACE", "Wsle", &Result);
  1608. dprintf("&PMMWSLE %p\n",
  1609. MmSessionSpace + Result
  1610. );
  1611. GetFieldOffset("MM_SESSION_SPACE", "Session", &Result);
  1612. dprintf("&MMSESSION %p\n",
  1613. MmSessionSpace + Result
  1614. );
  1615. GetFieldOffset("MM_SESSION_SPACE", "WorkingSetLockOwner", &Result);
  1616. dprintf("&WorkingSetLockOwner %p\n",
  1617. MmSessionSpace + Result
  1618. );
  1619. GetFieldOffset("MM_SESSION_SPACE", "PagedPool", &Result);
  1620. dprintf("&POOL_DESCRIPTOR %p\n",
  1621. MmSessionSpace + Result
  1622. );
  1623. return S_OK;
  1624. }
  1625. DECLARE_API( session )
  1626. {
  1627. INIT_API();
  1628. HRESULT hr;
  1629. ULONG NewSession = CURRENT_SESSION;
  1630. ULONG CurrentSession = INVALID_SESSION;
  1631. ULONG SessionCount = 0;
  1632. BOOL SetSession = FALSE;
  1633. PRTL_BITMAP SessionList = NULL;
  1634. DEBUG_VALUE DebugValue;
  1635. ULONG Remainder;
  1636. while (*args && isspace(*args)) args++;
  1637. if (args[0] == '-' || args[0] == '/')
  1638. {
  1639. if (args[1] == '?')
  1640. {
  1641. ExtOut("session displays number of sessions on machine and\n"
  1642. " the default SessionId used by session related extensions.\n"
  1643. "\n"
  1644. "Usage: session [ [-s] SessionId]\n"
  1645. " -s - sets default session used for session extensions\n"
  1646. "Note: Use !sprocess to dump session process\n");
  1647. EXIT_API();
  1648. return S_OK;
  1649. } else if (args[1] == 's')
  1650. {
  1651. args+=2;
  1652. SetSession = TRUE;
  1653. }
  1654. }
  1655. hr = g_ExtControl->Evaluate(args, DEBUG_VALUE_INT32, &DebugValue, &Remainder);
  1656. if (hr == S_OK)
  1657. {
  1658. args += Remainder;
  1659. }
  1660. if (GetSessionNumbers(Client, &CurrentSession, NULL, &SessionCount, &SessionList) == S_OK)
  1661. {
  1662. if (SessionCount != 0)
  1663. {
  1664. ExtOut("Sessions on machine: %lu\n", SessionCount);
  1665. // If a session wasn't specified,
  1666. // list valid sessions (up to a point).
  1667. if (hr != S_OK)
  1668. {
  1669. ULONG SessionLimit = SessionList->SizeOfBitMap;
  1670. ExtOut("Valid Sessions:");
  1671. for (ULONG CheckSession = 0; CheckSession <= SessionLimit; CheckSession++)
  1672. {
  1673. if (RtlCheckBit(SessionList, CheckSession)
  1674. /*GetSessionSpace(Client, CheckSession, NULL) == S_OK*/)
  1675. {
  1676. ExtOut(" %lu", CheckSession);
  1677. SessionCount--;
  1678. if (SessionCount == 0) break;
  1679. }
  1680. if (g_ExtControl->GetInterrupt() == S_OK)
  1681. {
  1682. ExtWarn("\n User aborted.\n");
  1683. break;
  1684. }
  1685. }
  1686. if (SessionCount > 0)
  1687. {
  1688. ExtOut(" ...?");
  1689. }
  1690. ExtOut("\n");
  1691. }
  1692. }
  1693. else if (SessionList)
  1694. {
  1695. ExtOut("There are ZERO session on machine.\n");
  1696. }
  1697. else
  1698. {
  1699. ExtErr("Couldn't determine number of sessions.\n");
  1700. }
  1701. if (SessionList)
  1702. {
  1703. FreeBitMap(SessionList);
  1704. }
  1705. if (CurrentSession != INVALID_SESSION)
  1706. {
  1707. ExtVerb("Running session: %lu\n", CurrentSession);
  1708. }
  1709. }
  1710. if ((hr == S_OK) && SetSession)
  1711. {
  1712. NewSession = DebugValue.I32;
  1713. ExtVerb("Previous Default Session: %s\n", SessionStr);
  1714. if (SetDefaultSession(Client, NewSession, NULL) != S_OK)
  1715. {
  1716. ExtErr("Couldn't set Session %lu.\n", NewSession);
  1717. }
  1718. ExtOut("Using session %s", SessionStr);
  1719. }
  1720. if (SessionId == CURRENT_SESSION)
  1721. {
  1722. if (CurrentSession != INVALID_SESSION)
  1723. {
  1724. ExtOut("Current Session %d", CurrentSession);
  1725. }
  1726. else
  1727. {
  1728. ExtOut("Error in reading current session");
  1729. }
  1730. }
  1731. ExtOut("\n");
  1732. EXIT_API();
  1733. return S_OK;
  1734. }
  1735. DECLARE_API( svtop )
  1736. {
  1737. INIT_API();
  1738. HRESULT hr;
  1739. DEBUG_VALUE SessVirtAddr;
  1740. ULONG64 PhysAddr;
  1741. if (S_OK == g_ExtControl->Evaluate(args, DEBUG_VALUE_INT64, &SessVirtAddr, NULL))
  1742. {
  1743. ExtOut("Use !vtop 0 %p\n", SessVirtAddr.I64);
  1744. }
  1745. else
  1746. {
  1747. ExtOut("Use !vtop 0 VirtualAddress\n");
  1748. }
  1749. EXIT_API();
  1750. return S_OK;
  1751. }
  1752. DECLARE_API( sprocess )
  1753. {
  1754. INIT_API();
  1755. HRESULT hr;
  1756. DEBUG_VALUE Session;
  1757. ULONG RemainingArgIndex;
  1758. DEBUG_VALUE Flag;
  1759. while (*args && isspace(*args)) args++;
  1760. if (args[0] == '-' && args[1] == '?')
  1761. {
  1762. ExtOut("sprocess is like !process, but for the SessionId specified.\n"
  1763. "\n"
  1764. "Usage: sprocess [SessionId [Flags]]\n"
  1765. " SessionId - specifies which session to dump.\n"
  1766. " Special SessionId values:\n"
  1767. " -1 - current session\n"
  1768. " Flags - see !process help\n");
  1769. EXIT_API();
  1770. return S_OK;
  1771. }
  1772. ULONG OldRadix;
  1773. g_ExtControl->GetRadix(&OldRadix);
  1774. g_ExtControl->SetRadix(10);
  1775. hr = g_ExtControl->Evaluate(args, DEBUG_VALUE_INT32, &Session, &RemainingArgIndex);
  1776. g_ExtControl->SetRadix(OldRadix);
  1777. Flag.I32 = 0;
  1778. if (hr != S_OK)
  1779. {
  1780. Session.I32 = SessionId;
  1781. hr = S_OK;
  1782. }
  1783. else
  1784. {
  1785. args += RemainingArgIndex;
  1786. hr = g_ExtControl->Evaluate(args, DEBUG_VALUE_INT32, &Flag, &RemainingArgIndex);
  1787. if (hr == S_OK)
  1788. {
  1789. args += RemainingArgIndex;
  1790. }
  1791. }
  1792. Flag.I32 = (Flag.I32 << 2) | 2;
  1793. while (*args && *args == ' ') ++args;
  1794. hr = DumpSessionInfo(Flag.I32, Session.I32, (PCHAR) (*args ? args : NULL));
  1795. EXIT_API();
  1796. return hr;
  1797. }
  1798. HRESULT
  1799. SearchLinkedList(
  1800. PDEBUG_CLIENT Client,
  1801. ULONG64 StartAddr,
  1802. ULONG64 NextLinkOffset,
  1803. ULONG64 SearchAddr,
  1804. PULONG LinksTraversed
  1805. )
  1806. {
  1807. if (LinksTraversed != NULL)
  1808. {
  1809. *LinksTraversed = 0;
  1810. }
  1811. INIT_API();
  1812. HRESULT hr = S_OK;
  1813. ULONG64 PhysAddr;
  1814. ULONG64 NextAddr = StartAddr;
  1815. ULONG LinkCount = 0;
  1816. ULONG PointerSize;
  1817. ULONG BytesRead;
  1818. PointerSize = (g_ExtControl->IsPointer64Bit() == S_OK) ? 8 : 4;
  1819. do
  1820. {
  1821. if ((hr = g_ExtData->ReadVirtual(NextLinkOffset + NextLinkOffset,
  1822. &NextAddr,
  1823. PointerSize,
  1824. &BytesRead)) == S_OK)
  1825. {
  1826. if (BytesRead == PointerSize)
  1827. {
  1828. LinkCount++;
  1829. if (PointerSize != 8)
  1830. {
  1831. NextAddr = DEBUG_EXTEND64(NextAddr);
  1832. }
  1833. ExtVerb("NextAddr: %p\n", NextAddr);
  1834. }
  1835. else
  1836. {
  1837. hr = S_FALSE;
  1838. }
  1839. }
  1840. } while (hr == S_OK &&
  1841. NextAddr != SearchAddr &&
  1842. NextAddr != 0 &&
  1843. LinkCount < 4 &&
  1844. NextAddr != StartAddr);
  1845. if (LinksTraversed != NULL)
  1846. {
  1847. *LinksTraversed = LinkCount;
  1848. }
  1849. // Did we really find SearchAddr?
  1850. if (hr == S_OK &&
  1851. NextAddr != SearchAddr)
  1852. {
  1853. hr = S_FALSE;
  1854. }
  1855. EXIT_API();
  1856. return hr;
  1857. }
  1858. DECLARE_API( walklist )
  1859. {
  1860. INIT_API();
  1861. HRESULT hr;
  1862. BOOL NeedHelp = FALSE;
  1863. BOOL SearchSessions = FALSE;
  1864. DEBUG_VALUE StartAddr;
  1865. DEBUG_VALUE OffsetToNextField = { -1, DEBUG_VALUE_INVALID };//FIELD_OFFSET(Win32PoolHead, pNext);
  1866. DEBUG_VALUE SearchAddr;
  1867. ULONG NextArg;
  1868. ULONG SessionCount;
  1869. ULONG Session = 0;
  1870. ULONG OldDefSession;
  1871. ULONG LinksToDest = 0;
  1872. while (*args && isspace(*args)) args++;
  1873. while (args[0] == '-' && !NeedHelp)
  1874. {
  1875. if (tolower(args[1]) == 'a' && isspace(args[2]))
  1876. {
  1877. SearchSessions = TRUE;
  1878. args += 2;
  1879. while (*args && isspace(*args)) args++;
  1880. }
  1881. else if (tolower(args[1]) == 'o' &&
  1882. GetExpressionEx(args+2,
  1883. &OffsetToNextField.I64, &args) == TRUE)
  1884. {
  1885. while (*args && isspace(*args)) args++;
  1886. }
  1887. else
  1888. {
  1889. NeedHelp = TRUE;
  1890. }
  1891. }
  1892. if (!NeedHelp &&
  1893. S_OK == g_ExtControl->Evaluate(args, DEBUG_VALUE_INT64, &StartAddr, &NextArg))
  1894. {
  1895. args += NextArg;
  1896. if (S_OK != g_ExtControl->Evaluate(args, DEBUG_VALUE_INT64, &SearchAddr, &NextArg))
  1897. {
  1898. SearchAddr.I64 = 0;
  1899. }
  1900. if (OffsetToNextField.Type == DEBUG_VALUE_INVALID)
  1901. {
  1902. ExtWarn("Assuming next field's offset is +8.\n");
  1903. OffsetToNextField.I64 = 8;
  1904. }
  1905. else
  1906. {
  1907. ExtOut("Using field at offset +0x%I64u for next.\n", OffsetToNextField.I64);
  1908. }
  1909. if (SearchSessions &&
  1910. GetSessionNumbers(Client, NULL, &OldDefSession, &SessionCount, NULL) == S_OK &&
  1911. SessionCount > 0)
  1912. {
  1913. ExtOut("Searching all sessions lists @ %p for %p\n", StartAddr.I64, SearchAddr.I64);
  1914. do
  1915. {
  1916. while (SetDefaultSession(Client, Session, NULL) != S_OK &&
  1917. Session <= SESSION_SEARCH_LIMIT)
  1918. {
  1919. Session++;
  1920. }
  1921. if (Session <= SESSION_SEARCH_LIMIT)
  1922. {
  1923. if ((hr = SearchLinkedList(Client, StartAddr.I64, OffsetToNextField.I64, SearchAddr.I64, &LinksToDest)) == S_OK)
  1924. {
  1925. ExtOut("Session %lu: Found %p after walking %lu linked list entries.\n", Session, SearchAddr.I64, LinksToDest);
  1926. }
  1927. else
  1928. {
  1929. ExtOut("Session %lu: Couldn't find %p after walking %lu linked list entries.\n", Session, SearchAddr.I64, LinksToDest);
  1930. }
  1931. Session++;
  1932. SessionCount--;
  1933. }
  1934. } while (SessionCount > 0 && Session <= SESSION_SEARCH_LIMIT);
  1935. if (SessionCount)
  1936. {
  1937. ExtErr("%lu sessions beyond session %lu were not searched.\n",
  1938. SessionCount, SESSION_SEARCH_LIMIT);
  1939. }
  1940. SetDefaultSession(Client, OldDefSession, NULL);
  1941. }
  1942. else
  1943. {
  1944. ExtOut("Searching Session %s list @ %p for %p\n", SessionStr, StartAddr.I64, SearchAddr.I64);
  1945. if ((hr = SearchLinkedList(Client, StartAddr.I64, OffsetToNextField.I64, SearchAddr.I64, &LinksToDest)) == S_OK)
  1946. {
  1947. ExtOut("Found %p after walking %lu linked list entries.\n", SearchAddr.I64, LinksToDest);
  1948. }
  1949. else
  1950. {
  1951. ExtOut("Couldn't find %p after walking %lu linked list entries.\n", SearchAddr.I64, LinksToDest);
  1952. }
  1953. }
  1954. }
  1955. else
  1956. {
  1957. NeedHelp = TRUE;
  1958. }
  1959. if (NeedHelp)
  1960. {
  1961. ExtOut("Usage: walklist [-a] StartAddress [SearchAddr]\n");
  1962. }
  1963. EXIT_API();
  1964. return S_OK;
  1965. }
  1966. HRESULT
  1967. GetBitMap(
  1968. PDEBUG_CLIENT Client,
  1969. ULONG64 pBitMap,
  1970. PRTL_BITMAP *pBitMapOut
  1971. )
  1972. {
  1973. HRESULT hr;
  1974. PRTL_BITMAP p;
  1975. ULONG Size;
  1976. ULONG64 Buffer;
  1977. ULONG BufferLen;
  1978. ULONG BytesRead = 0;
  1979. *pBitMapOut = NULL;
  1980. if ((GetFieldValue(pBitMap, "nt!_RTL_BITMAP", "SizeOfBitMap", Size) == S_OK) &&
  1981. (GetFieldValue(pBitMap, "nt!_RTL_BITMAP", "Buffer", Buffer) == S_OK))
  1982. {
  1983. PDEBUG_DATA_SPACES Data;
  1984. if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  1985. (void **)&Data)) == S_OK)
  1986. {
  1987. BufferLen = (Size + 7) / 8;
  1988. #if DBG
  1989. ExtVerb("Reading RTL_BITMAP @ 0x%p:\n"
  1990. " SizeOfBitMap: %lu\n"
  1991. " Buffer: 0x%p\n"
  1992. " Length in bytes: 0x%lx\n",
  1993. pBitMap,
  1994. Size,
  1995. Buffer,
  1996. BufferLen);
  1997. #endif
  1998. p = (PRTL_BITMAP) HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) + BufferLen );
  1999. if (p != NULL)
  2000. {
  2001. RtlInitializeBitMap(p, (PULONG)(p + 1), Size);
  2002. hr = Data->ReadVirtual(Buffer, p->Buffer, BufferLen, &BytesRead);
  2003. if (hr != S_OK)
  2004. {
  2005. ExtErr("Error reading bitmap contents @ 0x%p\n", Buffer);
  2006. }
  2007. else if (BytesRead < BufferLen)
  2008. {
  2009. ExtErr("Error reading bitmap contents @ 0x%p\n", Buffer + BytesRead);
  2010. hr = E_FAIL;
  2011. }
  2012. if (hr != S_OK)
  2013. {
  2014. HeapFree( GetProcessHeap(), 0, p );
  2015. p = NULL;
  2016. }
  2017. else
  2018. {
  2019. *pBitMapOut = p;
  2020. }
  2021. }
  2022. else
  2023. {
  2024. hr = E_OUTOFMEMORY;
  2025. }
  2026. Data->Release();
  2027. }
  2028. else
  2029. {
  2030. ExtErr("Error setting up debugger interface.\n");
  2031. }
  2032. }
  2033. else
  2034. {
  2035. ExtErr("Error reading bitmap header @ 0x%p.\n", pBitMap);
  2036. }
  2037. return hr;
  2038. }
  2039. HRESULT
  2040. FreeBitMap(
  2041. PRTL_BITMAP pBitMap
  2042. )
  2043. {
  2044. return (HeapFree( GetProcessHeap(), 0, pBitMap) ? S_OK : S_FALSE);
  2045. }
  2046. HRESULT
  2047. CheckSingleFilter(
  2048. PUCHAR Tag,
  2049. PUCHAR Filter
  2050. )
  2051. {
  2052. ULONG i;
  2053. UCHAR tc;
  2054. UCHAR fc;
  2055. for ( i = 0; i < 4; i++ )
  2056. {
  2057. tc = (UCHAR) *Tag++;
  2058. fc = (UCHAR) *Filter++;
  2059. if ( fc == '*' ) return S_OK;
  2060. if ( fc == '?' ) continue;
  2061. if (i == 3 && (tc & ~(PROTECTED_POOL >> 24)) == fc) continue;
  2062. if ( tc != fc ) return S_FALSE;
  2063. }
  2064. return S_OK;
  2065. }
  2066. HRESULT
  2067. AccumAllFilter(
  2068. ULONG64 PoolAddr,
  2069. ULONG TagFilter,
  2070. ULONG64 PoolHeader,
  2071. PDEBUG_VALUE Tag,
  2072. ULONG BlockSize,
  2073. BOOL bQuotaWithTag,
  2074. PVOID Context
  2075. )
  2076. {
  2077. HRESULT hr;
  2078. DEBUG_VALUE PoolType;
  2079. PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)Context;
  2080. if (AllocStatsAccum == NULL)
  2081. {
  2082. return E_INVALIDARG;
  2083. }
  2084. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType.I32);
  2085. if (hr == S_OK)
  2086. {
  2087. if (PoolType.I32 == 0)
  2088. {
  2089. AllocStatsAccum->Free++;
  2090. AllocStatsAccum->FreeSize += BlockSize;
  2091. }
  2092. else
  2093. {
  2094. DEBUG_VALUE PoolIndex;
  2095. if (!NewPool)
  2096. {
  2097. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex.I32);
  2098. }
  2099. if (hr == S_OK)
  2100. {
  2101. if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80))
  2102. {
  2103. AllocStatsAccum->Allocated++;
  2104. AllocStatsAccum->AllocatedSize += BlockSize;
  2105. if (AllocStatsAccum->Allocated % 100 == 0)
  2106. {
  2107. ExtOut(".");
  2108. if (AllocStatsAccum->Allocated % 8000 == 0)
  2109. {
  2110. ExtOut("\n");
  2111. }
  2112. }
  2113. }
  2114. else
  2115. {
  2116. AllocStatsAccum->Free++;
  2117. AllocStatsAccum->FreeSize += BlockSize;
  2118. }
  2119. }
  2120. else
  2121. {
  2122. AllocStatsAccum->Indeterminate++;
  2123. AllocStatsAccum->IndeterminateSize += BlockSize;
  2124. }
  2125. }
  2126. }
  2127. else
  2128. {
  2129. AllocStatsAccum->Indeterminate++;
  2130. AllocStatsAccum->IndeterminateSize += BlockSize;
  2131. }
  2132. return hr;
  2133. }
  2134. HRESULT
  2135. CheckPrintAndAccumFilter(
  2136. ULONG64 PoolAddr,
  2137. ULONG TagFilter,
  2138. ULONG64 PoolHeader,
  2139. PDEBUG_VALUE Tag,
  2140. ULONG BlockSize,
  2141. BOOL bQuotaWithTag,
  2142. PVOID Context
  2143. )
  2144. {
  2145. HRESULT hr;
  2146. DEBUG_VALUE PoolType;
  2147. PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)Context;
  2148. if (CheckSingleFilter(Tag->RawBytes, (PUCHAR)&TagFilter) != S_OK)
  2149. {
  2150. return S_FALSE;
  2151. }
  2152. ExtOut("0x%p size: %5lx ",//previous size: %4lx ",
  2153. PoolAddr,
  2154. BlockSize << POOL_BLOCK_SHIFT/*,
  2155. PreviousSize << POOL_BLOCK_SHIFT*/);
  2156. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType.I32);
  2157. if (hr == S_OK)
  2158. {
  2159. if (PoolType.I32 == 0)
  2160. {
  2161. //
  2162. // "Free " with a space after it before the parentheses means
  2163. // it's been freed to a (pool manager internal) lookaside list.
  2164. // We used to print "Lookaside" but that just confused driver
  2165. // writers because they didn't know if this meant in use or not
  2166. // and many would say "but I don't use lookaside lists - the
  2167. // extension or kernel is broken".
  2168. //
  2169. // "Free" with no space after it before the parentheses means
  2170. // it is not on a pool manager internal lookaside list and is
  2171. // instead on the regular pool manager internal flink/blink
  2172. // chains.
  2173. //
  2174. // Note to anyone using the pool package, these 2 terms are
  2175. // equivalent. The fine distinction is only for those actually
  2176. // writing pool internal code.
  2177. //
  2178. ExtOut(" (Free)");
  2179. ExtOut(" %c%c%c%c\n",
  2180. Tag->RawBytes[0],
  2181. Tag->RawBytes[1],
  2182. Tag->RawBytes[2],
  2183. Tag->RawBytes[3]
  2184. );
  2185. if (AllocStatsAccum != NULL)
  2186. {
  2187. AllocStatsAccum->Free++;
  2188. AllocStatsAccum->FreeSize += BlockSize;
  2189. }
  2190. }
  2191. else
  2192. {
  2193. DEBUG_VALUE PoolIndex;
  2194. DEBUG_VALUE ProcessBilled;
  2195. if (!NewPool)
  2196. {
  2197. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex.I32);
  2198. }
  2199. if (hr == S_OK)
  2200. {
  2201. if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80))
  2202. {
  2203. ExtOut(" (Allocated)");
  2204. if (AllocStatsAccum != NULL)
  2205. {
  2206. AllocStatsAccum->Allocated++;
  2207. AllocStatsAccum->AllocatedSize += BlockSize;
  2208. }
  2209. }
  2210. else
  2211. {
  2212. //
  2213. // "Free " with a space after it before the parentheses means
  2214. // it's been freed to a (pool manager internal) lookaside list.
  2215. // We used to print "Lookaside" but that just confused driver
  2216. // writers because they didn't know if this meant in use or not
  2217. // and many would say "but I don't use lookaside lists - the
  2218. // extension or kernel is broken".
  2219. //
  2220. // "Free" with no space after it before the parentheses means
  2221. // it is not on a pool manager internal lookaside list and is
  2222. // instead on the regular pool manager internal flink/blink
  2223. // chains.
  2224. //
  2225. // Note to anyone using the pool package, these 2 terms are
  2226. // equivalent. The fine distinction is only for those actually
  2227. // writing pool internal code.
  2228. //
  2229. ExtOut(" (Free ) ");
  2230. if (AllocStatsAccum != NULL)
  2231. {
  2232. AllocStatsAccum->Free++;
  2233. AllocStatsAccum->FreeSize += BlockSize;
  2234. }
  2235. }
  2236. }
  2237. else
  2238. {
  2239. ExtOut(" (?) ");
  2240. if (AllocStatsAccum != NULL)
  2241. {
  2242. AllocStatsAccum->Indeterminate++;
  2243. AllocStatsAccum->IndeterminateSize += BlockSize;
  2244. }
  2245. }
  2246. if (!(PoolType.I32 & POOL_QUOTA_MASK) ||
  2247. bQuotaWithTag)
  2248. {
  2249. ExtOut(" %c%c%c%c%s",
  2250. Tag->RawBytes[0],
  2251. Tag->RawBytes[1],
  2252. Tag->RawBytes[2],
  2253. (Tag->RawBytes[3] & ~(PROTECTED_POOL >> 24)),
  2254. ((Tag->I32 & PROTECTED_POOL) ? " (Protected)" : "")
  2255. );
  2256. }
  2257. if (PoolType.I32 & POOL_QUOTA_MASK &&
  2258. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "ProcessBilled", ProcessBilled.I64) == S_OK &&
  2259. ProcessBilled.I64 != 0)
  2260. {
  2261. ExtOut(" Process: 0x%p\n", ProcessBilled.I64);
  2262. }
  2263. else
  2264. {
  2265. ExtOut("\n");
  2266. }
  2267. }
  2268. }
  2269. else
  2270. {
  2271. ExtErr(" Couldn't determine PoolType\n");
  2272. if (AllocStatsAccum != NULL)
  2273. {
  2274. AllocStatsAccum->Indeterminate++;
  2275. AllocStatsAccum->IndeterminateSize += BlockSize;
  2276. }
  2277. }
  2278. return hr;
  2279. }
  2280. typedef struct _TAG_BUCKET : public ALLOCATION_STATS {
  2281. ULONG Tag;
  2282. _TAG_BUCKET *pNextTag;
  2283. } TAG_BUCKET, *PTAG_BUCKET;
  2284. typedef enum {
  2285. AllocatedPool,
  2286. FreePool,
  2287. IndeterminatePool,
  2288. } PoolType;
  2289. class AccumTagUsage : public ALLOCATION_STATS {
  2290. public:
  2291. AccumTagUsage(ULONG TagFilter);
  2292. ~AccumTagUsage();
  2293. HRESULT Valid();
  2294. HRESULT Add(ULONG Tag, PoolType Type, ULONG Size);
  2295. HRESULT OutputResults(BOOL TagSort);
  2296. void Reset();
  2297. private:
  2298. ULONG GetHashIndex(ULONG Tag);
  2299. PTAG_BUCKET GetBucket(ULONG Tag);
  2300. ULONG SetTagFilter(ULONG TagFilter);
  2301. static const HashBitmaskLimit = 10; // For little-endian, must <= 16
  2302. HANDLE hHeap;
  2303. ULONG Buckets;
  2304. PTAG_BUCKET *Bucket; // Array of buckets
  2305. #if BIG_ENDIAN
  2306. ULONG HighMask;
  2307. ULONG HighShift;
  2308. ULONG LowMask;
  2309. ULONG LowShift;
  2310. #else
  2311. ULONG HighShiftLeft;
  2312. ULONG HighShiftRight;
  2313. ULONG LowShiftRight;
  2314. ULONG LowMask;
  2315. #endif
  2316. };
  2317. AccumTagUsage::AccumTagUsage(
  2318. ULONG TagFilter
  2319. )
  2320. {
  2321. hHeap = GetProcessHeap();
  2322. Buckets = SetTagFilter(TagFilter);
  2323. if (Buckets != 0)
  2324. {
  2325. Bucket = (PTAG_BUCKET *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, Buckets*sizeof(*Bucket));
  2326. Reset();
  2327. }
  2328. else
  2329. {
  2330. Bucket = NULL;
  2331. }
  2332. }
  2333. AccumTagUsage::~AccumTagUsage()
  2334. {
  2335. PTAG_BUCKET pB, pBNext;
  2336. ULONG i;
  2337. if (Bucket != NULL)
  2338. {
  2339. for (i = 0; i < Buckets; i++)
  2340. {
  2341. pB = Bucket[i];
  2342. while (pB != NULL)
  2343. {
  2344. pBNext = pB->pNextTag;
  2345. HeapFree(hHeap, 0, pB);
  2346. pB = pBNext;
  2347. }
  2348. }
  2349. HeapFree(hHeap, 0, Bucket);
  2350. }
  2351. }
  2352. HRESULT
  2353. AccumTagUsage::Valid()
  2354. {
  2355. return ((Bucket != NULL) ? S_OK : S_FALSE);
  2356. }
  2357. HRESULT
  2358. AccumTagUsage::Add(
  2359. ULONG Tag,
  2360. PoolType Type,
  2361. ULONG Size
  2362. )
  2363. {
  2364. PTAG_BUCKET pBucket = GetBucket(Tag);
  2365. if (pBucket == NULL) return E_FAIL;
  2366. switch (Type)
  2367. {
  2368. case AllocatedPool:
  2369. pBucket->Allocated++;
  2370. pBucket->AllocatedSize += Size;
  2371. break;
  2372. case FreePool:
  2373. pBucket->Free++;
  2374. pBucket->FreeSize += Size;
  2375. break;
  2376. case IndeterminatePool:
  2377. default:
  2378. pBucket->Indeterminate++;
  2379. pBucket->IndeterminateSize += Size;
  2380. break;
  2381. }
  2382. return S_OK;
  2383. }
  2384. HRESULT
  2385. AccumTagUsage::OutputResults(
  2386. BOOL AllocSort
  2387. )
  2388. {
  2389. HRESULT hr;
  2390. PTAG_BUCKET pB, pBNext;
  2391. ULONG i;
  2392. if (Bucket == NULL)
  2393. {
  2394. ExtOut(" No results\n");
  2395. }
  2396. else
  2397. {
  2398. CHAR szNormal[] = "%4.4s %8lu %12I64u %8lu %12I64u\n";
  2399. CHAR szShowIndeterminate[] = "%4.4s %8lu %12I64u %8lu %12I64u %8lu %12I64u\n";
  2400. PSZ pszOutFormat = szNormal;
  2401. ExtOut("\n"
  2402. " %I64u bytes in %lu allocated pages\n"
  2403. " %I64u bytes in %lu large allocations\n"
  2404. " %I64u bytes in %lu free pages\n"
  2405. " %I64u bytes available in %lu expansion pages\n",
  2406. ((ULONG64) AllocatedPages) << PageShift,
  2407. AllocatedPages,
  2408. ((ULONG64) LargePages) << PageShift,
  2409. LargeAllocs,
  2410. ((ULONG64) FreePages) << PageShift,
  2411. FreePages,
  2412. ((ULONG64) ExpansionPages) << PageShift,
  2413. ExpansionPages);
  2414. ExtOut("\nTag Allocs Bytes Freed Bytes");
  2415. if (Indeterminate != 0)
  2416. {
  2417. ExtOut(" Unknown Bytes");
  2418. pszOutFormat = szShowIndeterminate;
  2419. }
  2420. ExtOut("\n");
  2421. if (AllocSort)
  2422. {
  2423. ExtWarn(" Sorting by allocation size isn't supported.\n");
  2424. }
  2425. //else
  2426. {
  2427. // Output results sorted by Tag (natural storage order)
  2428. for (i = 0; i < Buckets; i++)
  2429. {
  2430. for (pB = Bucket[i]; pB != NULL; pB = pB->pNextTag)
  2431. {
  2432. if (pB->Allocated)
  2433. {
  2434. ExtOut(pszOutFormat,
  2435. &pB->Tag,
  2436. pB->Allocated, ((ULONG64)pB->AllocatedSize) << POOL_BLOCK_SHIFT,
  2437. pB->Free, ((ULONG64)pB->FreeSize) << POOL_BLOCK_SHIFT,
  2438. pB->Indeterminate, ((ULONG64)pB->IndeterminateSize) << POOL_BLOCK_SHIFT
  2439. );
  2440. }
  2441. }
  2442. }
  2443. }
  2444. ExtOut("-------------------------------------------------------------------------------\n");
  2445. ExtOut(pszOutFormat,
  2446. "Ttl:",
  2447. Allocated, ((ULONG64)AllocatedSize) << POOL_BLOCK_SHIFT,
  2448. Free, ((ULONG64)FreeSize) << POOL_BLOCK_SHIFT,
  2449. Indeterminate, ((ULONG64)IndeterminateSize) << POOL_BLOCK_SHIFT
  2450. );
  2451. }
  2452. return S_OK;
  2453. }
  2454. void
  2455. AccumTagUsage::Reset()
  2456. {
  2457. PTAG_BUCKET pB, pBNext;
  2458. ULONG i;
  2459. AllocatedPages = 0;
  2460. LargePages = 0;
  2461. LargeAllocs = 0;
  2462. FreePages = 0;
  2463. ExpansionPages = 0;
  2464. Allocated = 0;
  2465. AllocatedSize = 0;
  2466. Free = 0;
  2467. FreeSize = 0;
  2468. Indeterminate = 0;
  2469. IndeterminateSize = 0;
  2470. if (Bucket != NULL)
  2471. {
  2472. for (i = 0; i < Buckets; i++)
  2473. {
  2474. pB = Bucket[i];
  2475. if (pB != NULL)
  2476. {
  2477. do
  2478. {
  2479. pBNext = pB->pNextTag;
  2480. HeapFree(hHeap, 0, pB);
  2481. pB = pBNext;
  2482. } while (pB != NULL);
  2483. Bucket[i] = NULL;
  2484. }
  2485. }
  2486. }
  2487. }
  2488. ULONG
  2489. AccumTagUsage::GetHashIndex(
  2490. ULONG Tag
  2491. )
  2492. {
  2493. #if BIG_ENDIAN
  2494. return (((Tag & HighMask) >> HighShift) | ((Tag & LowMask) >> LowShift));
  2495. #else
  2496. return ((((Tag << HighShiftLeft) >> HighShiftRight) & ~LowMask) | ((Tag >> LowShiftRight) & LowMask));
  2497. #endif
  2498. }
  2499. PTAG_BUCKET
  2500. AccumTagUsage::GetBucket(
  2501. ULONG Tag
  2502. )
  2503. {
  2504. ULONG Index = GetHashIndex(Tag);
  2505. PTAG_BUCKET pB = Bucket[Index];
  2506. if (pB == NULL ||
  2507. #if BIG_ENDIAN
  2508. pB->Tag > Tag
  2509. #else
  2510. strncmp((char *)&pB->Tag, (char *)&Tag, 4) > 0
  2511. #endif
  2512. )
  2513. {
  2514. pB = (PTAG_BUCKET)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(TAG_BUCKET));
  2515. if (pB != NULL)
  2516. {
  2517. pB->Tag = Tag;
  2518. pB->pNextTag = Bucket[Index];
  2519. Bucket[Index] = pB;
  2520. }
  2521. }
  2522. else
  2523. {
  2524. while (pB->pNextTag != NULL)
  2525. {
  2526. if (
  2527. #if BIG_ENDIAN
  2528. pB->pNextTag->Tag > Tag
  2529. #else
  2530. strncmp((char *)&pB->pNextTag->Tag, (char *)&Tag, 4) > 0
  2531. #endif
  2532. )
  2533. {
  2534. break;
  2535. }
  2536. pB = pB->pNextTag;
  2537. }
  2538. if (pB->Tag != Tag)
  2539. {
  2540. PTAG_BUCKET pBPrev = pB;
  2541. pB = (PTAG_BUCKET)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(TAG_BUCKET));
  2542. if (pB != NULL)
  2543. {
  2544. pB->Tag = Tag;
  2545. pB->pNextTag = pBPrev->pNextTag;
  2546. pBPrev->pNextTag = pB;
  2547. }
  2548. }
  2549. }
  2550. return pB;
  2551. }
  2552. ULONG
  2553. AccumTagUsage::SetTagFilter(
  2554. ULONG TagFilter
  2555. )
  2556. {
  2557. ULONG NumBuckets;
  2558. UCHAR *Filter = (UCHAR *)&TagFilter;
  2559. ULONG i;
  2560. ULONG HighMaskBits, LowMaskBits;
  2561. UCHAR fc;
  2562. #if BIG_ENDIAN
  2563. ULONG Mask = 0;
  2564. ULONG MaskBits = 0;
  2565. if (Filter[0] == '*')
  2566. {
  2567. Mask = -1;
  2568. MaskBits = 32;
  2569. }
  2570. else
  2571. {
  2572. for ( i = 0; i < 32; i += 8 )
  2573. {
  2574. Mask <<= 8;
  2575. fc = *Filter++;
  2576. if ( fc == '*' )
  2577. {
  2578. Mask |= ((1 << i) - 1);
  2579. MaskBits += 32 - i;
  2580. break;
  2581. }
  2582. if ( fc == '?' )
  2583. {
  2584. Mask |= 0xFF;
  2585. MaskBits += 8;
  2586. }
  2587. }
  2588. }
  2589. if (MaskBits > HashBitmaskLimit)
  2590. {
  2591. MaskBits = HashBitmaskLimit;
  2592. }
  2593. NumBuckets = (1 << MaskBits);
  2594. for (HighShift = 32, HighMaskBits = 0;
  2595. HighShift > 0 && HighMaskBits < MaskBits;
  2596. HighShift--)
  2597. {
  2598. if (Mask & (1 << (HighShift-1)))
  2599. {
  2600. HighMaskBits++;
  2601. }
  2602. else if (HighMaskBits)
  2603. {
  2604. break;
  2605. }
  2606. }
  2607. HighMask = Mask & ~((1 << HighShift) - 1);
  2608. Mask &= ~HighMask;
  2609. MaskBits -= HighMaskBits;
  2610. HighShift -= MaskBits;
  2611. for (LowShift = HighShift, LowMaskBits = 0;
  2612. LowShift > 0 && LowMaskBits < MaskBits;
  2613. LowShift--)
  2614. {
  2615. if (Mask & (1 << (LowShift-1)))
  2616. {
  2617. LowMaskBits++;
  2618. }
  2619. else if (LowMaskBits)
  2620. {
  2621. break;
  2622. }
  2623. }
  2624. LowMask = Mask & ~((1 << LowShift) - 1);
  2625. #else
  2626. HighMaskBits = 0;
  2627. LowMaskBits = 0;
  2628. HighShiftLeft = 32;
  2629. HighShiftRight = 32;
  2630. LowShiftRight = 32;
  2631. LowMask = 0;
  2632. for ( i = 0; i < 32; i += 8 )
  2633. {
  2634. fc = *Filter++;
  2635. if ( fc == '*' )
  2636. {
  2637. if (HighMaskBits == 0)
  2638. {
  2639. HighMaskBits = min(8, HashBitmaskLimit);
  2640. HighShiftLeft = 32 - HighMaskBits - i;
  2641. HighShiftRight = 32 - HighMaskBits;
  2642. LowMaskBits = ((HighShiftLeft != 0) ?
  2643. min(8, HashBitmaskLimit - HighMaskBits) :
  2644. 0);
  2645. HighShiftRight -= LowMaskBits;
  2646. LowShiftRight = (8 - LowMaskBits) + HighMaskBits + i;
  2647. LowMask = (1 << LowMaskBits) - 1;
  2648. }
  2649. else
  2650. {
  2651. LowMaskBits = min(8, HashBitmaskLimit - HighMaskBits);
  2652. HighShiftRight -= LowMaskBits;
  2653. LowShiftRight = (8 - LowMaskBits) + i;
  2654. LowMask = (1 << LowMaskBits) - 1;
  2655. }
  2656. break;
  2657. }
  2658. if ( fc == '?' )
  2659. {
  2660. if (HighMaskBits == 0)
  2661. {
  2662. HighMaskBits = min(8, HashBitmaskLimit);
  2663. HighShiftLeft = 32 - HighMaskBits - i;
  2664. HighShiftRight = 32 - HighMaskBits;
  2665. }
  2666. else
  2667. {
  2668. LowMaskBits = min(8, HashBitmaskLimit - HighMaskBits);
  2669. HighShiftRight -= LowMaskBits;
  2670. LowShiftRight = (8 - LowMaskBits) + i;
  2671. LowMask = (1 << LowMaskBits) - 1;
  2672. break;
  2673. }
  2674. }
  2675. }
  2676. NumBuckets = 1 << (HighMaskBits + LowMaskBits);
  2677. #endif
  2678. if (NumBuckets-1 != GetHashIndex(-1))
  2679. {
  2680. DbgPrint("AccumTagUsage::SetTagFilter: Invalid hash was generated.\n");
  2681. NumBuckets = 0;
  2682. }
  2683. return NumBuckets;
  2684. }
  2685. HRESULT
  2686. AccumTagUsageFilter(
  2687. ULONG64 PoolAddr,
  2688. ULONG TagFilter,
  2689. ULONG64 PoolHeader,
  2690. PDEBUG_VALUE Tag,
  2691. ULONG BlockSize,
  2692. BOOL bQuotaWithTag,
  2693. PVOID Context
  2694. )
  2695. {
  2696. HRESULT hr;
  2697. DEBUG_VALUE PoolType;
  2698. AccumTagUsage *atu = (AccumTagUsage *)Context;
  2699. PALLOCATION_STATS AllocStatsAccum = (PALLOCATION_STATS)atu;
  2700. if (CheckSingleFilter(Tag->RawBytes, (PUCHAR)&TagFilter) != S_OK)
  2701. {
  2702. return S_FALSE;
  2703. }
  2704. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType.I32);
  2705. if (hr == S_OK)
  2706. {
  2707. if (PoolType.I32 == 0)
  2708. {
  2709. hr = atu->Add(Tag->I32, FreePool, BlockSize);
  2710. AllocStatsAccum->Free++;
  2711. AllocStatsAccum->FreeSize += BlockSize;
  2712. }
  2713. else
  2714. {
  2715. DEBUG_VALUE PoolIndex;
  2716. if (!(PoolType.I32 & POOL_QUOTA_MASK) ||
  2717. bQuotaWithTag)
  2718. {
  2719. Tag->I32 &= ~PROTECTED_POOL;
  2720. }
  2721. else if (PoolType.I32 & POOL_QUOTA_MASK)
  2722. {
  2723. Tag->I32 = 'CORP';
  2724. }
  2725. if (!NewPool)
  2726. {
  2727. hr = GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex.I32);
  2728. }
  2729. if (hr == S_OK)
  2730. {
  2731. if (NewPool ? (PoolType.I32 & 0x04) : (PoolIndex.I32 & 0x80))
  2732. {
  2733. hr = atu->Add(Tag->I32, AllocatedPool, BlockSize);
  2734. AllocStatsAccum->Allocated++;
  2735. AllocStatsAccum->AllocatedSize += BlockSize;
  2736. if (AllocStatsAccum->Allocated % 100 == 0)
  2737. {
  2738. ExtOut(".");
  2739. if (AllocStatsAccum->Allocated % 8000 == 0)
  2740. {
  2741. ExtOut("\n");
  2742. }
  2743. }
  2744. }
  2745. else
  2746. {
  2747. hr = atu->Add(Tag->I32, FreePool, BlockSize);
  2748. AllocStatsAccum->Free++;
  2749. AllocStatsAccum->FreeSize += BlockSize;
  2750. }
  2751. }
  2752. else
  2753. {
  2754. hr = atu->Add(Tag->I32, IndeterminatePool, BlockSize);
  2755. AllocStatsAccum->Indeterminate++;
  2756. AllocStatsAccum->IndeterminateSize += BlockSize;
  2757. }
  2758. }
  2759. }
  2760. else
  2761. {
  2762. AllocStatsAccum->Indeterminate++;
  2763. AllocStatsAccum->IndeterminateSize += BlockSize;
  2764. }
  2765. return hr;
  2766. }
  2767. HRESULT
  2768. SearchSessionPool(
  2769. PDEBUG_CLIENT Client,
  2770. ULONG Session,
  2771. ULONG TagName,
  2772. FLONG Flags,
  2773. ULONG64 RestartAddr,
  2774. PoolFilterFunc Filter,
  2775. PALLOCATION_STATS AllocStats,
  2776. PVOID Context
  2777. )
  2778. /*++
  2779. Routine Description:
  2780. Engine to search session pool.
  2781. Arguments:
  2782. TagName - Supplies the tag to search for.
  2783. Flags - Supplies 0 if a nonpaged pool search is desired.
  2784. Supplies 1 if a paged pool search is desired.
  2785. RestartAddr - Supplies the address to restart the search from.
  2786. Filter - Supplies the filter routine to use.
  2787. Context - Supplies the user defined context blob.
  2788. Return Value:
  2789. HRESULT
  2790. --*/
  2791. {
  2792. HRESULT hr;
  2793. PDEBUG_SYMBOLS Symbols;
  2794. PDEBUG_DATA_SPACES Data;
  2795. LOGICAL PhysicallyContiguous;
  2796. ULONG PoolBlockSize;
  2797. ULONG64 PoolHeader;
  2798. ULONG64 PoolPage;
  2799. ULONG64 StartPage;
  2800. ULONG64 Pool;
  2801. ULONG Previous;
  2802. ULONG64 PoolStart;
  2803. ULONG64 PoolStartPage;
  2804. ULONG64 PoolPteAddress;
  2805. ULONG64 PoolEnd;
  2806. BOOL PageReadFailed;
  2807. ULONG64 PagesRead;
  2808. ULONG64 PageReadFailures;
  2809. ULONG64 PageReadFailuresAtEnd;
  2810. ULONG64 LastPageRead;
  2811. ULONG PoolTypeFlags = Flags & (SEARCH_POOL_NONPAGED | SEARCH_POOL_PAGED);
  2812. ULONG64 NTModuleBase;
  2813. ULONG PoolHeadTypeID;
  2814. ULONG SessionHeadTypeID;
  2815. ULONG HdrSize;
  2816. ULONG64 SessionSpace;
  2817. if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  2818. (void **)&Symbols)) != S_OK)
  2819. {
  2820. return hr;
  2821. }
  2822. if ((hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  2823. (void **)&Data)) != S_OK)
  2824. {
  2825. Symbols->Release();
  2826. return hr;
  2827. }
  2828. if (Session == DEFAULT_SESSION)
  2829. {
  2830. Session = SessionId;
  2831. }
  2832. if ((hr = Symbols->GetSymbolTypeId("NT!_POOL_HEADER", &PoolHeadTypeID, &NTModuleBase)) == S_OK &&
  2833. (hr = Symbols->GetTypeSize(NTModuleBase, PoolHeadTypeID, & HdrSize)) == S_OK &&
  2834. (hr = GetSessionSpace(Session, &SessionSpace, NULL)) == S_OK)
  2835. {
  2836. ULONG PoolTagOffset, ProcessBilledOffset;
  2837. BOOL bQuotaWithTag;
  2838. ULONG ReadSessionId;
  2839. ULONG64 PagedPoolInfo;
  2840. ULONG64 NonPagedPoolBytes;
  2841. ULONG64 NonPagedPoolAllocations;
  2842. ULONG64 NonPagedPoolStart;
  2843. ULONG64 NonPagedPoolEnd;
  2844. ULONG64 PagedPoolPages;
  2845. ULONG64 PagedPoolBytes;
  2846. ULONG64 PagedPoolAllocations;
  2847. ULONG64 PagedPoolStart;
  2848. ULONG64 PagedPoolEnd;
  2849. ULONG SessionSpaceTypeID;
  2850. ULONG PagedPoolInfoOffset;
  2851. BOOL SearchingPaged = FALSE;
  2852. PRTL_BITMAP PagedPoolAllocationMap = NULL;
  2853. PRTL_BITMAP EndOfPagedPoolBitmap = NULL;
  2854. ULONG BusyStart;
  2855. PRTL_BITMAP PagedPoolLargeSessionAllocationMap = NULL;
  2856. BOOL Continue = TRUE;
  2857. bQuotaWithTag = (Symbols->GetFieldOffset(NTModuleBase, PoolHeadTypeID, "PoolTag", &PoolTagOffset) == S_OK &&
  2858. Symbols->GetFieldOffset(NTModuleBase, PoolHeadTypeID, "ProcessBilled", &ProcessBilledOffset) == S_OK &&
  2859. PoolTagOffset != ProcessBilledOffset);
  2860. // General parser setup and dump MM_SESSION_SPACE structure
  2861. if ((hr = Symbols->GetTypeId(NTModuleBase, "MM_SESSION_SPACE", &SessionSpaceTypeID)) == S_OK &&
  2862. (hr = GetFieldValue(SessionSpace, "nt!MM_SESSION_SPACE", "SessionId", ReadSessionId)) == S_OK &&
  2863. (hr = Symbols->GetFieldOffset(NTModuleBase, SessionSpaceTypeID, "PagedPoolInfo", &PagedPoolInfoOffset)) == S_OK &&
  2864. (InitTypeRead(SessionSpace, nt!MM_SESSION_SPACE) == S_OK)
  2865. // (hr = OutState.OutputTypeVirtual(SessionSpace + PagedPoolInfoOffset, "NT!_MM_PAGED_POOL_INFO", 0)) == S_OK
  2866. )
  2867. {
  2868. ExtOut("Searching session %ld pool.\n", ReadSessionId);
  2869. // Remaining type output goes to PoolHead reader
  2870. }
  2871. else
  2872. {
  2873. ExtErr("Error getting basic session pool information.\n");
  2874. }
  2875. while (hr == S_OK && Continue)
  2876. {
  2877. ExtOut("\n");
  2878. if (PoolTypeFlags & SEARCH_POOL_NONPAGED)
  2879. {
  2880. NonPagedPoolBytes = ReadField(NonPagedPoolBytes);// NOFIELD
  2881. NonPagedPoolAllocations = ReadField(NonPagedPoolAllocations);// NOFIELD
  2882. if (NonPagedPoolBytes != 0 &&
  2883. NonPagedPoolAllocations != 0)
  2884. {
  2885. ExtOut("NonPaged pool: %I64u bytes in %I64u allocations\n",
  2886. NonPagedPoolBytes, NonPagedPoolAllocations);
  2887. }
  2888. ExtOut(" NonPaged pool range reader isn't implemented.\n");
  2889. PoolStart = 0;
  2890. PoolEnd = 0;
  2891. SearchingPaged = FALSE;
  2892. }
  2893. else
  2894. {
  2895. PagedPoolBytes = ReadField(PagedPoolBytes); // NOFIELD
  2896. PagedPoolAllocations = ReadField(PagedPoolAllocations); // NOFIELD
  2897. if (PagedPoolBytes != 0 &&
  2898. PagedPoolAllocations != 0)
  2899. {
  2900. ExtOut("Paged pool: %I64u bytes in %I64u allocations\n",
  2901. PagedPoolBytes, PagedPoolAllocations);
  2902. PagedPoolPages = ReadField(AllocatedPagedPool); // NOFIELD
  2903. if (PagedPoolPages != 0)
  2904. {
  2905. ExtOut(" Paged Pool Info: %I64u pages allocated\n",
  2906. PagedPoolPages);
  2907. }
  2908. }
  2909. PagedPoolStart = ReadField(PagedPoolStart);
  2910. PagedPoolEnd = ReadField(PagedPoolEnd);
  2911. if (PagedPoolStart == 0 || PagedPoolEnd == 0)
  2912. {
  2913. ExtErr(" Couldn't get PagedPool range.\n");
  2914. }
  2915. else
  2916. {
  2917. PoolStart = PagedPoolStart;
  2918. PoolEnd = PagedPoolEnd;
  2919. SearchingPaged = TRUE;
  2920. ULONG64 PagedBitMap, EndOfPagedBitMap;
  2921. PagedBitMap = ReadField(PagedPoolInfo.PagedPoolAllocationMap);
  2922. EndOfPagedBitMap = ReadField(PagedPoolInfo.EndOfPagedPoolBitmap);
  2923. if (GetBitMap(Client, PagedBitMap, &PagedPoolAllocationMap) == S_OK &&
  2924. GetBitMap(Client, EndOfPagedBitMap, &EndOfPagedPoolBitmap) == S_OK)
  2925. {
  2926. ULONG PositionAfterLastAlloc;
  2927. ULONG AllocBits;
  2928. ULONG UnusedBusyBits;
  2929. if (RtlCheckBit(EndOfPagedPoolBitmap, EndOfPagedPoolBitmap->SizeOfBitMap - 1))
  2930. {
  2931. BusyStart = PagedPoolAllocationMap->SizeOfBitMap;
  2932. UnusedBusyBits = 0;
  2933. }
  2934. else
  2935. {
  2936. OSCompat_RtlFindLastBackwardRunClear(
  2937. EndOfPagedPoolBitmap,
  2938. EndOfPagedPoolBitmap->SizeOfBitMap - 1,
  2939. &PositionAfterLastAlloc);
  2940. BusyStart = RtlFindSetBits(PagedPoolAllocationMap, 1, PositionAfterLastAlloc);
  2941. if (BusyStart < PositionAfterLastAlloc || BusyStart == -1)
  2942. {
  2943. BusyStart = PagedPoolAllocationMap->SizeOfBitMap;
  2944. UnusedBusyBits = 0;
  2945. }
  2946. else
  2947. {
  2948. UnusedBusyBits = PagedPoolAllocationMap->SizeOfBitMap - BusyStart;
  2949. }
  2950. }
  2951. AllocBits = RtlNumberOfSetBits(PagedPoolAllocationMap) - UnusedBusyBits;
  2952. AllocStats->AllocatedPages += AllocBits;
  2953. AllocStats->FreePages += (BusyStart - AllocBits);
  2954. AllocStats->ExpansionPages += UnusedBusyBits;
  2955. PagedBitMap = ReadField(PagedPoolInfo.PagedPoolLargeSessionAllocationMap); // NOFIELD
  2956. if (PagedBitMap != 0 &&
  2957. GetBitMap(Client, PagedBitMap, &PagedPoolLargeSessionAllocationMap) == S_OK)
  2958. {
  2959. ULONG AllocStart, AllocEnd;
  2960. ULONG LargeAllocs = RtlNumberOfSetBits(PagedPoolLargeSessionAllocationMap);
  2961. AllocStats->LargeAllocs += LargeAllocs;
  2962. AllocStart = 0;
  2963. AllocEnd = -1;
  2964. while (LargeAllocs > 0)
  2965. {
  2966. AllocStart = RtlFindSetBits(PagedPoolLargeSessionAllocationMap, 1, AllocStart);
  2967. if (AllocStart >= AllocEnd+1 && AllocStart != -1)
  2968. {
  2969. AllocEnd = RtlFindSetBits(EndOfPagedPoolBitmap, 1, AllocStart);
  2970. if (AllocEnd >= AllocStart && AllocEnd != -1)
  2971. {
  2972. AllocStats->LargePages += AllocEnd - AllocStart + 1;
  2973. AllocStart++;
  2974. LargeAllocs--;
  2975. }
  2976. else
  2977. {
  2978. ExtWarn(" Warning Large Pool Allocation Map or End Of Pool Map is invalid.\n");
  2979. break;
  2980. }
  2981. }
  2982. else
  2983. {
  2984. ExtWarn(" Warning Large Pool Allocation Map is invalid.\n");
  2985. break;
  2986. }
  2987. }
  2988. if (LargeAllocs != 0)
  2989. {
  2990. ExtWarn(" %lu large allocations weren't calculated.\n", LargeAllocs);
  2991. AllocStats->LargeAllocs -= LargeAllocs;
  2992. }
  2993. }
  2994. }
  2995. }
  2996. }
  2997. if (hr == S_OK)
  2998. {
  2999. ExtOut("Searching %s pool (0x%p : 0x%p) for Tag: %c%c%c%c\r\n\n",
  3000. ((PoolTypeFlags & SEARCH_POOL_NONPAGED) ? "NonPaged" : "Paged"),
  3001. PoolStart,
  3002. PoolEnd,
  3003. TagName,
  3004. TagName >> 8,
  3005. TagName >> 16,
  3006. TagName >> 24);
  3007. PageReadFailed = FALSE;
  3008. PoolStartPage = PAGE_ALIGN64(PoolStart);
  3009. PoolPage = PoolStart;
  3010. PagesRead = 0;
  3011. PageReadFailures = 0;
  3012. PageReadFailuresAtEnd = 0;
  3013. LastPageRead = PAGE_ALIGN64(PoolPage);
  3014. while (PoolPage < PoolEnd && hr == S_OK)
  3015. {
  3016. Pool = PAGE_ALIGN64(PoolPage);
  3017. StartPage = Pool;
  3018. Previous = 0;
  3019. if (Session != CURRENT_SESSION)
  3020. {
  3021. ExtOut("Currently only searching the current session is supported.\n");
  3022. PoolPage = PoolEnd;
  3023. break;
  3024. }
  3025. if (CheckControlC())
  3026. {
  3027. ExtOut("\n...terminating - searched pool to 0x%p\n",
  3028. Pool-1);
  3029. hr = E_ABORT;
  3030. break;
  3031. }
  3032. if (SearchingPaged)
  3033. {
  3034. if (PagedPoolAllocationMap != NULL)
  3035. {
  3036. ULONG StartPosition, EndPosition;
  3037. StartPosition = (ULONG)((Pool - PoolStartPage) >> PageShift);
  3038. EndPosition = RtlFindSetBits(EndOfPagedPoolBitmap, 1, StartPosition);
  3039. if (EndPosition < StartPosition) EndPosition = -1;
  3040. if (!RtlCheckBit(PagedPoolAllocationMap, StartPosition))
  3041. {
  3042. if (PageReadFailed)
  3043. {
  3044. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3045. {
  3046. ExtWarn(" to 0x%p\n", StartPage-1);
  3047. }
  3048. PageReadFailures += (StartPage - LastPageRead) >> PageShift;
  3049. LastPageRead = StartPage;
  3050. PageReadFailed = FALSE;
  3051. }
  3052. if (EndPosition == -1)
  3053. {
  3054. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3055. {
  3056. ExtWarn("No remaining pool allocations from 0x%p to 0x%p.\n", Pool, PoolEnd);
  3057. }
  3058. PoolPage = PoolEnd;
  3059. }
  3060. else
  3061. {
  3062. PoolPage = PoolStartPage + (((ULONG64)EndPosition + 1) << PageShift);
  3063. }
  3064. continue;
  3065. }
  3066. else if (EndOfPagedPoolBitmap != NULL)
  3067. {
  3068. if (PagedPoolLargeSessionAllocationMap != NULL &&
  3069. RtlCheckBit(PagedPoolLargeSessionAllocationMap, StartPosition))
  3070. {
  3071. if (EndPosition == -1)
  3072. {
  3073. ExtWarn("No end to large pool allocation @ 0x%p found.\n", Pool);
  3074. PoolPage = PoolEnd;
  3075. }
  3076. else
  3077. {
  3078. EndPosition++;
  3079. if (PageReadFailed)
  3080. {
  3081. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3082. {
  3083. ExtWarn(" to 0x%p\n", StartPage-1);
  3084. }
  3085. PageReadFailures += (StartPage - LastPageRead) >> PageShift;
  3086. LastPageRead = StartPage;
  3087. PageReadFailed = FALSE;
  3088. }
  3089. PoolPage = PoolStartPage + (((ULONG64)EndPosition) << PageShift);
  3090. if (Flags & SEARCH_POOL_PRINT_LARGE)
  3091. {
  3092. ExtOut("0x%p size: %5I64x %s UNTAGGED Large\n",
  3093. StartPage,
  3094. PoolPage - StartPage,
  3095. ((RtlAreBitsSet(PagedPoolAllocationMap, StartPosition, EndPosition - StartPosition)) ?
  3096. "(Allocated)" :
  3097. ((RtlAreBitsClear(PagedPoolAllocationMap, StartPosition, EndPosition - StartPosition)) ?
  3098. "(! Free !) " :
  3099. "(!! Partially Allocated !!)"))
  3100. );
  3101. }
  3102. if (Flags & SEARCH_POOL_LARGE_ONLY)
  3103. {
  3104. // Quickly locate next large allocation
  3105. StartPosition = RtlFindSetBits(PagedPoolLargeSessionAllocationMap, 1, EndPosition);
  3106. if (StartPosition < EndPosition || StartPosition == -1)
  3107. {
  3108. ExtVerb(" No large allocations found after 0x%p\n", PoolPage-1);
  3109. PoolPage = PoolEnd;
  3110. }
  3111. else
  3112. {
  3113. PoolPage = PoolStartPage + (((ULONG64)StartPosition) << PageShift);
  3114. }
  3115. }
  3116. }
  3117. continue;
  3118. }
  3119. else if (EndPosition == -1)
  3120. {
  3121. if (PageReadFailed)
  3122. {
  3123. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3124. {
  3125. ExtWarn(" to 0x%p\n", StartPage-1);
  3126. }
  3127. PageReadFailures += (StartPage - LastPageRead) >> PageShift;
  3128. LastPageRead = StartPage;
  3129. PageReadFailed = FALSE;
  3130. }
  3131. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3132. {
  3133. ExtWarn("No remaining pool allocations from 0x%p to 0x%p.\n", Pool, PoolEnd);
  3134. }
  3135. PoolPage = PoolEnd;
  3136. continue;
  3137. }
  3138. else if (StartPosition >= BusyStart)
  3139. {
  3140. ExtWarn("Found end of allocation at %lu within expansion pages starting at %lu.\n",
  3141. EndPosition, BusyStart);
  3142. }
  3143. }
  3144. }
  3145. }
  3146. if (Flags & SEARCH_POOL_LARGE_ONLY)
  3147. {
  3148. ExtErr(" Unable to identify large pages. Terminating search at 0x%p.\n", StartPage);
  3149. PoolPage = PoolEnd;
  3150. hr = E_FAIL;
  3151. continue;
  3152. }
  3153. // Search page for small allocations
  3154. while (PAGE_ALIGN64(Pool) == StartPage && hr == S_OK)
  3155. {
  3156. DEBUG_VALUE HdrPoolTag, BlockSize, PreviousSize, AllocatorBackTraceIndex, PoolTagHash;
  3157. ULONG PoolType;
  3158. if ((hr = GetFieldValue(Pool, "nt!_POOL_HEADER", "PoolTag", HdrPoolTag.I32)) != S_OK)
  3159. {
  3160. if (hr != S_OK)
  3161. {
  3162. PSTR psz;
  3163. ExtErr("Type read error %lx @ 0x%p.\n", hr, Pool);
  3164. ExtWarn("Failed to read an allocated page @ 0x%p.\n", StartPage);
  3165. if (hr == MEMORY_READ_ERROR)
  3166. {
  3167. hr = S_OK;
  3168. }
  3169. else
  3170. {
  3171. ExtOut("\n...terminating - searched pool to 0x%p\n",
  3172. Pool);
  3173. hr = E_ABORT;
  3174. }
  3175. if (hr == E_ABORT)
  3176. {
  3177. break;
  3178. }
  3179. }
  3180. if (!PageReadFailed)
  3181. {
  3182. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3183. {
  3184. ExtWarn(" Couldn't read pool from 0x%p", Pool);
  3185. }
  3186. PagesRead += (StartPage - LastPageRead) / PageSize;
  3187. LastPageRead = StartPage;
  3188. PageReadFailed = TRUE;
  3189. }
  3190. #if 0
  3191. if ((hr = GetNextResidentAddress(Client,
  3192. Session,
  3193. StartPage + PageSize,
  3194. PoolEnd,
  3195. &PoolPage,
  3196. NULL)) != S_OK)
  3197. #endif
  3198. if ((PoolPage = GetNextResidentAddress(StartPage + PageSize,
  3199. PoolEnd)) == 0)
  3200. {
  3201. if (hr != E_ABORT)
  3202. {
  3203. hr = S_OK;
  3204. }
  3205. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3206. {
  3207. ExtWarn(" to 0x%p.\n", PoolEnd);
  3208. ExtWarn("No remaining resident page found.\n");
  3209. }
  3210. PageReadFailuresAtEnd = (PoolEnd - LastPageRead) / PageSize;
  3211. PageReadFailures += PageReadFailuresAtEnd;
  3212. LastPageRead = PoolEnd;
  3213. PageReadFailed = FALSE;
  3214. PoolPage = PoolEnd;
  3215. }
  3216. break;
  3217. }
  3218. if (PageReadFailed)
  3219. {
  3220. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3221. {
  3222. ExtWarn(" to 0x%p\n", StartPage-1);
  3223. }
  3224. PageReadFailures += (StartPage - LastPageRead) / PageSize;
  3225. LastPageRead = StartPage;
  3226. PageReadFailed = FALSE;
  3227. }
  3228. if (GetFieldValue(Pool, "nt!_POOL_HEADER", "BlockSize", BlockSize.I32) != S_OK)
  3229. {
  3230. ExtErr("Error reading BlockSize @ 0x%p.\n", Pool);
  3231. break;
  3232. }
  3233. if ((BlockSize.I32 << POOL_BLOCK_SHIFT) > PageSize)//POOL_PAGE_SIZE)
  3234. {
  3235. ExtVerb("Bad allocation size @ 0x%p, too large\n", Pool);
  3236. break;
  3237. }
  3238. if (BlockSize.I32 == 0)
  3239. {
  3240. ExtVerb("Bad allocation size @ 0x%p, zero is invalid\n", Pool);
  3241. break;
  3242. }
  3243. if (GetFieldValue(Pool, "nt!_POOL_HEADER", "PreviousSize", PreviousSize.I32) != S_OK ||
  3244. PreviousSize.I32 != Previous)
  3245. {
  3246. ExtVerb("Bad previous allocation size @ 0x%p, last size was 0x%lx\n", Pool, Previous);
  3247. break;
  3248. }
  3249. Filter(Pool,
  3250. TagName,
  3251. Pool,
  3252. &HdrPoolTag,
  3253. BlockSize.I32,
  3254. bQuotaWithTag,
  3255. Context
  3256. );
  3257. Previous = BlockSize.I32;
  3258. Pool += (Previous << POOL_BLOCK_SHIFT);
  3259. if ( CheckControlC())
  3260. {
  3261. ExtOut("\n...terminating - searched pool to 0x%p\n",
  3262. PoolPage-1);
  3263. hr = E_ABORT;
  3264. }
  3265. }
  3266. if (hr == S_OK)
  3267. {
  3268. PoolPage = (PoolPage + PageSize);
  3269. }
  3270. }
  3271. if (PageReadFailed)
  3272. {
  3273. if (Flags & SEARCH_POOL_PRINT_UNREAD)
  3274. {
  3275. ExtWarn(" to 0x%p\n", StartPage-1);
  3276. }
  3277. PageReadFailuresAtEnd = (PoolPage - LastPageRead) / PageSize;
  3278. PageReadFailures += PageReadFailuresAtEnd;
  3279. PageReadFailed = FALSE;
  3280. }
  3281. else
  3282. {
  3283. PagesRead += (PoolPage - LastPageRead) / PageSize;
  3284. }
  3285. ExtOut(" Pages Read: %I64d\n"
  3286. " Failures: %I64d (%I64d at end of search)\n",
  3287. PagesRead, PageReadFailures, PageReadFailuresAtEnd);
  3288. }
  3289. if (PoolTypeFlags == (SEARCH_POOL_NONPAGED | SEARCH_POOL_PAGED))
  3290. {
  3291. PoolTypeFlags = SEARCH_POOL_PAGED;
  3292. }
  3293. else
  3294. {
  3295. Continue = FALSE;
  3296. }
  3297. }
  3298. if (PagedPoolAllocationMap != NULL) FreeBitMap(PagedPoolAllocationMap);
  3299. if (EndOfPagedPoolBitmap != NULL) FreeBitMap(EndOfPagedPoolBitmap);
  3300. if (PagedPoolLargeSessionAllocationMap != NULL) FreeBitMap(PagedPoolLargeSessionAllocationMap);
  3301. }
  3302. return hr;
  3303. }
  3304. HRESULT
  3305. GetTagFilter(
  3306. PDEBUG_CLIENT Client,
  3307. PCSTR *pArgs,
  3308. PDEBUG_VALUE TagFilter
  3309. )
  3310. {
  3311. HRESULT hr;
  3312. PCSTR args;
  3313. PCSTR TagArg;
  3314. ULONG TagLen;
  3315. CHAR TagEnd;
  3316. ULONG WildCardPos;
  3317. TagArg = args = *pArgs;
  3318. TagFilter->Type = DEBUG_VALUE_INVALID;
  3319. do
  3320. {
  3321. args++;
  3322. } while (*args != '\0' && !isspace(*args));
  3323. while (isspace(*args)) args++;
  3324. if (TagArg[0] == '0' && TagArg[1] == 'x')
  3325. {
  3326. TagFilter->I64 = GetExpression(TagArg);
  3327. }
  3328. else
  3329. {
  3330. if (TagArg[0] == '`' || TagArg[0] == '\'' || TagArg[0] == '\"')
  3331. {
  3332. TagEnd = TagArg[0];
  3333. TagArg++;
  3334. args = TagArg;
  3335. while (args - TagArg < 4 &&
  3336. *args != '\0' &&
  3337. *args != TagEnd)
  3338. {
  3339. args++;
  3340. }
  3341. TagLen = (ULONG)(args - TagArg);
  3342. if (*args == TagEnd) args++;
  3343. while (isspace(*args)) args++;
  3344. }
  3345. else
  3346. {
  3347. TagLen = (ULONG)(args - TagArg);
  3348. TagEnd = '\0';
  3349. }
  3350. if (TagLen == 0 ||
  3351. (TagLen < 4 &&
  3352. TagArg[TagLen-1] != '*'
  3353. ) ||
  3354. (TagLen >= 4 &&
  3355. TagArg[4] != '\0' &&
  3356. !isspace(TagArg[4]) &&
  3357. (TagArg[4] != TagEnd || (TagArg[5] != '\0' && !isspace(TagArg[5])))
  3358. )
  3359. )
  3360. {
  3361. ExtErr(" Invalid Tag filter.\n");
  3362. hr = E_INVALIDARG;
  3363. }
  3364. else
  3365. {
  3366. hr = S_OK;
  3367. for (WildCardPos = 0; WildCardPos < TagLen; WildCardPos++)
  3368. {
  3369. if (TagArg[WildCardPos] == '*')
  3370. {
  3371. ULONG NewTagLen = WildCardPos + 1;
  3372. if (NewTagLen < TagLen)
  3373. {
  3374. ExtWarn(" Ignoring %lu characters after * in Tag.\n",
  3375. TagLen - NewTagLen);
  3376. }
  3377. TagLen = NewTagLen;
  3378. // loop will terminate
  3379. }
  3380. }
  3381. if (TagLen < 4)
  3382. {
  3383. TagFilter->I32 = ' ';
  3384. while (TagLen-- > 0)
  3385. {
  3386. TagFilter->RawBytes[TagLen] = TagArg[TagLen];
  3387. }
  3388. }
  3389. else
  3390. {
  3391. TagFilter->I32 = TagArg[0] | (TagArg[1] << 8) | (TagArg[2] << 16) | (TagArg[3] << 24);
  3392. }
  3393. TagFilter->Type = DEBUG_VALUE_INT32;
  3394. }
  3395. }
  3396. if (hr == S_OK)
  3397. {
  3398. *pArgs = args;
  3399. }
  3400. return hr;
  3401. }
  3402. HRESULT
  3403. OutputAllocStats(
  3404. PALLOCATION_STATS AllocStats,
  3405. BOOL PartialResults
  3406. )
  3407. {
  3408. ExtOut("\n"
  3409. " %I64u bytes in %lu allocated pages\n"
  3410. " %I64u bytes in %lu large allocations\n"
  3411. " %I64u bytes in %lu free pages\n"
  3412. " %I64u bytes available in %lu expansion pages\n"
  3413. "\n"
  3414. "%s found (small allocations only): %lu\n"
  3415. " Allocated: %I64u bytes in %lu entries\n"
  3416. " Free: %I64u bytes in %lu entries\n"
  3417. " Undetermined: %I64u bytes in %lu entries\n",
  3418. ((ULONG64) AllocStats->AllocatedPages) << PageShift,
  3419. AllocStats->AllocatedPages,
  3420. ((ULONG64) AllocStats->LargePages) << PageShift,
  3421. AllocStats->LargeAllocs,
  3422. ((ULONG64) AllocStats->FreePages) << PageShift,
  3423. AllocStats->FreePages,
  3424. ((ULONG64) AllocStats->ExpansionPages) << PageShift,
  3425. AllocStats->ExpansionPages,
  3426. ((PartialResults) ? "PARTIAL entries" : "Entries"),
  3427. AllocStats->Allocated + AllocStats->Free + AllocStats->Indeterminate,
  3428. ((ULONG64)AllocStats->AllocatedSize) << POOL_BLOCK_SHIFT,
  3429. AllocStats->Allocated,
  3430. ((ULONG64)AllocStats->FreeSize) << POOL_BLOCK_SHIFT,
  3431. AllocStats->Free,
  3432. ((ULONG64)AllocStats->IndeterminateSize) << POOL_BLOCK_SHIFT,
  3433. AllocStats->Indeterminate
  3434. );
  3435. return S_OK;
  3436. }
  3437. DECLARE_API( spoolfind )
  3438. {
  3439. HRESULT hr = S_OK;
  3440. INIT_API( );
  3441. BOOL BadArg = FALSE;
  3442. ULONG RemainingArgIndex;
  3443. DEBUG_VALUE TagName = { 0, DEBUG_VALUE_INVALID };
  3444. FLONG Flags = 0;
  3445. DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID };
  3446. while (isspace(*args)) args++;
  3447. while (!BadArg && hr == S_OK)
  3448. {
  3449. while (isspace(*args)) args++;
  3450. if (*args == '-')
  3451. {
  3452. // Process switches
  3453. args++;
  3454. BadArg = (*args == '\0' || isspace(*args));
  3455. while (*args != '\0' && !isspace(*args))
  3456. {
  3457. switch (tolower(*args))
  3458. {
  3459. case 'f':
  3460. Flags |= SEARCH_POOL_PRINT_UNREAD;
  3461. args++;
  3462. break;
  3463. case 'l':
  3464. Flags |= SEARCH_POOL_PRINT_LARGE;
  3465. args++;
  3466. break;
  3467. case 'n':
  3468. Flags |= SEARCH_POOL_NONPAGED;
  3469. args++;
  3470. break;
  3471. case 'p':
  3472. Flags |= SEARCH_POOL_PAGED;
  3473. args++;
  3474. break;
  3475. case 's':
  3476. if (Session.Type != DEBUG_VALUE_INVALID)
  3477. {
  3478. ExtErr("Session argument specified multiple times.\n");
  3479. BadArg = TRUE;
  3480. }
  3481. else
  3482. {
  3483. args++;
  3484. hr = GetExpressionEx(args, &Session.I64, &args);
  3485. if (hr == FALSE)
  3486. {
  3487. ExtErr("Invalid Session.\n");
  3488. }
  3489. }
  3490. break;
  3491. default:
  3492. BadArg = TRUE;
  3493. break;
  3494. }
  3495. if (BadArg) break;
  3496. }
  3497. }
  3498. else
  3499. {
  3500. if (*args == '\0') break;
  3501. if (TagName.Type == DEBUG_VALUE_INVALID)
  3502. {
  3503. hr = GetTagFilter(Client, &args, &TagName);
  3504. }
  3505. else
  3506. {
  3507. ExtErr("Unrecognized argument @ %s\n", args);
  3508. BadArg = TRUE;
  3509. }
  3510. }
  3511. }
  3512. if (!BadArg && hr == S_OK)
  3513. {
  3514. if (TagName.Type == DEBUG_VALUE_INVALID)
  3515. {
  3516. if (Flags & SEARCH_POOL_PRINT_LARGE)
  3517. {
  3518. TagName.I32 = ' *';
  3519. Flags |= SEARCH_POOL_LARGE_ONLY;
  3520. }
  3521. else
  3522. {
  3523. ExtErr("Missing Tag.\n");
  3524. hr = E_INVALIDARG;
  3525. }
  3526. }
  3527. }
  3528. if (BadArg || hr != S_OK)
  3529. {
  3530. if (*args == '?')
  3531. {
  3532. ExtOut("spoolfind is like !kdexts.poolfind, but for the SessionId specified.\n"
  3533. "\n");
  3534. }
  3535. ExtOut("Usage: spoolfind [-lnpf] [-s SessionId] Tag\n"
  3536. " -f - show read failure ranges\n"
  3537. " -l - show large allocations\n"
  3538. " -n - show non-paged pool\n"
  3539. " -p - show paged pool\n"
  3540. "\n"
  3541. " Tag - Pool tag to search for\n"
  3542. " Can be 4 character string or\n"
  3543. " hex value in 0xXXXX format\n"
  3544. "\n"
  3545. " SessionId - session to dump\n"
  3546. " Special SessionId values:\n"
  3547. " -1 - current session\n"
  3548. " -2 - last !session SessionId (default)\n"
  3549. );
  3550. }
  3551. else
  3552. {
  3553. ALLOCATION_STATS AllocStats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3554. if ((Flags & (SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED)) == 0)
  3555. {
  3556. Flags |= SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED;
  3557. }
  3558. if (Session.Type == DEBUG_VALUE_INVALID)
  3559. {
  3560. Session.I32 = DEFAULT_SESSION;
  3561. }
  3562. hr = SearchSessionPool(Client,
  3563. Session.I32, TagName.I32, Flags,
  3564. 0,
  3565. CheckPrintAndAccumFilter, &AllocStats, &AllocStats);
  3566. if (hr == S_OK || hr == E_ABORT)
  3567. {
  3568. OutputAllocStats(&AllocStats, (hr != S_OK));
  3569. }
  3570. else
  3571. {
  3572. ExtWarn("SearchSessionPool returned %lx\n", hr);
  3573. }
  3574. }
  3575. return hr;
  3576. }
  3577. DECLARE_API( spoolsum )
  3578. {
  3579. HRESULT hr = S_OK;
  3580. INIT_API( );
  3581. ULONG RemainingArgIndex;
  3582. FLONG Flags = 0;
  3583. DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID };
  3584. while (isspace(*args)) args++;
  3585. while (hr == S_OK)
  3586. {
  3587. while (isspace(*args)) args++;
  3588. if (*args == '-')
  3589. {
  3590. // Process switches
  3591. args++;
  3592. if (*args == '\0' || isspace(*args)) hr = E_INVALIDARG;
  3593. while (*args != '\0' && !isspace(*args))
  3594. {
  3595. switch (tolower(*args))
  3596. {
  3597. case 'f':
  3598. Flags |= SEARCH_POOL_PRINT_UNREAD;
  3599. args++;
  3600. break;
  3601. case 'n':
  3602. Flags |= SEARCH_POOL_NONPAGED;
  3603. args++;
  3604. break;
  3605. case 'p':
  3606. Flags |= SEARCH_POOL_PAGED;
  3607. args++;
  3608. break;
  3609. case 's':
  3610. if (Session.Type != DEBUG_VALUE_INVALID)
  3611. {
  3612. ExtErr("Session argument specified multiple times.\n");
  3613. hr = E_INVALIDARG;
  3614. }
  3615. else
  3616. {
  3617. args++;
  3618. hr = GetExpressionEx(args, &Session.I64, &args);
  3619. if (hr == FALSE)
  3620. {
  3621. ExtErr("Invalid Session.\n");
  3622. }
  3623. }
  3624. break;
  3625. default:
  3626. hr = E_INVALIDARG;
  3627. break;
  3628. }
  3629. if (hr != S_OK) break;
  3630. }
  3631. }
  3632. else
  3633. {
  3634. if (*args == '\0') break;
  3635. if (Session.Type == DEBUG_VALUE_INVALID)
  3636. {
  3637. hr = GetExpressionEx(args, &Session.I64, &args);
  3638. if (hr == FALSE)
  3639. {
  3640. ExtErr("Invalid Session.\n");
  3641. }
  3642. }
  3643. else
  3644. {
  3645. ExtErr("Unrecognized argument @ %s\n", args);
  3646. hr = E_INVALIDARG;
  3647. }
  3648. }
  3649. }
  3650. if (hr != S_OK)
  3651. {
  3652. if (*args == '?')
  3653. {
  3654. ExtOut("spoolsum summarizes session pool information for SessionId specified.\n"
  3655. "\n");
  3656. hr = S_OK;
  3657. }
  3658. ExtOut("Usage: spoolsum [-fnp] [[-s] SessionId]\n"
  3659. " f - show read failure ranges\n"
  3660. " n - show non-paged pool\n"
  3661. " p - show paged pool (Default)\n"
  3662. "\n"
  3663. " SessionId - session to dump\n"
  3664. " Special SessionId values:\n"
  3665. " -1 - current session\n"
  3666. " -2 - last !session SessionId (default)\n"
  3667. );
  3668. }
  3669. else
  3670. {
  3671. ALLOCATION_STATS AllocStats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3672. if ((Flags & (SEARCH_POOL_PAGED | SEARCH_POOL_NONPAGED)) == 0)
  3673. {
  3674. Flags |= SEARCH_POOL_PAGED;
  3675. }
  3676. hr = SearchSessionPool(Client,
  3677. DEFAULT_SESSION, ' *', Flags,
  3678. 0,
  3679. AccumAllFilter, &AllocStats, &AllocStats);
  3680. if (hr == S_OK || hr == E_ABORT)
  3681. {
  3682. OutputAllocStats(&AllocStats, (hr != S_OK));
  3683. }
  3684. else
  3685. {
  3686. ExtWarn("SearchSessionPool returned %lx\n", hr);
  3687. }
  3688. }
  3689. return hr;
  3690. }
  3691. DECLARE_API( spoolused )
  3692. {
  3693. HRESULT hr = S_OK;
  3694. INIT_API( );
  3695. BOOL BadArg = FALSE;
  3696. ULONG RemainingArgIndex;
  3697. DEBUG_VALUE TagName = { 0, DEBUG_VALUE_INVALID };
  3698. BOOL NonPagedUsage = FALSE;
  3699. BOOL PagedUsage = FALSE;
  3700. BOOL AllocSort = FALSE;
  3701. DEBUG_VALUE Session = { DEFAULT_SESSION, DEBUG_VALUE_INVALID };
  3702. while (isspace(*args)) args++;
  3703. while (!BadArg && hr == S_OK)
  3704. {
  3705. while (isspace(*args)) args++;
  3706. if (*args == '-')
  3707. {
  3708. // Process switches
  3709. args++;
  3710. BadArg = (*args == '\0' || isspace(*args));
  3711. while (*args != '\0' && !isspace(*args))
  3712. {
  3713. switch (tolower(*args))
  3714. {
  3715. case 'a':
  3716. AllocSort = TRUE;
  3717. args++;
  3718. break;
  3719. case 'n':
  3720. NonPagedUsage = TRUE;
  3721. args++;
  3722. break;
  3723. case 'p':
  3724. PagedUsage = TRUE;
  3725. args++;
  3726. break;
  3727. case 's':
  3728. if (Session.Type != DEBUG_VALUE_INVALID)
  3729. {
  3730. ExtErr("Session argument specified multiple times.\n");
  3731. BadArg = TRUE;
  3732. }
  3733. else
  3734. {
  3735. args++;
  3736. hr = GetExpressionEx(args, &Session.I64, &args);
  3737. if (hr == FALSE)
  3738. {
  3739. ExtErr("Invalid Session.\n");
  3740. }
  3741. }
  3742. break;
  3743. default:
  3744. BadArg = TRUE;
  3745. break;
  3746. }
  3747. if (BadArg) break;
  3748. }
  3749. }
  3750. else
  3751. {
  3752. if (*args == '\0') break;
  3753. if (TagName.Type == DEBUG_VALUE_INVALID)
  3754. {
  3755. hr = GetTagFilter(Client, &args, &TagName);
  3756. }
  3757. else
  3758. {
  3759. ExtErr("Unrecognized argument @ %s\n", args);
  3760. BadArg = TRUE;
  3761. }
  3762. }
  3763. }
  3764. if (BadArg || hr != S_OK)
  3765. {
  3766. if (*args == '?')
  3767. {
  3768. ExtOut("spoolused is like !kdexts.poolused, but for the SessionId specified.\n"
  3769. "\n");
  3770. }
  3771. ExtOut("Usage: spoolused [-anp] [-s SessionId] [Tag]\n"
  3772. " -a - sort by allocation size (Not Implemented)\n"
  3773. " -n - show non-paged pool\n"
  3774. " -p - show paged pool\n"
  3775. "\n"
  3776. " SessionId - session to dump\n"
  3777. " Special SessionId values:\n"
  3778. " -1 - current session\n"
  3779. " -2 - last !session SessionId (default)\n"
  3780. "\n"
  3781. " Tag - Pool tag filter\n"
  3782. " Can be 4 character string or\n"
  3783. " hex value in 0xXXXX format\n"
  3784. );
  3785. }
  3786. else
  3787. {
  3788. if (!NonPagedUsage && !PagedUsage)
  3789. {
  3790. NonPagedUsage = TRUE;
  3791. PagedUsage = TRUE;
  3792. }
  3793. if (Session.Type == DEBUG_VALUE_INVALID)
  3794. {
  3795. Session.I32 = DEFAULT_SESSION;
  3796. }
  3797. if (TagName.Type == DEBUG_VALUE_INVALID)
  3798. {
  3799. TagName.I32 = ' *';
  3800. }
  3801. AccumTagUsage atu(TagName.I32);
  3802. if (atu.Valid() != S_OK)
  3803. {
  3804. ExtErr("Error: failed to prepare tag usage reader.\n");
  3805. hr = E_FAIL;
  3806. }
  3807. if (hr == S_OK && NonPagedUsage)
  3808. {
  3809. hr = SearchSessionPool(Client,
  3810. Session.I32, TagName.I32, SEARCH_POOL_NONPAGED,
  3811. 0,
  3812. AccumTagUsageFilter, &atu, &atu);
  3813. if (hr == S_OK || hr == E_ABORT)
  3814. {
  3815. atu.OutputResults(AllocSort);
  3816. }
  3817. else
  3818. {
  3819. ExtWarn("SearchSessionPool returned %lx\n", hr);
  3820. }
  3821. }
  3822. if (hr == S_OK && PagedUsage)
  3823. {
  3824. if (NonPagedUsage) atu.Reset();
  3825. hr = SearchSessionPool(Client,
  3826. Session.I32, TagName.I32, SEARCH_POOL_PAGED,
  3827. 0,
  3828. AccumTagUsageFilter, &atu, &atu);
  3829. if (hr == S_OK || hr == E_ABORT)
  3830. {
  3831. atu.OutputResults(AllocSort);
  3832. }
  3833. else
  3834. {
  3835. ExtWarn("SearchSessionPool returned %lx\n", hr);
  3836. }
  3837. }
  3838. }
  3839. return hr;
  3840. }