diff --git a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp index 6f73af4e6b3c4..b8c6769db20d9 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp @@ -28,7 +28,6 @@ #define UBF_FUNC_HAS_EHINFO 0x04 #define UBF_FUNC_REVERSE_PINVOKE 0x08 #define UBF_FUNC_HAS_ASSOCIATED_DATA 0x10 -#define UBF_FUNC_HAS_PROLOG_LENGTH 0x20 struct UnixNativeMethodInfo { @@ -41,8 +40,6 @@ struct UnixNativeMethodInfo unw_word_t unwind_info; uint32_t format; - uint8_t prolog_length; - bool executionAborted; }; @@ -71,8 +68,7 @@ bool UnixNativeCodeManager::VirtualUnwind(MethodInfo* pMethodInfo, REGDISPLAY* p UnixNativeMethodInfo * pNativeMethodInfo = (UnixNativeMethodInfo *)pMethodInfo; return UnwindHelpers::StepFrame( - pRegisterSet, pNativeMethodInfo->start_ip, pNativeMethodInfo->format, pNativeMethodInfo->unwind_info, - pNativeMethodInfo->prolog_length); + pRegisterSet, pNativeMethodInfo->start_ip, pNativeMethodInfo->format, pNativeMethodInfo->unwind_info); } bool UnixNativeCodeManager::FindMethodInfo(PTR_VOID ControlPC, @@ -128,15 +124,6 @@ bool UnixNativeCodeManager::FindMethodInfo(PTR_VOID ControlPC, pMethodInfo->pMethodStartAddress = dac_cast(procInfo.start_ip); } - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - { - pMethodInfo->prolog_length = *p++; - } - else - { - pMethodInfo->prolog_length = 0; - } - pMethodInfo->executionAborted = false; return true; @@ -181,9 +168,6 @@ uint32_t UnixNativeCodeManager::GetCodeOffset(MethodInfo* pMethodInfo, PTR_VOID uint8_t unwindBlockFlags = *p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) p += sizeof(int32_t); @@ -280,9 +264,6 @@ uintptr_t UnixNativeCodeManager::GetConservativeUpperBoundForOutgoingArgs(Method // Reverse PInvoke transition should be on the main function body only assert(pNativeMethodInfo->pMainLSDA == pNativeMethodInfo->pLSDA); - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) p += sizeof(int32_t); @@ -345,9 +326,6 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo, // Reverse PInvoke transition should be on the main function body only assert(pNativeMethodInfo->pMainLSDA == pNativeMethodInfo->pLSDA); - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) p += sizeof(int32_t); @@ -400,7 +378,78 @@ bool UnixNativeCodeManager::IsUnwindable(PTR_VOID pvAddress) #endif // VirtualUnwind can't unwind epilogues. - return TrailingEpilogueInstructionsCount(pMethodInfo, pvAddress) == 0; + return TrailingEpilogueInstructionsCount(pMethodInfo, pvAddress) == 0 && IsInProlog(pMethodInfo, pvAddress) != 1; +} + +// checks for known prolog instructions generated by ILC and returns +// 1 - in prolog +// 0 - not in prolog, +// -1 - unknown. +int UnixNativeCodeManager::IsInProlog(MethodInfo * pMethodInfo, PTR_VOID pvAddress) +{ +#if defined(TARGET_ARM64) + +// post/pre + + +// stp with signed offset +// x010 1001 00xx xxxx xxxx xxxx xxxx xxxx +#define STP_BITS1 0x29000000 +#define STP_MASK1 0x7FC00000 + +// stp with pre/post/no offset +// x010 100x x0xx xxxx xxxx xxxx xxxx xxxx +#define STP_BITS2 0x28000000 +#define STP_MASK2 0x7E400000 + +// add fp, sp, x +// mov fp, sp +// 1001 0001 0xxx xxxx xxxx xx11 1111 1101 +#define ADD_FP_SP_BITS 0x910003FD +#define ADD_FP_SP_MASK 0xFF8003FF + +#define STP_RT2_RT_MASK 0x7C1F +#define STP_RT2_RT_FP_LR 0x781D +#define STP_RN_MASK 0x3E0 +#define STP_RN_SP 0x3E0 +#define STP_RN_FP 0x3A0 + + + UnixNativeMethodInfo * pNativeMethodInfo = (UnixNativeMethodInfo *)pMethodInfo; + ASSERT(pNativeMethodInfo != NULL); + + uint32_t* start = (uint32_t*)pNativeMethodInfo->pMethodStartAddress; + bool savedFpLr = false; + bool establishedFp = false; + + for (uint32_t* pInstr = (uint32_t*)start; pInstr < pvAddress && !(savedFpLr && establishedFp); pInstr++) + { + uint32_t instr = *pInstr; + + if (((instr & STP_MASK1) == STP_BITS1 || (instr & STP_MASK2) == STP_BITS2) && + ((instr & STP_RN_MASK) == STP_RN_SP || (instr & STP_RN_MASK) == STP_RN_FP)) + { + // SP/FP-relative store of pair of registers + savedFpLr |= (instr & STP_RT2_RT_MASK) == STP_RT2_RT_FP_LR; + } + else if ((instr & ADD_FP_SP_MASK) == ADD_FP_SP_BITS) + { + establishedFp = true; + } + else + { + // TODO: Detect saving non-paired register, stack pointer adjustments + return -1; + } + } + + return savedFpLr && establishedFp ? 0 : 1; + +#else + + return -1; + +#endif } // when stopped in an epilogue, returns the count of remaining stack-consuming instructions @@ -714,9 +763,6 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) return false; - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) p += sizeof(int32_t); @@ -744,6 +790,20 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn return true; } +#if defined(TARGET_APPLE) && defined(TARGET_ARM64) + // If we are inside a prolog without a saved frame then we cannot safely unwind. + // + // Some known frame layouts use compact unwind encoding which cannot handle unwinding + // inside prolog or epilog, so don't even try that. These known sequences must be + // recognized by IsInProlog. Any other instruction sequence, known or unknown, falls + // through to the platform unwinder which should have DWARF information about the + // frame. + if (IsInProlog(pMethodInfo, (PTR_VOID)pRegisterSet->IP) == 1) + { + return false; + } +#endif + ASSERT(IsUnwindable((PTR_VOID)pRegisterSet->IP)); // Unwind the current method context to the caller's context to get its stack pointer @@ -836,9 +896,6 @@ bool UnixNativeCodeManager::EHEnumInit(MethodInfo * pMethodInfo, PTR_VOID * pMet uint8_t unwindBlockFlags = *p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) p += sizeof(int32_t); @@ -952,9 +1009,6 @@ PTR_VOID UnixNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC) if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT) p += sizeof(uint32_t); - if ((unwindBlockFlags & UBF_FUNC_HAS_PROLOG_LENGTH) != 0) - p++; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) == 0) return NULL; diff --git a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h index 5998572edeb98..9c129cc1fd3f3 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h +++ b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h @@ -63,6 +63,8 @@ class UnixNativeCodeManager : public ICodeManager bool IsUnwindable(PTR_VOID pvAddress); + int IsInProlog(MethodInfo * pMethodInfo, PTR_VOID pvAddress); + int TrailingEpilogueInstructionsCount(MethodInfo * pMethodInfo, PTR_VOID pvAddress); bool GetReturnAddressHijackInfo(MethodInfo * pMethodInfo, diff --git a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp index 62e7ba195e33a..9d12e7a91933f 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp @@ -761,19 +761,12 @@ void Registers_REGDISPLAY::setVectorRegister(int num, libunwind::v128 value) #endif // TARGET_ARM64 -bool UnwindHelpers::StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t format, unw_word_t unwind_info, uint8_t prolog_length) +bool UnwindHelpers::StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t format, unw_word_t unwind_info) { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND - // Compact unwinding doesn't support asynchronous unwinding in prolog. We can interpret a code - // subset in some cases if it becomes necessary. - if (regs->GetIP() - start_ip < prolog_length) - { - return false; - } - #if defined(TARGET_ARM64) if ((format & UNWIND_ARM64_MODE_MASK) != UNWIND_ARM64_MODE_DWARF) { CompactUnwinder_arm64 compactInst; diff --git a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.h b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.h index 877c45fd4c647..2e9d7a299e0e0 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.h +++ b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.h @@ -13,6 +13,6 @@ class UnwindHelpers { public: - static bool StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t format, unw_word_t unwind_info, uint8_t prolog_length); + static bool StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t format, unw_word_t unwind_info); static bool GetUnwindProcInfo(PCODE ip, libunwind::UnwindInfoSections &uwInfoSections, unw_proc_info_t *procInfo); }; diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs index b618d27674149..62e8c282fc334 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs @@ -14,8 +14,6 @@ public enum FrameInfoFlags HasEHInfo = 0x04, ReversePInvoke = 0x08, HasAssociatedData = 0x10, - - HasPrologLength = 0x20, } public struct FrameInfo diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs index c3c036de0e98d..c59315de5304c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -644,7 +644,6 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) int len = frameInfo.BlobData.Length; byte[] blob = frameInfo.BlobData; bool emitDwarf = true; - byte dwarfPrologLength = 0; ObjectNodeSection lsdaSection = LsdaSection; if (ShouldShareSymbol(node)) @@ -662,19 +661,11 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) { _offsetToCfiCompactEncoding[start] = compactEncoding; emitDwarf = false; - - // Calculate the length of the prolog covered by DWARF codes - for (int j = 0; j < len; j += CfiCodeSize) - { - // The first byte of CFI_CODE is code offset. - dwarfPrologLength = Math.Max(blob[j], dwarfPrologLength); - } } FrameInfoFlags flags = frameInfo.Flags; flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0; flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0; - flags |= !emitDwarf ? FrameInfoFlags.HasPrologLength : 0; EmitIntValue((byte)flags, 1); @@ -686,11 +677,6 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) EmitIntValue((ulong)(start - frameInfos[0].StartOffset), 4); } - if (!emitDwarf) - { - EmitIntValue(dwarfPrologLength, 1); - } - if (associatedDataNode != null) { EmitSymbolReference(associatedDataNode, 0, RelocType.IMAGE_REL_BASED_RELPTR32);