diff --git a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp index 7b4465966727da..658919608179ac 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp @@ -67,8 +67,7 @@ bool UnixNativeCodeManager::VirtualUnwind(MethodInfo* pMethodInfo, REGDISPLAY* p { UnixNativeMethodInfo * pNativeMethodInfo = (UnixNativeMethodInfo *)pMethodInfo; - return UnwindHelpers::StepFrame( - pRegisterSet, pNativeMethodInfo->start_ip, pNativeMethodInfo->format, pNativeMethodInfo->unwind_info); + return UnwindHelpers::StepFrame(pRegisterSet, pNativeMethodInfo->start_ip, pNativeMethodInfo->format, pNativeMethodInfo->unwind_info); } bool UnixNativeCodeManager::FindMethodInfo(PTR_VOID ControlPC, @@ -259,14 +258,14 @@ uintptr_t UnixNativeCodeManager::GetConservativeUpperBoundForOutgoingArgs(Method uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) { // Reverse PInvoke transition should be on the main function body only assert(pNativeMethodInfo->pMainLSDA == pNativeMethodInfo->pLSDA); - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) - p += sizeof(int32_t); - if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); @@ -321,14 +320,14 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo, uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) { // Reverse PInvoke transition should be on the main function body only assert(pNativeMethodInfo->pMainLSDA == pNativeMethodInfo->pLSDA); - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) - p += sizeof(int32_t); - if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); @@ -378,81 +377,7 @@ bool UnixNativeCodeManager::IsUnwindable(PTR_VOID pvAddress) #endif // VirtualUnwind can't unwind epilogues. - 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 - { - // JIT generates other patterns into the prolog that we currently don't - // recognize (saving unpaired register, stack pointer adjustments). We - // don't need to recognize these patterns unless a compact unwinding code - // is generated for them in ILC. - // https://github.com/dotnet/runtime/issues/76371 - return -1; - } - } - - return savedFpLr && establishedFp ? 0 : 1; - -#else - - return -1; - -#endif + return TrailingEpilogueInstructionsCount(pMethodInfo, pvAddress) == 0; } // when stopped in an epilogue, returns the count of remaining stack-consuming instructions @@ -757,6 +682,9 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + // Check whether this is a funclet if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT) return false; @@ -766,9 +694,6 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) return false; - if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) - p += sizeof(int32_t); - if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); @@ -793,20 +718,6 @@ 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 @@ -1008,10 +919,6 @@ PTR_VOID UnixNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC) PTR_UInt8 p = methodInfo.pLSDA; uint8_t unwindBlockFlags = *p++; - - if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT) - p += sizeof(uint32_t); - 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 9c129cc1fd3f3b..5998572edeb982 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h +++ b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h @@ -63,8 +63,6 @@ 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/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs index bef41e3d7ba351..9e7241048ff997 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -49,8 +49,6 @@ public class ObjectWriter : IDisposable, ITypesDebugInfoWriter private HashSet _offsetToCfiStart = new HashSet(); // Code offsets that ends a frame private HashSet _offsetToCfiEnd = new HashSet(); - // Code offsets to compact unwind encoding - private Dictionary _offsetToCfiCompactEncoding = new Dictionary(); // Used to assert whether frames are not overlapped. private bool _frameOpened; @@ -250,14 +248,6 @@ public void EmitCFICode(int nativeOffset, byte[] blob) EmitCFICode(_nativeObjectWriter, nativeOffset, blob); } - [DllImport(NativeObjectWriterFileName)] - private static extern void EmitCFICompactUnwindEncoding(IntPtr objWriter, uint encoding); - public void EmitCFICompactUnwindEncoding(uint encoding) - { - Debug.Assert(_frameOpened); - EmitCFICompactUnwindEncoding(_nativeObjectWriter, encoding); - } - [DllImport(NativeObjectWriterFileName)] private static extern void EmitDebugFileInfo(IntPtr objWriter, int fileId, string fileName); public void EmitDebugFileInfo(int fileId, string fileName) @@ -584,49 +574,12 @@ public void PublishUnwindInfo(ObjectNode node) } } - // This represents the following DWARF code: - // DW_CFA_advance_loc: 4 - // DW_CFA_def_cfa_offset: +16 - // DW_CFA_offset: W29 -16 - // DW_CFA_offset: W30 -8 - // DW_CFA_advance_loc: 4 - // DW_CFA_def_cfa_register: W29 - // which is generated for the following frame prolog/epilog: - // stp fp, lr, [sp, #-10]! - // mov fp, sp - // ... - // ldp fp, lr, [sp], #0x10 - // ret - private static ReadOnlySpan DwarfArm64EmptyFrame => new byte[] - { - 0x04, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x02, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x02, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x01, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - private bool TryGetCompactUnwindEncoding(byte[] blob, out uint encoding) - { - if (_targetPlatform.Architecture == TargetArchitecture.ARM64) - { - if (blob.AsSpan().SequenceEqual(DwarfArm64EmptyFrame)) - { - // Frame-based encoding, no saved registers - encoding = 0x04000000; - return true; - } - } - encoding = 0; - return false; - } - public void BuildCFIMap(NodeFactory factory, ObjectNode node) { _offsetToCfis.Clear(); _offsetToCfiStart.Clear(); _offsetToCfiEnd.Clear(); _offsetToCfiLsdaBlobName.Clear(); - _offsetToCfiCompactEncoding.Clear(); _frameOpened = false; INodeWithCodeInfo nodeWithCodeInfo = node as INodeWithCodeInfo; @@ -656,7 +609,6 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) int end = frameInfo.EndOffset; int len = frameInfo.BlobData.Length; byte[] blob = frameInfo.BlobData; - bool emitDwarf = true; ObjectNodeSection lsdaSection = LsdaSection; if (ShouldShareSymbol(node)) @@ -669,13 +621,6 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) byte[] blobSymbolName = _sb.ToUtf8String().UnderlyingArray; EmitSymbolDef(blobSymbolName); - if (_targetPlatform.IsOSXLike && - TryGetCompactUnwindEncoding(blob, out uint compactEncoding)) - { - _offsetToCfiCompactEncoding[start] = compactEncoding; - emitDwarf = false; - } - FrameInfoFlags flags = frameInfo.Flags; flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0; flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0; @@ -717,25 +662,21 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) _byteInterruptionOffsets[start] = true; _byteInterruptionOffsets[end] = true; _offsetToCfiLsdaBlobName.Add(start, blobSymbolName); - - if (emitDwarf) + for (int j = 0; j < len; j += CfiCodeSize) { - for (int j = 0; j < len; j += CfiCodeSize) + // The first byte of CFI_CODE is offset from the range the frame covers. + // Compute code offset from the root method. + int codeOffset = blob[j] + start; + List cfis; + if (!_offsetToCfis.TryGetValue(codeOffset, out cfis)) { - // The first byte of CFI_CODE is offset from the range the frame covers. - // Compute code offset from the root method. - int codeOffset = blob[j] + start; - List cfis; - if (!_offsetToCfis.TryGetValue(codeOffset, out cfis)) - { - cfis = new List(); - _offsetToCfis.Add(codeOffset, cfis); - _byteInterruptionOffsets[codeOffset] = true; - } - byte[] cfi = new byte[CfiCodeSize]; - Array.Copy(blob, j, cfi, 0, CfiCodeSize); - cfis.Add(cfi); + cfis = new List(); + _offsetToCfis.Add(codeOffset, cfis); + _byteInterruptionOffsets[codeOffset] = true; } + byte[] cfi = new byte[CfiCodeSize]; + Array.Copy(blob, j, cfi, 0, CfiCodeSize); + cfis.Add(cfi); } } @@ -785,11 +726,6 @@ public void EmitCFICodes(int offset) // prefix to `_fram`. "_fram"u8.CopyTo(blobSymbolName); EmitSymbolDef(blobSymbolName); - - if (_offsetToCfiCompactEncoding.TryGetValue(offset, out uint compactEncoding)) - { - EmitCFICompactUnwindEncoding(compactEncoding); - } } }