From 1b8df831c0513c0f84327cfb82e71ab03c263873 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Mon, 28 Jan 2019 10:45:45 -0800 Subject: [PATCH] =?utf8?q?Fix=20finding=20entry=20point=20unwind=20record?= =?utf8?q?=20for=20a=20method=20with=20fragmented=20un=E2=80=A6=20(#22202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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. --- src/vm/codeman.cpp | 61 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp index 422cc28..663605b 100644 --- a/src/vm/codeman.cpp +++ b/src/vm/codeman.cpp @@ -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 @@ -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; } @@ -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 { @@ -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; } } -- 2.7.4