|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
SvrUtil.cxx
Abstract:
Utility functions for querying RPC Server debug data
Author:
Kamen Moutafov (kamenm) Dec 99 - Feb 2000
Revision History:
--*/
#include <precomp.hxx>
#include <DbgLib.hxx>
typedef struct tagServerEnumerationState { int CurrentPosition; int NumberOfProcesses; // the actual size is NumberOfProcesses
ULONG ProcessUniqueId[1]; } ServerEnumerationState;
RPC_STATUS StartServerEnumeration(ServerEnumerationHandle *pHandle) { ServerEnumerationState *pNewState; void *pProcessDataBuffer = NULL; NTSTATUS NtStatus; int CurrentAllocatedSize = 0x6000; SYSTEM_PROCESS_INFORMATION *pCurrentProcessInfo; unsigned char *pCurrentPos; int NumberOfProcesses; int i; BOOL fResult;
do { if (pProcessDataBuffer) { fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE); ASSERT(fResult); }
CurrentAllocatedSize += 4096 * 2; pProcessDataBuffer = VirtualAlloc(NULL, CurrentAllocatedSize, MEM_COMMIT, PAGE_READWRITE); if (pProcessDataBuffer == NULL) return RPC_S_OUT_OF_MEMORY;
NtStatus = NtQuerySystemInformation(SystemProcessInformation, pProcessDataBuffer, CurrentAllocatedSize, NULL); } while (NtStatus == STATUS_INFO_LENGTH_MISMATCH);
if (!NT_SUCCESS(NtStatus)) return RPC_S_OUT_OF_MEMORY;
// walk the buffer - on first pass, we just count the entries
pCurrentPos = (unsigned char *)pProcessDataBuffer; pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos; NumberOfProcesses = 0; while (TRUE) { // we skip idle process and zombie processes
if (pCurrentProcessInfo->UniqueProcessId != NULL) { NumberOfProcesses ++; } // is there a place to advance to?
if (pCurrentProcessInfo->NextEntryOffset == 0) break; pCurrentPos += pCurrentProcessInfo->NextEntryOffset; pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos; }
pNewState = (ServerEnumerationState *) new char [ sizeof(ServerEnumerationState) + (NumberOfProcesses - 1) * sizeof(ULONG)]; // implicit placement
// pNewState = new ((NumberOfProcesses - 1) * sizeof(ULONG)) ServerEnumerationState;
if (pNewState == NULL) { fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE); ASSERT(fResult); return RPC_S_OUT_OF_MEMORY; }
new (pNewState) ServerEnumerationState; // make the second pass - actual copying of data
pCurrentPos = (unsigned char *)pProcessDataBuffer; pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos; i = 0; while (TRUE) { // we skip idle process and zombie processes
if (pCurrentProcessInfo->UniqueProcessId != NULL) { pNewState->ProcessUniqueId[i] = PtrToUlong(pCurrentProcessInfo->UniqueProcessId); i ++; } // is there a place to advance to?
if (pCurrentProcessInfo->NextEntryOffset == 0) break; pCurrentPos += pCurrentProcessInfo->NextEntryOffset; pCurrentProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pCurrentPos; }
ASSERT(i == NumberOfProcesses);
fResult = VirtualFree(pProcessDataBuffer, 0, MEM_RELEASE); ASSERT(fResult);
// make the data available to the user
pNewState->CurrentPosition = 0; pNewState->NumberOfProcesses = NumberOfProcesses; *pHandle = pNewState; return RPC_S_OK; }
RPC_STATUS OpenNextRPCServer(IN ServerEnumerationHandle Handle, OUT CellEnumerationHandle *pHandle) { ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle; int CurrentPosition; RPC_STATUS RpcStatus; ASSERT(ServerState != NULL); ASSERT(pHandle != NULL);
do { CurrentPosition = ServerState->CurrentPosition;
if (CurrentPosition >= ServerState->NumberOfProcesses) return RPC_S_INVALID_BOUND;
ServerState->CurrentPosition ++; RpcStatus = OpenRPCServerDebugInfo(ServerState->ProcessUniqueId[CurrentPosition], pHandle); } while(RpcStatus == ERROR_FILE_NOT_FOUND);
return RpcStatus; }
void ResetServerEnumeration(IN ServerEnumerationHandle Handle) { ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle; ASSERT(ServerState != NULL); ServerState->CurrentPosition = 0; }
void FinishServerEnumeration(ServerEnumerationHandle *pHandle) { ServerEnumerationState *ServerState;
ASSERT (pHandle != NULL); ServerState = *(ServerEnumerationState **)pHandle; ASSERT(ServerState != NULL); delete ServerState; *pHandle = NULL; }
DWORD GetCurrentServerPID(IN ServerEnumerationHandle Handle) { ServerEnumerationState *ServerState = (ServerEnumerationState *)Handle; ASSERT(ServerState != NULL); // -1, because the CurrentPosition points to the next server
return (DWORD)ServerState->ProcessUniqueId[ServerState->CurrentPosition - 1]; }
// a helper function
// whenever we detect an inconsistency in one of the lists,
// we can call this function, which will determine what to do
// with the current section, and will transfer sections between
// the OpenedSections list and the InconsistentSections list
void InconsistencyDetected(IN LIST_ENTRY *OpenedSections, IN LIST_ENTRY *InconsistentSections, IN LIST_ENTRY *CurrentListEntry, IN OpenedDbgSection *pCurrentSection, BOOL fExceptionOccurred) { LIST_ENTRY *NextEntry; LIST_ENTRY *LastEntry;
// if an exception occurred, throw away this section altogether
if (fExceptionOccurred) { // save the next entry before we delete this one
NextEntry = CurrentListEntry->Flink; RemoveEntryList(CurrentListEntry); CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer); delete pCurrentSection;
CurrentListEntry = NextEntry; pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
// if the bad section was the last on the list,
// there is nothing to add to the grab bag - just
// return
if (CurrentListEntry == OpenedSections) { return; } }
// the chain is broken - we need to throw the rest of the list in
// the grab bag
// unchain this segment from the opened sections list
LastEntry = OpenedSections->Blink; OpenedSections->Blink = CurrentListEntry->Blink; CurrentListEntry->Blink->Flink = OpenedSections; // chain the segment to the inconsistent sections list
CurrentListEntry->Blink = InconsistentSections->Blink; InconsistentSections->Blink->Flink = CurrentListEntry; InconsistentSections->Blink = LastEntry; LastEntry->Flink = InconsistentSections; }
RPC_STATUS OpenRPCServerDebugInfo(IN DWORD ProcessID, OUT CellEnumerationHandle *pHandle) { RPC_STATUS RpcStatus; HANDLE SecHandle; PVOID SecPointer; int Retries = 10; BOOL fConsistentSnapshotObtained = FALSE; BOOL fNeedToRetry; CellSection *CurrentSection; DWORD SectionNumbers[2]; OpenedDbgSection *pCurrentSection; // each section as it is opened, is linked on one of those lists
// if the view of the sections is consistent, we link it to opened
// sections. Otherwise, we link it to InconsistentSections
LIST_ENTRY OpenedSections; LIST_ENTRY InconsistentSections; LIST_ENTRY *CurrentListEntry; DWORD *pActualSectionNumbers; BOOL fExceptionOccurred; LIST_ENTRY *LastEntry; BOOL fFound; int NumberOfCommittedPages; BOOL fConsistencyPass = FALSE; DWORD LocalPageSize; SectionsSnapshot *LocalSectionsSnapshot; BOOL fResult;
RpcStatus = InitializeDbgLib(); if (RpcStatus != RPC_S_OK) return RpcStatus;
LocalPageSize = GetPageSize();
// loop until we obtain a consistent snapshot or we are out of
// retry attempts. We declare a snapshot to be consistent
// if we manage to:
// - open all sections
// - copy their contents to a private memory location
// - verify that the section chain is still consistent after the copying
// For this purpose, when we copy all the sections, we make one more
// pass at the section chain to verify it is consistent using the special
// flag fConsistencyPass.
InconsistentSections.Blink = InconsistentSections.Flink = &InconsistentSections; OpenedSections.Blink = OpenedSections.Flink = &OpenedSections;
while (Retries > 0) { // on entry to the loop, the state will be this - OpenSections will
// contain a consistent view of the sections. Inconsistent sections
// will be a grab bag of sections we could not bring into
// consistent view. It's used as a cache to facilitate quick
// recovery
// we are just starting, or we are recovering from an inconsistency
// found somewhere. As soon as somebody detects an inconsistency,
// they will jump here. First thing is to try to establish what
// part of the chain is consistent. Walk the open sections for
// this purpose. We walk as far as we can, and then we declare
// the rest of the sections inconsistent, and we throw them in
// the grab bag
SectionNumbers[0] = SectionNumbers[1] = 0; CurrentListEntry = OpenedSections.Flink; fNeedToRetry = FALSE; while (CurrentListEntry != &OpenedSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); if ((SectionNumbers[0] != pCurrentSection->SectionNumbers[0]) || (SectionNumbers[1] != pCurrentSection->SectionNumbers[1])) { fNeedToRetry = TRUE; } else { __try { // attempt to read the numbers of the next section
// we do this within try/except since server may free this
// memory and we will get toast
SectionNumbers[0] = pCurrentSection->SectionPointer->NextSectionId[0]; SectionNumbers[1] = pCurrentSection->SectionPointer->NextSectionId[1];
fExceptionOccurred = FALSE;
// note that the SectionNumbers array will be used after the end of
// the loop - make sure we don't whack them
} __except (EXCEPTION_EXECUTE_HANDLER) { fExceptionOccurred = TRUE; fNeedToRetry = TRUE; } }
if (fNeedToRetry) { // if this is the first section, the server went down. There is no
// legal way for the server to have inconsistent first section
if (CurrentListEntry == OpenedSections.Flink) { RpcStatus = ERROR_FILE_NOT_FOUND; goto CleanupAndExit; }
InconsistencyDetected(&OpenedSections, &InconsistentSections, CurrentListEntry, pCurrentSection, fExceptionOccurred);
fNeedToRetry = TRUE; break; }
CurrentListEntry = CurrentListEntry->Flink; }
// walking is complete. Did we detect inconsistency?
if (fNeedToRetry) { Retries --; fConsistencyPass = FALSE; continue; } else if (fConsistencyPass) { // this is the only place we break out of the loop -
// the consistency pass has passed
break; }
// whatever we have in the opened sections list is consistent
// if there was something in the list keep reading,
// otherwise, start reading
if (IsListEmpty(&OpenedSections)) { pActualSectionNumbers = NULL; } else { pCurrentSection = CONTAINING_RECORD(OpenedSections.Blink, OpenedDbgSection, SectionsList); // we re-use the section numbers from the loop above. They can be 0 at
// this point if the last section got dropped
pActualSectionNumbers = SectionNumbers; }
// make a pass over the sections, opening each one, but only if
// case we're missing parts of the chain or this is the first time.
// Otherwise, skip this step
while ((SectionNumbers[0] != 0) || (SectionNumbers[1] != 0) || (pActualSectionNumbers == NULL)) { // we know which section we're looking for
// first, search the grab bag. We can only do this for a non-first
// section. The first section never goes to the grab bag
// pActualSectionNumbers will contain the section we're looking for
fFound = FALSE; if (pActualSectionNumbers) { CurrentListEntry = InconsistentSections.Flink; while (CurrentListEntry != &InconsistentSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); // it is impossible that a well behaving server will have
// opened a different section with the same numbers, because we
// keep the section object opened.
if ((pActualSectionNumbers[0] == pCurrentSection->SectionNumbers[0]) && (pActualSectionNumbers[1] == pCurrentSection->SectionNumbers[1])) { // found something
RemoveEntryList(CurrentListEntry);
// if we had already made a copy of this one, free it, as it is
// probably inconsistent
if (pCurrentSection->SectionCopy) { fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE); ASSERT(fResult); pCurrentSection->SectionCopy = NULL; } fFound = TRUE; break; } CurrentListEntry = CurrentListEntry->Flink; } }
if (fFound == FALSE) { // nothing in the grab bag - try to open it the normal way
RpcStatus = OpenDbgSection(&SecHandle, &SecPointer, ProcessID, pActualSectionNumbers); if (RpcStatus == ERROR_FILE_NOT_FOUND) { // if this is the first time, this is not a server - bail out
if (pActualSectionNumbers == NULL) { goto CleanupAndExit; }
// not the first time - we have an inconsistent view - need to retry
fNeedToRetry = TRUE; break; } else if (RpcStatus != RPC_S_OK) { goto CleanupAndExit; }
pCurrentSection = new OpenedDbgSection; if (pCurrentSection == NULL) { RpcStatus = RPC_S_OUT_OF_MEMORY; CloseDbgSection(SecHandle, SecPointer); goto CleanupAndExit; }
pCurrentSection->SectionHandle = SecHandle; if (pActualSectionNumbers) { pCurrentSection->SectionNumbers[0] = pActualSectionNumbers[0]; pCurrentSection->SectionNumbers[1] = pActualSectionNumbers[1]; } else { pCurrentSection->SectionNumbers[0] = pCurrentSection->SectionNumbers[1] = 0; } pCurrentSection->SectionPointer = (CellSection *) SecPointer; pCurrentSection->SectionCopy = NULL; }
// either we have found this in the grab bag, or we have just opened it
// both ways, try to get the section numbers we expect for the next section
__try { // load the section numbers that we expect for the next iteration of the
// loop
SectionNumbers[0] = pCurrentSection->SectionPointer->NextSectionId[0]; SectionNumbers[1] = pCurrentSection->SectionPointer->NextSectionId[1]; pActualSectionNumbers = SectionNumbers; fExceptionOccurred = FALSE; } __except (EXCEPTION_EXECUTE_HANDLER) { fExceptionOccurred = TRUE; }
if (fExceptionOccurred) { delete pCurrentSection; CloseDbgSection(SecHandle, SecPointer); fNeedToRetry = TRUE; break; }
InsertTailList(&OpenedSections, &pCurrentSection->SectionsList); }
if (fNeedToRetry) { Retries --; fConsistencyPass = FALSE; continue; }
// at this point, we have opened all the sections
// now we need to allocate memory for the snapshots and to do the copying
CurrentListEntry = OpenedSections.Flink; while (CurrentListEntry != &OpenedSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); __try { // do all the allocation and copying only if it hasn't been done yet
if (pCurrentSection->SectionCopy == NULL) { NumberOfCommittedPages = pCurrentSection->SectionPointer->LastCommittedPage; pCurrentSection->SectionCopy = (CellSection *)VirtualAlloc(NULL, NumberOfCommittedPages * LocalPageSize, MEM_COMMIT, PAGE_READWRITE); if (pCurrentSection->SectionCopy == NULL) { RpcStatus = RPC_S_OUT_OF_MEMORY; goto CleanupAndExit; } memcpy(pCurrentSection->SectionCopy, pCurrentSection->SectionPointer, NumberOfCommittedPages * LocalPageSize); pCurrentSection->SectionID = pCurrentSection->SectionPointer->SectionID; pCurrentSection->CommittedPagesInSection = NumberOfCommittedPages; } fExceptionOccurred = FALSE; } __except (EXCEPTION_EXECUTE_HANDLER) { fExceptionOccurred = TRUE; }
if (fExceptionOccurred) { if (pCurrentSection->SectionCopy) { fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE); ASSERT(fResult); pCurrentSection->SectionCopy = NULL; }
// the section got out of sync
InconsistencyDetected(&OpenedSections, &InconsistentSections, CurrentListEntry, pCurrentSection, fExceptionOccurred); fNeedToRetry = TRUE; break; }
CurrentListEntry = CurrentListEntry->Flink; }
if (fNeedToRetry) { Retries --; fConsistencyPass = FALSE; continue; } else { fConsistencyPass = TRUE; } }
// if we managed to get a consistent view, unmap the shared sections and
// save the opened section list
if (Retries != 0) { ASSERT(fConsistencyPass == TRUE); ASSERT(fNeedToRetry == FALSE); ASSERT(!IsListEmpty(&OpenedSections));
CurrentListEntry = OpenedSections.Flink; while (CurrentListEntry != &OpenedSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList);
CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer); pCurrentSection->SectionHandle = NULL; pCurrentSection->SectionPointer = NULL; pCurrentSection->SectionNumbers[0] = pCurrentSection->SectionNumbers[1] = 0;
CurrentListEntry = CurrentListEntry->Flink; }
// save the opened section list
CurrentListEntry = OpenedSections.Flink; pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); LocalSectionsSnapshot = new SectionsSnapshot; if (LocalSectionsSnapshot != NULL) { LocalSectionsSnapshot->CellIndex = 0; LocalSectionsSnapshot->FirstOpenedSection = pCurrentSection; LocalSectionsSnapshot->CurrentOpenedSection = pCurrentSection;
// unchain the opened sections
// terminate the chain with NULL
OpenedSections.Blink->Flink = NULL; OpenedSections.Blink = OpenedSections.Flink = &OpenedSections;
// that's the only place where we return success
*pHandle = (CellEnumerationHandle)LocalSectionsSnapshot; RpcStatus = RPC_S_OK; } else { // let the CleanupAndExit code destroy the lists
RpcStatus = RPC_S_OUT_OF_MEMORY; } } else { // we couldn't get a consistent snapshot of the server and
// we ran out of retries
RpcStatus = RPC_S_CANNOT_SUPPORT; }
CleanupAndExit:
// walk the two lists, and free all sections on them
CurrentListEntry = OpenedSections.Flink; while (CurrentListEntry != &OpenedSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); // advance the pointer while we haven't freed the stuff
CurrentListEntry = CurrentListEntry->Flink; if (pCurrentSection->SectionCopy) { fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE); ASSERT(fResult); } if (pCurrentSection->SectionHandle) { ASSERT(pCurrentSection->SectionPointer); CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer); } delete pCurrentSection; }
CurrentListEntry = InconsistentSections.Flink; while (CurrentListEntry != &InconsistentSections) { pCurrentSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); // advance the pointer while we haven't freed the stuff
CurrentListEntry = CurrentListEntry->Flink; if (pCurrentSection->SectionCopy) { fResult = VirtualFree(pCurrentSection->SectionCopy, 0, MEM_RELEASE); ASSERT(fResult); } if (pCurrentSection->SectionHandle) { ASSERT(pCurrentSection->SectionPointer); CloseDbgSection(pCurrentSection->SectionHandle, pCurrentSection->SectionPointer); } delete pCurrentSection; } return RpcStatus; }
DebugCellUnion *GetNextDebugCellInfo(IN CellEnumerationHandle Handle, OUT DebugCellID *CellID) { SectionsSnapshot *Snapshot = (SectionsSnapshot *)Handle; OpenedDbgSection *CurrentSection, *NextSection; DebugCellGeneric *CurrentCell; int CurrentCellIndex; DebugCellGeneric *LastCellForCurrentSection; DWORD LocalPageSize = GetPageSize();
ASSERT(Handle != NULL);
CurrentSection = Snapshot->CurrentOpenedSection; LastCellForCurrentSection = GetLastCellForSection(CurrentSection, LocalPageSize); if (Snapshot->CellIndex == 0) { #ifdef _WIN64
Snapshot->CellIndex = 2; #else
Snapshot->CellIndex = 1; #endif
} CurrentCell = GetCellForSection(CurrentSection, Snapshot->CellIndex);
while (TRUE) { // did we exhaust the current section?
if (CurrentCell > LastCellForCurrentSection) { // try to advance to the next one
if (CurrentSection->SectionsList.Flink) { CurrentSection = CONTAINING_RECORD(CurrentSection->SectionsList.Flink, OpenedDbgSection, SectionsList); Snapshot->CurrentOpenedSection = CurrentSection; #ifdef _WIN64
Snapshot->CellIndex = 2; #else
Snapshot->CellIndex = 1; #endif
LastCellForCurrentSection = GetLastCellForSection(CurrentSection, LocalPageSize);
CurrentCell = GetCellForSection(CurrentSection, Snapshot->CellIndex); continue; } return NULL; } CellID->CellID = (USHORT) Snapshot->CellIndex; Snapshot->CellIndex ++; if ((CurrentCell->Type == dctCallInfo) || (CurrentCell->Type == dctThreadInfo) || (CurrentCell->Type == dctEndpointInfo) || (CurrentCell->Type == dctClientCallInfo)) { CellID->SectionID = (USHORT)CurrentSection->SectionID; return (DebugCellUnion *)CurrentCell; } CurrentCell = (DebugCellGeneric *)((unsigned char *)CurrentCell + sizeof(DebugFreeCell)); }
return NULL; }
void ResetRPCServerDebugInfo(IN CellEnumerationHandle Handle) { SectionsSnapshot *LocalSnapshot = (SectionsSnapshot *)Handle;
ASSERT(Handle != NULL); LocalSnapshot->CellIndex = 0; LocalSnapshot->CurrentOpenedSection = LocalSnapshot->FirstOpenedSection; }
void CloseRPCServerDebugInfo(IN CellEnumerationHandle *pHandle) { SectionsSnapshot *LocalSnapshot; OpenedDbgSection *DbgSection; LIST_ENTRY *CurrentListEntry;
ASSERT(pHandle != NULL); LocalSnapshot = (SectionsSnapshot *)*pHandle; ASSERT(LocalSnapshot != NULL); ASSERT(LocalSnapshot->FirstOpenedSection != NULL);
DbgSection = LocalSnapshot->FirstOpenedSection;
do { // advance while we can
CurrentListEntry = DbgSection->SectionsList.Flink;
// free the section
ASSERT(DbgSection->SectionCopy); VirtualFree(DbgSection->SectionCopy, 0, MEM_RELEASE); delete DbgSection;
// calculate next record. Note that this will not AV even if
// CurrentListEntry is NULL - this is just offset calculation
DbgSection = CONTAINING_RECORD(CurrentListEntry, OpenedDbgSection, SectionsList); } while (CurrentListEntry != NULL);
delete LocalSnapshot;
*pHandle = NULL; }
typedef struct tagRPCSystemWideCellEnumeration { ServerEnumerationHandle serverHandle; CellEnumerationHandle cellHandle; } RPCSystemWideCellEnumeration;
RPC_STATUS OpenRPCSystemWideCellEnumeration(OUT RPCSystemWideCellEnumerationHandle *pHandle) { RPCSystemWideCellEnumeration *cellEnum; RPC_STATUS Status; DebugCellUnion *NextCell;
ASSERT(pHandle != NULL); *pHandle = NULL; cellEnum = new RPCSystemWideCellEnumeration; if (cellEnum == NULL) return RPC_S_OUT_OF_MEMORY;
cellEnum->cellHandle = NULL; cellEnum->serverHandle = NULL;
Status = StartServerEnumeration(&cellEnum->serverHandle); if (Status != RPC_S_OK) { delete cellEnum; return Status; }
Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle);
// if we're done, we will get RPC_S_SERVER_INVALID_BOUND - ok to
// just return to caller
if (Status != RPC_S_OK) { FinishServerEnumeration(&cellEnum->serverHandle); delete cellEnum; return Status; }
*pHandle = (RPCSystemWideCellEnumerationHandle) cellEnum; return RPC_S_OK; }
RPC_STATUS GetNextRPCSystemWideCell(IN RPCSystemWideCellEnumerationHandle handle, OUT DebugCellUnion **NextCell, OUT DebugCellID *CellID, OUT DWORD *ServerPID OPTIONAL) { RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle; RPC_STATUS Status;
ASSERT(cellEnum != NULL);
// loop skipping empty servers
do { *NextCell = GetNextDebugCellInfo(cellEnum->cellHandle, CellID);
// this server is done - move on to the next
if (*NextCell == NULL) { CloseRPCServerDebugInfo(&cellEnum->cellHandle); Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle);
// if we're done with all servers, we will get RPC_S_SERVER_INVALID_BOUND - ok to
// just return to caller. Caller needs to call us back to finish enumeration
if (Status != RPC_S_OK) { // remember that this failed so that we don't try to clean it up
// when finishing the enumeration
cellEnum->cellHandle = NULL; return Status; } } } while(*NextCell == NULL);
if (ServerPID && (*NextCell != NULL)) { *ServerPID = GetCurrentServerPID(cellEnum->serverHandle); }
return RPC_S_OK; }
DebugCellUnion *GetRPCSystemWideCellFromCellID(IN RPCSystemWideCellEnumerationHandle handle, IN DebugCellID CellID) { RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle;
return GetCellByDebugCellID(cellEnum->cellHandle, CellID); }
void FinishRPCSystemWideCellEnumeration(IN OUT RPCSystemWideCellEnumerationHandle *pHandle) { RPCSystemWideCellEnumeration *cellEnum;
ASSERT(pHandle != NULL); cellEnum = (RPCSystemWideCellEnumeration *)*pHandle; ASSERT(cellEnum != NULL);
if (cellEnum->cellHandle) { CloseRPCServerDebugInfo(&cellEnum->cellHandle); } FinishServerEnumeration(&cellEnum->serverHandle); delete cellEnum; *pHandle = NULL; }
RPC_STATUS ResetRPCSystemWideCellEnumeration(IN RPCSystemWideCellEnumerationHandle handle) { RPCSystemWideCellEnumeration *cellEnum = (RPCSystemWideCellEnumeration *)handle; RPC_STATUS Status;
ASSERT(cellEnum != NULL);
if (cellEnum->cellHandle) { CloseRPCServerDebugInfo(&cellEnum->cellHandle); cellEnum->cellHandle = NULL; }
ResetServerEnumeration(cellEnum->serverHandle);
Status = OpenNextRPCServer(cellEnum->serverHandle, &cellEnum->cellHandle); if (Status != RPC_S_OK) { // remember that this failed so that we don't try to clean it up
// when finishing the enumeration
cellEnum->cellHandle = NULL; } return Status; }
|