Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix arm64 fragment unwinding #92678

Merged
merged 1 commit into from
Sep 27, 2023
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
63 changes: 21 additions & 42 deletions src/coreclr/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,35 +920,6 @@ 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.
while (true)
{
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 @@ -1134,12 +1105,30 @@ TADDR IJitManager::GetFuncletStartAddress(EECodeInfo * pCodeInfo)
#endif

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

#if defined(EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS)
pFunctionEntry = FindRootEntry(pFunctionEntry, baseAddress);
#endif // 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).

TADDR funcletStartAddress = baseAddress + RUNTIME_FUNCTION__BeginAddress(pFunctionEntry);
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);
}
#endif // EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS

return funcletStartAddress;
}
Expand Down Expand Up @@ -4133,8 +4122,6 @@ void EEJitManager::NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, BOOL bSet)
#endif // !DACCESS_COMPILE

#if defined(FEATURE_EH_FUNCLETS)
// 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 @@ -4163,14 +4150,6 @@ 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) && (defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64))
// If we might have fragmented unwind, and we're on ARM64/LoongArch64,
// make sure to returning the root record,
// as the trailing records don't have prolog unwind codes.
pFunctionEntry = FindRootEntry(pFunctionEntry, baseAddress);
#endif

return pFunctionEntry;
}
}
Expand Down
Loading