Skip to content

Commit 3a6b120

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. (cherry picked from commit c964d56)
1 parent 65d3ee5 commit 3a6b120

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
@@ -2668,20 +2668,48 @@ static llvm::Expected<addr_t> ReadAsyncContextRegisterFromUnwind(
26682668
return async_reg;
26692669
}
26702670

2671+
static llvm::Expected<bool>
2672+
DoesContinuationPointToSameFunction(addr_t async_reg, SymbolContext &sc,
2673+
Process &process) {
2674+
llvm::Expected<addr_t> continuation_ptr = ReadPtrFromAddr(
2675+
process, async_reg, /*offset*/ process.GetAddressByteSize());
2676+
if (!continuation_ptr)
2677+
return continuation_ptr.takeError();
2678+
2679+
Address continuation_addr;
2680+
continuation_addr.SetLoadAddress(process.FixCodeAddress(*continuation_ptr),
2681+
&process.GetTarget());
2682+
if (sc.function)
2683+
return sc.function->GetAddressRange().ContainsLoadAddress(
2684+
continuation_addr, &process.GetTarget());
2685+
assert(sc.symbol);
2686+
return sc.symbol->ContainsFileAddress(continuation_addr.GetFileAddress());
2687+
}
2688+
26712689
/// Returns true if the async register should be dereferenced once to obtain the
26722690
/// CFA of the currently executing function. This is the case at the start of
26732691
/// "Q" funclets, before the low level code changes the meaning of the async
26742692
/// register to not require the indirection.
2675-
/// The end of the prologue approximates the transition point.
2693+
/// The end of the prologue approximates the transition point well in non-arm64e
2694+
/// targets.
26762695
/// FIXME: In the few instructions between the end of the prologue and the
26772696
/// transition point, this approximation fails. rdar://139676623
26782697
static llvm::Expected<bool> IsIndirectContext(Process &process,
26792698
StringRef mangled_name,
2680-
Address pc, SymbolContext &sc) {
2699+
Address pc, SymbolContext &sc,
2700+
addr_t async_reg) {
26812701
if (!SwiftLanguageRuntime::IsSwiftAsyncAwaitResumePartialFunctionSymbol(
26822702
mangled_name))
26832703
return false;
26842704

2705+
// For arm64e, pointer authentication generates branches that cause stepping
2706+
// algorithms to stop & unwind in more places. The "end of the prologue"
2707+
// approximation fails in those; instead, check whether the continuation
2708+
// pointer still points to the currently executing function. This works for
2709+
// all instructions, but fails when direct recursion is involved.
2710+
if (process.GetTarget().GetArchitecture().GetTriple().isArm64e())
2711+
return DoesContinuationPointToSameFunction(async_reg, sc, process);
2712+
26852713
// This is checked prior to calling this function.
26862714
assert(sc.function || sc.symbol);
26872715
uint32_t prologue_size = sc.function ? sc.function->GetPrologueByteSize()
@@ -2764,7 +2792,7 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
27642792
return log_expected(async_reg.takeError());
27652793

27662794
llvm::Expected<bool> maybe_indirect_context =
2767-
IsIndirectContext(*process_sp, mangled_name, pc, sc);
2795+
IsIndirectContext(*process_sp, mangled_name, pc, sc, *async_reg);
27682796
if (!maybe_indirect_context)
27692797
return log_expected(maybe_indirect_context.takeError());
27702798

0 commit comments

Comments
 (0)