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

Commit

Permalink
Fix finding entry point unwind record for a method with fragmented un… (
Browse files Browse the repository at this point in the history
#22202)

On Arm and Arm64 unwind records can only cover a limited range of code
(512K and 1MB respectively). So for methods larger than this the jit
will emit multiple "fragment" unwind records to cover the full method code
range. Only the first of these describes the behavior of the method prolog.

When mapping an offset back to a method's entry point unwind, make sure to
find this "root" unwind record instead of one of the internal fragments.

Fixes #19209.
  • Loading branch information
AndyAyersMS authored Jan 28, 2019
1 parent ddd85a9 commit 1b8df83
Showing 1 changed file with 40 additions and 21 deletions.
61 changes: 40 additions & 21 deletions src/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,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 @@ -1075,31 +1104,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 @@ -3872,6 +3883,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 @@ -3900,6 +3913,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

0 comments on commit 1b8df83

Please sign in to comment.