877 lines
31 KiB
C++
877 lines
31 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|