Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Fix finding entry point unwind record for a method with fragmented un… #22202

Merged
merged 3 commits into from
Jan 28, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions src/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,35 @@ BOOL IsFunctionFragment(TADDR baseAddress, PTR_RUNTIME_FUNCTION pFunctionEntry)
#endif
}

// When we have fragmented unwind we usually want to refer to the
// unwind record that includes the prolog. We can find it by searching
// back in the sequence of unwind records.
PTR_RUNTIME_FUNCTION FindRootEntry(PTR_RUNTIME_FUNCTION pFunctionEntry, TADDR baseAddress)
{
LIMITED_METHOD_DAC_CONTRACT;

PTR_RUNTIME_FUNCTION pRootEntry = pFunctionEntry;

if (pRootEntry != NULL)
{
// Walk backwards in the RUNTIME_FUNCTION array until we find a non-fragment.
// We're guaranteed to find one, because we require that a fragment live in a function or funclet
// that has a prolog, which will have non-fragment .xdata.
for (;;)
{
if (!IsFunctionFragment(baseAddress, pRootEntry))
{
// This is not a fragment; we're done
break;
}

--pRootEntry;
}
}

return pRootEntry;
}

#endif // EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS


Expand Down Expand Up @@ -1078,31 +1107,13 @@ TADDR IJitManager::GetFuncletStartAddress(EECodeInfo * pCodeInfo)
#endif

TADDR baseAddress = pCodeInfo->GetModuleBase();
TADDR funcletStartAddress = baseAddress + RUNTIME_FUNCTION__BeginAddress(pFunctionEntry);

#if defined(EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS)
// Is the RUNTIME_FUNCTION a fragment? If so, we need to walk backwards until we find the first
// non-fragment RUNTIME_FUNCTION, and use that one. This happens when we have very large functions
// and multiple RUNTIME_FUNCTION entries per function or funclet. However, all but the first will
// have the "F" bit set in the unwind data, indicating a fragment (with phantom prolog unwind codes).

for (;;)
{
if (!IsFunctionFragment(baseAddress, pFunctionEntry))
{
// This is not a fragment; we're done
break;
}

// We found a fragment. Walk backwards in the RUNTIME_FUNCTION array until we find a non-fragment.
// We're guaranteed to find one, because we require that a fragment live in a function or funclet
// that has a prolog, which will have non-fragment .xdata.
--pFunctionEntry;

funcletStartAddress = baseAddress + RUNTIME_FUNCTION__BeginAddress(pFunctionEntry);
}
pFunctionEntry = FindRootEntry(pFunctionEntry, baseAddress);
#endif // EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS

TADDR funcletStartAddress = baseAddress + RUNTIME_FUNCTION__BeginAddress(pFunctionEntry);

return funcletStartAddress;
}

Expand Down Expand Up @@ -3878,6 +3889,8 @@ void EEJitManager::NibbleMapSet(HeapList * pHp, TADDR pCode, BOOL bSet)
#endif // !DACCESS_COMPILE

#if defined(WIN64EXCEPTIONS)
// Note: This returns the root unwind record (the one that describes the prolog)
// in cases where there is fragmented unwind.
PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo)
{
CONTRACTL {
Expand Down Expand Up @@ -3907,6 +3920,12 @@ PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo)

if (RUNTIME_FUNCTION__BeginAddress(pFunctionEntry) <= address && address < RUNTIME_FUNCTION__EndAddress(pFunctionEntry, baseAddress))
{

#if defined(EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS)
// If we may have fragmented unwind make sure we're returning the root record
pFunctionEntry = FindRootEntry(pFunctionEntry, baseAddress);
#endif

return pFunctionEntry;
}
}
Expand Down