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.

876 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. SvrUtil.cxx
  5. Abstract:
  6. Utility functions for querying RPC Server debug data
  7. Author:
  8. Kamen Moutafov (kamenm) Dec 99 - Feb 2000
  9. Revision History:
  10. --*/
  11. #include <precomp.hxx>
  12. #include <DbgLib.hxx>
  13. typedef struct tagServerEnumerationState
  14. {
  15. int CurrentPosition;
  16. int NumberOfProcesses;
  17. // the actual size is NumberOfProcesses
  18. ULONG ProcessUniqueId[1];
  19. } ServerEnumerationState;
  20. RPC_STATUS StartServerEnumeration(ServerEnumerationHandle *pHandle)
  21. {
  22. ServerEnumerationState *pNewState;
  23. void *pProcessDataBuffer = NULL;
  24. NTSTATUS NtStatus;
  25. int CurrentAllocatedSize = 0x6000;
  26. SYSTEM_PROCESS_INFORMATION *pCurrentProcessInfo;
  27. unsigned char *pCurrentPos;
  28. int NumberOfProcesses;
  29. int i;
  30. BOOL fResult;
  31. do
  32. {
  33. if (pProcessDataBuffer)
  34. {
  35. fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE);
  36. ASSERT(fResult);
  37. }
  38. CurrentAllocatedSize += 4096 * 2;
  39. pProcessDataBuffer = VirtualAlloc(NULL, CurrentAllocatedSize, MEM_COMMIT, PAGE_READWRITE);
  40. if (pProcessDataBuffer == NULL)
  41. return RPC_S_OUT_OF_MEMORY;
  42. NtStatus = NtQuerySystemInformation(SystemProcessInformation, pProcessDataBuffer,
  43. CurrentAllocatedSize, NULL);
  44. }
  45. while (NtStatus == STATUS_INFO_LENGTH_MISMATCH);
  46. if (!NT_SUCCESS(NtStatus))
  47. return RPC_S_OUT_OF_MEMORY;
  48. // walk the buffer - on first pass, we just count the entries
  49. pCurrentPos = (unsigned char *)pProcessDataBuffer;
  50. pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos;
  51. NumberOfProcesses = 0;
  52. while (TRUE)
  53. {
  54. // we skip idle process and zombie processes
  55. if (pCurrentProcessInfo->UniqueProcessId != NULL)
  56. {
  57. NumberOfProcesses ++;
  58. }
  59. // is there a place to advance to?
  60. if (pCurrentProcessInfo->NextEntryOffset == 0)
  61. break;
  62. pCurrentPos += pCurrentProcessInfo->NextEntryOffset;
  63. pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos;
  64. }
  65. pNewState = (ServerEnumerationState *) new char [
  66. sizeof(ServerEnumerationState) + (NumberOfProcesses - 1) * sizeof(ULONG)];
  67. // implicit placement
  68. // pNewState = new ((NumberOfProcesses - 1) * sizeof(ULONG)) ServerEnumerationState;
  69. if (pNewState == NULL)
  70. {
  71. fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE);
  72. ASSERT(fResult);
  73. return RPC_S_OUT_OF_MEMORY;
  74. }
  75. new (pNewState) ServerEnumerationState;
  76. // make the second pass - actual copying of data
  77. pCurrentPos = (unsigned char *)pProcessDataBuffer;
  78. pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos;
  79. i = 0;
  80. while (TRUE)
  81. {
  82. // we skip idle process and zombie processes
  83. if (pCurrentProcessInfo->UniqueProcessId != NULL)
  84. {
  85. pNewState->ProcessUniqueId[i] = PtrToUlong(pCurrentProcessInfo->UniqueProcessId);
  86. i ++;
  87. }
  88. // is there a place to advance to?
  89. if (pCurrentProcessInfo->NextEntryOffset == 0)
  90. break;
  91. pCurrentPos += pCurrentProcessInfo->NextEntryOffset;
  92. pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos;
  93. }
  94. ASSERT(i == NumberOfProcesses);
  95. fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE);
  96. ASSERT(fResult);
  97. // make the data available to the user
  98. pNewState->CurrentPosition = 0;
  99. pNewState->NumberOfProcesses = NumberOfProcesses;
  100. *pHandle = pNewState;
  101. return RPC_S_OK;
  102. }
  103. RPC_STATUS OpenNextRPCServer(IN ServerEnumerationHandle Handle, OUT CellEnumerationHandle *pHandle)
  104. {
  105. ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle;
  106. int CurrentPosition;
  107. RPC_STATUS RpcStatus;
  108. ASSERT(ServerState != NULL);
  109. ASSERT(pHandle != NULL);
  110. do
  111. {
  112. CurrentPosition = ServerState->CurrentPosition;
  113. if (CurrentPosition >= ServerState->NumberOfProcesses)
  114. return RPC_S_INVALID_BOUND;
  115. ServerState->CurrentPosition ++;
  116. RpcStatus = OpenRPCServerDebugInfo(ServerState->ProcessUniqueId[CurrentPosition], pHandle);
  117. }
  118. while(RpcStatus == ERROR_FILE_NOT_FOUND);
  119. return RpcStatus;
  120. }
  121. void ResetServerEnumeration(IN ServerEnumerationHandle Handle)
  122. {
  123. ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle;
  124. ASSERT(ServerState != NULL);
  125. ServerState->CurrentPosition = 0;
  126. }
  127. void FinishServerEnumeration(ServerEnumerationHandle *pHandle)
  128. {
  129. ServerEnumerationState *ServerState;
  130. ASSERT (pHandle != NULL);
  131. ServerState = *(ServerEnumerationState **)pHandle;
  132. ASSERT(ServerState != NULL);
  133. delete ServerState;
  134. *pHandle = NULL;
  135. }
  136. DWORD GetCurrentServerPID(IN ServerEnumerationHandle Handle)
  137. {
  138. ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle;
  139. ASSERT(ServerState != NULL);
  140. // -1, because the CurrentPosition points to the next server
  141. return (DWORD)ServerState->ProcessUniqueId[ServerState->CurrentPosition - 1];
  142. }
  143. // a helper function
  144. // whenever we detect an inconsistency in one of the lists,
  145. // we can call this function, which will determine what to do
  146. // with the current section, and will transfer sections between
  147. // the OpenedSections list and the InconsistentSections list
  148. void InconsistencyDetected(IN LIST_ENTRY *OpenedSections, IN LIST_ENTRY *InconsistentSections,
  149. IN LIST_ENTRY *CurrentListEntry, IN OpenedDbgSection *pCurrentSection,
  150. BOOL fExceptionOccurred)
  151. {
  152. LIST_ENTRY *NextEntry;
  153. LIST_ENTRY *LastEntry;
  154. // if an exception occurred, throw away this section altogether
  155. if (fExceptionOccurred)
  156. {
  157. // save the next entry before we delete this one
  158. NextEntry = CurrentListEntry->Flink;
  159. RemoveEntryList(CurrentListEntry);
  160. CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer);
  161. delete pCurrentSection;
  162. CurrentListEntry = NextEntry;
  163. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  164. // if the bad section was the last on the list,
  165. // there is nothing to add to the grab bag - just
  166. // return
  167. if (CurrentListEntry == OpenedSections)
  168. {
  169. return;
  170. }
  171. }
  172. // the chain is broken - we need to throw the rest of the list in
  173. // the grab bag
  174. // unchain this segment from the opened sections list
  175. LastEntry = OpenedSections->Blink;
  176. OpenedSections->Blink = CurrentListEntry->Blink;
  177. CurrentListEntry->Blink->Flink = OpenedSections;
  178. // chain the segment to the inconsistent sections list
  179. CurrentListEntry->Blink = InconsistentSections->Blink;
  180. InconsistentSections->Blink->Flink = CurrentListEntry;
  181. InconsistentSections->Blink = LastEntry;
  182. LastEntry->Flink = InconsistentSections;
  183. }
  184. RPC_STATUS OpenRPCServerDebugInfo(IN DWORD ProcessID, OUT CellEnumerationHandle *pHandle)
  185. {
  186. RPC_STATUS RpcStatus;
  187. HANDLE SecHandle;
  188. PVOID SecPointer;
  189. int Retries = 10;
  190. BOOL fConsistentSnapshotObtained = FALSE;
  191. BOOL fNeedToRetry;
  192. CellSection *CurrentSection;
  193. DWORD SectionNumbers[2];
  194. OpenedDbgSection *pCurrentSection;
  195. // each section as it is opened, is linked on one of those lists
  196. // if the view of the sections is consistent, we link it to opened
  197. // sections. Otherwise, we link it to InconsistentSections
  198. LIST_ENTRY OpenedSections;
  199. LIST_ENTRY InconsistentSections;
  200. LIST_ENTRY *CurrentListEntry;
  201. DWORD *pActualSectionNumbers;
  202. BOOL fExceptionOccurred;
  203. LIST_ENTRY *LastEntry;
  204. BOOL fFound;
  205. int NumberOfCommittedPages;
  206. BOOL fConsistencyPass = FALSE;
  207. DWORD LocalPageSize;
  208. SectionsSnapshot *LocalSectionsSnapshot;
  209. BOOL fResult;
  210. RpcStatus = InitializeDbgLib();
  211. if (RpcStatus != RPC_S_OK)
  212. return RpcStatus;
  213. LocalPageSize = GetPageSize();
  214. // loop until we obtain a consistent snapshot or we are out of
  215. // retry attempts. We declare a snapshot to be consistent
  216. // if we manage to:
  217. // - open all sections
  218. // - copy their contents to a private memory location
  219. // - verify that the section chain is still consistent after the copying
  220. // For this purpose, when we copy all the sections, we make one more
  221. // pass at the section chain to verify it is consistent using the special
  222. // flag fConsistencyPass.
  223. InconsistentSections.Blink = InconsistentSections.Flink = &InconsistentSections;
  224. OpenedSections.Blink = OpenedSections.Flink = &OpenedSections;
  225. while (Retries > 0)
  226. {
  227. // on entry to the loop, the state will be this - OpenSections will
  228. // contain a consistent view of the sections. Inconsistent sections
  229. // will be a grab bag of sections we could not bring into
  230. // consistent view. It's used as a cache to facilitate quick
  231. // recovery
  232. // we are just starting, or we are recovering from an inconsistency
  233. // found somewhere. As soon as somebody detects an inconsistency,
  234. // they will jump here. First thing is to try to establish what
  235. // part of the chain is consistent. Walk the open sections for
  236. // this purpose. We walk as far as we can, and then we declare
  237. // the rest of the sections inconsistent, and we throw them in
  238. // the grab bag
  239. SectionNumbers[0] = SectionNumbers[1] = 0;
  240. CurrentListEntry = OpenedSections.Flink;
  241. fNeedToRetry = FALSE;
  242. while (CurrentListEntry != &OpenedSections)
  243. {
  244. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  245. if ((SectionNumbers[0] != pCurrentSection->SectionNumbers[0])
  246. || (SectionNumbers[1] != pCurrentSection->SectionNumbers[1]))
  247. {
  248. fNeedToRetry = TRUE;
  249. }
  250. else
  251. {
  252. __try
  253. {
  254. // attempt to read the numbers of the next section
  255. // we do this within try/except since server may free this
  256. // memory and we will get toast
  257. SectionNumbers[0] = pCurrentSection->SectionPointer->NextSectionId[0];
  258. SectionNumbers[1] = pCurrentSection->SectionPointer->NextSectionId[1];
  259. fExceptionOccurred = FALSE;
  260. // note that the SectionNumbers array will be used after the end of
  261. // the loop - make sure we don't whack them
  262. }
  263. __except (EXCEPTION_EXECUTE_HANDLER)
  264. {
  265. fExceptionOccurred = TRUE;
  266. fNeedToRetry = TRUE;
  267. }
  268. }
  269. if (fNeedToRetry)
  270. {
  271. // if this is the first section, the server went down. There is no
  272. // legal way for the server to have inconsistent first section
  273. if (CurrentListEntry == OpenedSections.Flink)
  274. {
  275. RpcStatus = ERROR_FILE_NOT_FOUND;
  276. goto CleanupAndExit;
  277. }
  278. InconsistencyDetected(&OpenedSections, &InconsistentSections, CurrentListEntry,
  279. pCurrentSection, fExceptionOccurred);
  280. fNeedToRetry = TRUE;
  281. break;
  282. }
  283. CurrentListEntry = CurrentListEntry->Flink;
  284. }
  285. // walking is complete. Did we detect inconsistency?
  286. if (fNeedToRetry)
  287. {
  288. Retries --;
  289. fConsistencyPass = FALSE;
  290. continue;
  291. }
  292. else if (fConsistencyPass)
  293. {
  294. // this is the only place we break out of the loop -
  295. // the consistency pass has passed
  296. break;
  297. }
  298. // whatever we have in the opened sections list is consistent
  299. // if there was something in the list keep reading,
  300. // otherwise, start reading
  301. if (IsListEmpty(&OpenedSections))
  302. {
  303. pActualSectionNumbers = NULL;
  304. }
  305. else
  306. {
  307. pCurrentSection = CONTAINING_RECORD(OpenedSections.Blink, OpenedDbgSection, SectionsList);
  308. // we re-use the section numbers from the loop above. They can be 0 at
  309. // this point if the last section got dropped
  310. pActualSectionNumbers = SectionNumbers;
  311. }
  312. // make a pass over the sections, opening each one, but only if
  313. // case we're missing parts of the chain or this is the first time.
  314. // Otherwise, skip this step
  315. while ((SectionNumbers[0] != 0) || (SectionNumbers[1] != 0) || (pActualSectionNumbers == NULL))
  316. {
  317. // we know which section we're looking for
  318. // first, search the grab bag. We can only do this for a non-first
  319. // section. The first section never goes to the grab bag
  320. // pActualSectionNumbers will contain the section we're looking for
  321. fFound = FALSE;
  322. if (pActualSectionNumbers)
  323. {
  324. CurrentListEntry = InconsistentSections.Flink;
  325. while (CurrentListEntry != &InconsistentSections)
  326. {
  327. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  328. // it is impossible that a well behaving server will have
  329. // opened a different section with the same numbers, because we
  330. // keep the section object opened.
  331. if ((pActualSectionNumbers[0] == pCurrentSection->SectionNumbers[0])
  332. && (pActualSectionNumbers[1] == pCurrentSection->SectionNumbers[1]))
  333. {
  334. // found something
  335. RemoveEntryList(CurrentListEntry);
  336. // if we had already made a copy of this one, free it, as it is
  337. // probably inconsistent
  338. if (pCurrentSection->SectionCopy)
  339. {
  340. fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE);
  341. ASSERT(fResult);
  342. pCurrentSection->SectionCopy = NULL;
  343. }
  344. fFound = TRUE;
  345. break;
  346. }
  347. CurrentListEntry = CurrentListEntry->Flink;
  348. }
  349. }
  350. if (fFound == FALSE)
  351. {
  352. // nothing in the grab bag - try to open it the normal way
  353. RpcStatus = OpenDbgSection(&SecHandle, &SecPointer, ProcessID, pActualSectionNumbers);
  354. if (RpcStatus == ERROR_FILE_NOT_FOUND)
  355. {
  356. // if this is the first time, this is not a server - bail out
  357. if (pActualSectionNumbers == NULL)
  358. {
  359. goto CleanupAndExit;
  360. }
  361. // not the first time - we have an inconsistent view - need to retry
  362. fNeedToRetry = TRUE;
  363. break;
  364. }
  365. else if (RpcStatus != RPC_S_OK)
  366. {
  367. goto CleanupAndExit;
  368. }
  369. pCurrentSection = new OpenedDbgSection;
  370. if (pCurrentSection == NULL)
  371. {
  372. RpcStatus = RPC_S_OUT_OF_MEMORY;
  373. CloseDbgSection(SecHandle, SecPointer);
  374. goto CleanupAndExit;
  375. }
  376. pCurrentSection->SectionHandle = SecHandle;
  377. if (pActualSectionNumbers)
  378. {
  379. pCurrentSection->SectionNumbers[0] = pActualSectionNumbers[0];
  380. pCurrentSection->SectionNumbers[1] = pActualSectionNumbers[1];
  381. }
  382. else
  383. {
  384. pCurrentSection->SectionNumbers[0] = pCurrentSection->SectionNumbers[1] = 0;
  385. }
  386. pCurrentSection->SectionPointer = (CellSection *) SecPointer;
  387. pCurrentSection->SectionCopy = NULL;
  388. }
  389. // either we have found this in the grab bag, or we have just opened it
  390. // both ways, try to get the section numbers we expect for the next section
  391. __try
  392. {
  393. // load the section numbers that we expect for the next iteration of the
  394. // loop
  395. SectionNumbers[0] = pCurrentSection->SectionPointer->NextSectionId[0];
  396. SectionNumbers[1] = pCurrentSection->SectionPointer->NextSectionId[1];
  397. pActualSectionNumbers = SectionNumbers;
  398. fExceptionOccurred = FALSE;
  399. }
  400. __except (EXCEPTION_EXECUTE_HANDLER)
  401. {
  402. fExceptionOccurred = TRUE;
  403. }
  404. if (fExceptionOccurred)
  405. {
  406. delete pCurrentSection;
  407. CloseDbgSection(SecHandle, SecPointer);
  408. fNeedToRetry = TRUE;
  409. break;
  410. }
  411. InsertTailList(&OpenedSections, &pCurrentSection->SectionsList);
  412. }
  413. if (fNeedToRetry)
  414. {
  415. Retries --;
  416. fConsistencyPass = FALSE;
  417. continue;
  418. }
  419. // at this point, we have opened all the sections
  420. // now we need to allocate memory for the snapshots and to do the copying
  421. CurrentListEntry = OpenedSections.Flink;
  422. while (CurrentListEntry != &OpenedSections)
  423. {
  424. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  425. __try
  426. {
  427. // do all the allocation and copying only if it hasn't been done yet
  428. if (pCurrentSection->SectionCopy == NULL)
  429. {
  430. NumberOfCommittedPages = pCurrentSection->SectionPointer->LastCommittedPage;
  431. pCurrentSection->SectionCopy = (CellSection *)VirtualAlloc(NULL,
  432. NumberOfCommittedPages * LocalPageSize, MEM_COMMIT, PAGE_READWRITE);
  433. if (pCurrentSection->SectionCopy == NULL)
  434. {
  435. RpcStatus = RPC_S_OUT_OF_MEMORY;
  436. goto CleanupAndExit;
  437. }
  438. memcpy(pCurrentSection->SectionCopy, pCurrentSection->SectionPointer,
  439. NumberOfCommittedPages * LocalPageSize);
  440. pCurrentSection->SectionID = pCurrentSection->SectionPointer->SectionID;
  441. pCurrentSection->CommittedPagesInSection = NumberOfCommittedPages;
  442. }
  443. fExceptionOccurred = FALSE;
  444. }
  445. __except (EXCEPTION_EXECUTE_HANDLER)
  446. {
  447. fExceptionOccurred = TRUE;
  448. }
  449. if (fExceptionOccurred)
  450. {
  451. if (pCurrentSection->SectionCopy)
  452. {
  453. fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE);
  454. ASSERT(fResult);
  455. pCurrentSection->SectionCopy = NULL;
  456. }
  457. // the section got out of sync
  458. InconsistencyDetected(&OpenedSections, &InconsistentSections, CurrentListEntry,
  459. pCurrentSection, fExceptionOccurred);
  460. fNeedToRetry = TRUE;
  461. break;
  462. }
  463. CurrentListEntry = CurrentListEntry->Flink;
  464. }
  465. if (fNeedToRetry)
  466. {
  467. Retries --;
  468. fConsistencyPass = FALSE;
  469. continue;
  470. }
  471. else
  472. {
  473. fConsistencyPass = TRUE;
  474. }
  475. }
  476. // if we managed to get a consistent view, unmap the shared sections and
  477. // save the opened section list
  478. if (Retries != 0)
  479. {
  480. ASSERT(fConsistencyPass == TRUE);
  481. ASSERT(fNeedToRetry == FALSE);
  482. ASSERT(!IsListEmpty(&OpenedSections));
  483. CurrentListEntry = OpenedSections.Flink;
  484. while (CurrentListEntry != &OpenedSections)
  485. {
  486. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  487. CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer);
  488. pCurrentSection->SectionHandle = NULL;
  489. pCurrentSection->SectionPointer = NULL;
  490. pCurrentSection->SectionNumbers[0] = pCurrentSection->SectionNumbers[1] = 0;
  491. CurrentListEntry = CurrentListEntry->Flink;
  492. }
  493. // save the opened section list
  494. CurrentListEntry = OpenedSections.Flink;
  495. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  496. LocalSectionsSnapshot = new SectionsSnapshot;
  497. if (LocalSectionsSnapshot != NULL)
  498. {
  499. LocalSectionsSnapshot->CellIndex = 0;
  500. LocalSectionsSnapshot->FirstOpenedSection = pCurrentSection;
  501. LocalSectionsSnapshot->CurrentOpenedSection = pCurrentSection;
  502. // unchain the opened sections
  503. // terminate the chain with NULL
  504. OpenedSections.Blink->Flink = NULL;
  505. OpenedSections.Blink = OpenedSections.Flink = &OpenedSections;
  506. // that's the only place where we return success
  507. *pHandle = (CellEnumerationHandle)LocalSectionsSnapshot;
  508. RpcStatus = RPC_S_OK;
  509. }
  510. else
  511. {
  512. // let the CleanupAndExit code destroy the lists
  513. RpcStatus = RPC_S_OUT_OF_MEMORY;
  514. }
  515. }
  516. else
  517. {
  518. // we couldn't get a consistent snapshot of the server and
  519. // we ran out of retries
  520. RpcStatus = RPC_S_CANNOT_SUPPORT;
  521. }
  522. CleanupAndExit:
  523. // walk the two lists, and free all sections on them
  524. CurrentListEntry = OpenedSections.Flink;
  525. while (CurrentListEntry != &OpenedSections)
  526. {
  527. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  528. // advance the pointer while we haven't freed the stuff
  529. CurrentListEntry = CurrentListEntry->Flink;
  530. if (pCurrentSection->SectionCopy)
  531. {
  532. fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE);
  533. ASSERT(fResult);
  534. }
  535. if (pCurrentSection->SectionHandle)
  536. {
  537. ASSERT(pCurrentSection->SectionPointer);
  538. CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer);
  539. }
  540. delete pCurrentSection;
  541. }
  542. CurrentListEntry = InconsistentSections.Flink;
  543. while (CurrentListEntry != &InconsistentSections)
  544. {
  545. pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  546. // advance the pointer while we haven't freed the stuff
  547. CurrentListEntry = CurrentListEntry->Flink;
  548. if (pCurrentSection->SectionCopy)
  549. {
  550. fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE);
  551. ASSERT(fResult);
  552. }
  553. if (pCurrentSection->SectionHandle)
  554. {
  555. ASSERT(pCurrentSection->SectionPointer);
  556. CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer);
  557. }
  558. delete pCurrentSection;
  559. }
  560. return RpcStatus;
  561. }
  562. DebugCellUnion *GetNextDebugCellInfo(IN CellEnumerationHandle Handle, OUT DebugCellID *CellID)
  563. {
  564. SectionsSnapshot *Snapshot = (SectionsSnapshot *)Handle;
  565. OpenedDbgSection *CurrentSection, *NextSection;
  566. DebugCellGeneric *CurrentCell;
  567. int CurrentCellIndex;
  568. DebugCellGeneric *LastCellForCurrentSection;
  569. DWORD LocalPageSize = GetPageSize();
  570. ASSERT(Handle != NULL);
  571. CurrentSection = Snapshot->CurrentOpenedSection;
  572. LastCellForCurrentSection = GetLastCellForSection(CurrentSection, LocalPageSize);
  573. if (Snapshot->CellIndex == 0)
  574. {
  575. #ifdef _WIN64
  576. Snapshot->CellIndex = 2;
  577. #else
  578. Snapshot->CellIndex = 1;
  579. #endif
  580. }
  581. CurrentCell = GetCellForSection(CurrentSection, Snapshot->CellIndex);
  582. while (TRUE)
  583. {
  584. // did we exhaust the current section?
  585. if (CurrentCell > LastCellForCurrentSection)
  586. {
  587. // try to advance to the next one
  588. if (CurrentSection->SectionsList.Flink)
  589. {
  590. CurrentSection = CONTAINING_RECORD(CurrentSection->SectionsList.Flink,
  591. OpenedDbgSection, SectionsList);
  592. Snapshot->CurrentOpenedSection = CurrentSection;
  593. #ifdef _WIN64
  594. Snapshot->CellIndex = 2;
  595. #else
  596. Snapshot->CellIndex = 1;
  597. #endif
  598. LastCellForCurrentSection = GetLastCellForSection(CurrentSection, LocalPageSize);
  599. CurrentCell = GetCellForSection(CurrentSection, Snapshot->CellIndex);
  600. continue;
  601. }
  602. return NULL;
  603. }
  604. CellID->CellID = (USHORT) Snapshot->CellIndex;
  605. Snapshot->CellIndex ++;
  606. if ((CurrentCell->Type == dctCallInfo) || (CurrentCell->Type == dctThreadInfo)
  607. || (CurrentCell->Type == dctEndpointInfo) || (CurrentCell->Type == dctClientCallInfo))
  608. {
  609. CellID->SectionID = (USHORT)CurrentSection->SectionID;
  610. return (DebugCellUnion *)CurrentCell;
  611. }
  612. CurrentCell = (DebugCellGeneric *)((unsigned char *)CurrentCell + sizeof(DebugFreeCell));
  613. }
  614. return NULL;
  615. }
  616. void ResetRPCServerDebugInfo(IN CellEnumerationHandle Handle)
  617. {
  618. SectionsSnapshot *LocalSnapshot = (SectionsSnapshot *)Handle;
  619. ASSERT(Handle != NULL);
  620. LocalSnapshot->CellIndex = 0;
  621. LocalSnapshot->CurrentOpenedSection = LocalSnapshot->FirstOpenedSection;
  622. }
  623. void CloseRPCServerDebugInfo(IN CellEnumerationHandle *pHandle)
  624. {
  625. SectionsSnapshot *LocalSnapshot;
  626. OpenedDbgSection *DbgSection;
  627. LIST_ENTRY *CurrentListEntry;
  628. ASSERT(pHandle != NULL);
  629. LocalSnapshot = (SectionsSnapshot *)*pHandle;
  630. ASSERT(LocalSnapshot != NULL);
  631. ASSERT(LocalSnapshot->FirstOpenedSection != NULL);
  632. DbgSection = LocalSnapshot->FirstOpenedSection;
  633. do
  634. {
  635. // advance while we can
  636. CurrentListEntry = DbgSection->SectionsList.Flink;
  637. // free the section
  638. ASSERT(DbgSection->SectionCopy);
  639. VirtualFree(DbgSection->SectionCopy, 0, MEM_RELEASE);
  640. delete DbgSection;
  641. // calculate next record. Note that this will not AV even if
  642. // CurrentListEntry is NULL - this is just offset calculation
  643. DbgSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
  644. }
  645. while (CurrentListEntry != NULL);
  646. delete LocalSnapshot;
  647. *pHandle = NULL;
  648. }
  649. typedef struct tagRPCSystemWideCellEnumeration
  650. {
  651. ServerEnumerationHandle serverHandle;
  652. CellEnumerationHandle cellHandle;
  653. } RPCSystemWideCellEnumeration;
  654. RPC_STATUS OpenRPCSystemWideCellEnumeration(OUT RPCSystemWideCellEnumerationHandle *pHandle)
  655. {
  656. RPCSystemWideCellEnumeration *cellEnum;
  657. RPC_STATUS Status;
  658. DebugCellUnion *NextCell;
  659. ASSERT(pHandle != NULL);
  660. *pHandle = NULL;
  661. cellEnum = new RPCSystemWideCellEnumeration;
  662. if (cellEnum == NULL)
  663. return RPC_S_OUT_OF_MEMORY;
  664. cellEnum->cellHandle = NULL;
  665. cellEnum->serverHandle = NULL;
  666. Status = StartServerEnumeration(&cellEnum->serverHandle);
  667. if (Status != RPC_S_OK)
  668. {
  669. delete cellEnum;
  670. return Status;
  671. }
  672. Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle);
  673. // if we're done, we will get RPC_S_SERVER_INVALID_BOUND - ok to
  674. // just return to caller
  675. if (Status != RPC_S_OK)
  676. {
  677. FinishServerEnumeration(&cellEnum->serverHandle);
  678. delete cellEnum;
  679. return Status;
  680. }
  681. *pHandle = (RPCSystemWideCellEnumerationHandle) cellEnum;
  682. return RPC_S_OK;
  683. }
  684. RPC_STATUS GetNextRPCSystemWideCell(IN RPCSystemWideCellEnumerationHandle handle, OUT DebugCellUnion **NextCell,
  685. OUT DebugCellID *CellID, OUT DWORD *ServerPID OPTIONAL)
  686. {
  687. RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle;
  688. RPC_STATUS Status;
  689. ASSERT(cellEnum != NULL);
  690. // loop skipping empty servers
  691. do
  692. {
  693. *NextCell = GetNextDebugCellInfo(cellEnum->cellHandle, CellID);
  694. // this server is done - move on to the next
  695. if (*NextCell == NULL)
  696. {
  697. CloseRPCServerDebugInfo(&cellEnum->cellHandle);
  698. Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle);
  699. // if we're done with all servers, we will get RPC_S_SERVER_INVALID_BOUND - ok to
  700. // just return to caller. Caller needs to call us back to finish enumeration
  701. if (Status != RPC_S_OK)
  702. {
  703. // remember that this failed so that we don't try to clean it up
  704. // when finishing the enumeration
  705. cellEnum->cellHandle = NULL;
  706. return Status;
  707. }
  708. }
  709. }
  710. while(*NextCell == NULL);
  711. if (ServerPID && (*NextCell != NULL))
  712. {
  713. *ServerPID = GetCurrentServerPID(cellEnum->serverHandle);
  714. }
  715. return RPC_S_OK;
  716. }
  717. DebugCellUnion *GetRPCSystemWideCellFromCellID(IN RPCSystemWideCellEnumerationHandle handle,
  718. IN DebugCellID CellID)
  719. {
  720. RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle;
  721. return GetCellByDebugCellID(cellEnum->cellHandle, CellID);
  722. }
  723. void FinishRPCSystemWideCellEnumeration(IN OUT RPCSystemWideCellEnumerationHandle *pHandle)
  724. {
  725. RPCSystemWideCellEnumeration *cellEnum;
  726. ASSERT(pHandle != NULL);
  727. cellEnum = (RPCSystemWideCellEnumeration *)*pHandle;
  728. ASSERT(cellEnum != NULL);
  729. if (cellEnum->cellHandle)
  730. {
  731. CloseRPCServerDebugInfo(&cellEnum->cellHandle);
  732. }
  733. FinishServerEnumeration(&cellEnum->serverHandle);
  734. delete cellEnum;
  735. *pHandle = NULL;
  736. }
  737. RPC_STATUS ResetRPCSystemWideCellEnumeration(IN RPCSystemWideCellEnumerationHandle handle)
  738. {
  739. RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle;
  740. RPC_STATUS Status;
  741. ASSERT(cellEnum != NULL);
  742. if (cellEnum->cellHandle)
  743. {
  744. CloseRPCServerDebugInfo(&cellEnum->cellHandle);
  745. cellEnum->cellHandle = NULL;
  746. }
  747. ResetServerEnumeration(cellEnum->serverHandle);
  748. Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle);
  749. if (Status != RPC_S_OK)
  750. {
  751. // remember that this failed so that we don't try to clean it up
  752. // when finishing the enumeration
  753. cellEnum->cellHandle = NULL;
  754. }
  755. return Status;
  756. }