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.

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