Skip to content

Commit c964d56

Browse files
[lldb][swift] Change unwind heuristic for Q funclets in arm64e
With arm64e, many more branches are generated, which cause the debugger to stop more often while stepping. Among those stops are code regions where the debugger gets confused about what is stored in the async register stack slot. This commit revives a heuristic that was previously used by default for all architectures and that works in all PC addresses, but that sacrifices unwinding o recursive functions. It is only used if the target is arm64e.
1 parent d03a4ce commit c964d56

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,20 +2663,48 @@ static llvm::Expected<addr_t> ReadAsyncContextRegisterFromUnwind(
26632663
return async_reg;
26642664
}
26652665

2666+
static llvm::Expected<bool>
2667+
DoesContinuationPointToSameFunction(addr_t async_reg, SymbolContext &sc,
2668+
Process &process) {
2669+
llvm::Expected<addr_t> continuation_ptr = ReadPtrFromAddr(
2670+
process, async_reg, /*offset*/ process.GetAddressByteSize());
2671+
if (!continuation_ptr)
2672+
return continuation_ptr.takeError();
2673+
2674+
Address continuation_addr;
2675+
continuation_addr.SetLoadAddress(process.FixCodeAddress(*continuation_ptr),
2676+
&process.GetTarget());
2677+
if (sc.function)
2678+
return sc.function->GetAddressRange().ContainsLoadAddress(
2679+
continuation_addr, &process.GetTarget());
2680+
assert(sc.symbol);
2681+
return sc.symbol->ContainsFileAddress(continuation_addr.GetFileAddress());
2682+
}
2683+
26662684
/// Returns true if the async register should be dereferenced once to obtain the
26672685
/// CFA of the currently executing function. This is the case at the start of
26682686
/// "Q" funclets, before the low level code changes the meaning of the async
26692687
/// register to not require the indirection.
2670-
/// The end of the prologue approximates the transition point.
2688+
/// The end of the prologue approximates the transition point well in non-arm64e
2689+
/// targets.
26712690
/// FIXME: In the few instructions between the end of the prologue and the
26722691
/// transition point, this approximation fails. rdar://139676623
26732692
static llvm::Expected<bool> IsIndirectContext(Process &process,
26742693
StringRef mangled_name,
2675-
Address pc, SymbolContext &sc) {
2694+
Address pc, SymbolContext &sc,
2695+
addr_t async_reg) {
26762696
if (!SwiftLanguageRuntime::IsSwiftAsyncAwaitResumePartialFunctionSymbol(
26772697
mangled_name))
26782698
return false;
26792699

2700+
// For arm64e, pointer authentication generates branches that cause stepping
2701+
// algorithms to stop & unwind in more places. The "end of the prologue"
2702+
// approximation fails in those; instead, check whether the continuation
2703+
// pointer still points to the currently executing function. This works for
2704+
// all instructions, but fails when direct recursion is involved.
2705+
if (process.GetTarget().GetArchitecture().GetTriple().isArm64e())
2706+
return DoesContinuationPointToSameFunction(async_reg, sc, process);
2707+
26802708
// This is checked prior to calling this function.
26812709
assert(sc.function || sc.symbol);
26822710
uint32_t prologue_size = sc.function ? sc.function->GetPrologueByteSize()
@@ -2759,7 +2787,7 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
27592787
return log_expected(async_reg.takeError());
27602788

27612789
llvm::Expected<bool> maybe_indirect_context =
2762-
IsIndirectContext(*process_sp, mangled_name, pc, sc);
2790+
IsIndirectContext(*process_sp, mangled_name, pc, sc, *async_reg);
27632791
if (!maybe_indirect_context)
27642792
return log_expected(maybe_indirect_context.takeError());
27652793

0 commit comments

Comments
 (0)