Skip to content

Commit

Permalink
Revert "[NativeAOT] macOS/iOS: Emit simple compact unwinding informat…
Browse files Browse the repository at this point in the history
…ion (#88724)"

This reverts commit 5bf45ce.
  • Loading branch information
jkotas authored Aug 4, 2023
1 parent d19a146 commit 549af5b
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 182 deletions.
115 changes: 11 additions & 104 deletions src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ public class ObjectWriter : IDisposable, ITypesDebugInfoWriter
private HashSet<int> _offsetToCfiStart = new HashSet<int>();
// Code offsets that ends a frame
private HashSet<int> _offsetToCfiEnd = new HashSet<int>();
// Code offsets to compact unwind encoding
private Dictionary<int, uint> _offsetToCfiCompactEncoding = new Dictionary<int, uint>();
// Used to assert whether frames are not overlapped.
private bool _frameOpened;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<byte> 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;
Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand Down Expand Up @@ -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<byte[]> 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<byte[]> cfis;
if (!_offsetToCfis.TryGetValue(codeOffset, out cfis))
{
cfis = new List<byte[]>();
_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<byte[]>();
_offsetToCfis.Add(codeOffset, cfis);
_byteInterruptionOffsets[codeOffset] = true;
}
byte[] cfi = new byte[CfiCodeSize];
Array.Copy(blob, j, cfi, 0, CfiCodeSize);
cfis.Add(cfi);
}
}

Expand Down Expand Up @@ -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);
}
}
}

Expand Down

0 comments on commit 549af5b

Please sign in to comment.