[Lldb-commits] [lldb] [lldb] Provide lr value in faulting frame on arm64 (PR #138805)
via lldb-commits
lldb-commits at lists.llvm.org
Tue May 6 22:50:37 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Jason Molenda (jasonmolenda)
<details>
<summary>Changes</summary>
When a frameless function faults or is interrupted asynchronously, the UnwindPlan MAY have no register location rule for the return address register (lr on arm64); the value is simply live in the lr register when it was interrupted, and the frame below this on the stack -- e.g. sigtramp on a Unix system -- has the full register context, including that register.
RegisterContextUnwind::SavedLocationForRegister, when asked to find the caller's pc value, will first see if there is a pc register location. If there isn't, on a Return Address Register architecture like arm/mips/riscv, we rewrite the register request from "pc" to "RA register", and search for a location.
On frame 0 (the live frame) and an interrupted frame, the UnwindPlan may have no register location rule for the RA Reg, that is valid. A frameless function that never calls another may simply keep the return address in the live register the whole way. Our instruction emulation unwind plans explicitly add a rule (see Pavel's May 2024 change https://github.com/llvm/llvm-project/pull/91321 ), but an UnwindPlan sourced from debug_frame may not.
I've got a case where this exactly happens - clang debug_frame for arm64 where there is no register location for the lr in a frameless function. There is a fault in the middle of this frameless function and we only get the lr value from the fault handler below this frame if lr has a register location of `IsSame`, in line with Pavel's 2024 change.
Similar to how we see a request of the RA Reg from frame 0 after failing to find an unwind location for the pc register, the same style of special casing is needed when this is a function that was interrupted.
Without this change, we can find the pc of the frame that was executing when it was interrupted, but we need $lr to find its caller, and we don't descend down to the trap handler to get that value, truncating the stack.
rdar://145614545
---
Full diff: https://github.com/llvm/llvm-project/pull/138805.diff
1 Files Affected:
- (modified) lldb/source/Target/RegisterContextUnwind.cpp (+15-4)
``````````diff
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 3ed49e12476dd..23a86bee2518b 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1377,6 +1377,7 @@ RegisterContextUnwind::SavedLocationForRegister(
}
}
+ // Check if the active_row has a register location listed.
if (regnum.IsValid() &&
active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
unwindplan_regloc)) {
@@ -1390,11 +1391,10 @@ RegisterContextUnwind::SavedLocationForRegister(
// This is frame 0 and we're retrieving the PC and it's saved in a Return
// Address register and it hasn't been saved anywhere yet -- that is,
// it's still live in the actual register. Handle this specially.
-
if (!have_unwindplan_regloc && return_address_reg.IsValid() &&
- IsFrameZero()) {
- if (return_address_reg.GetAsKind(eRegisterKindLLDB) !=
- LLDB_INVALID_REGNUM) {
+ return_address_reg.GetAsKind(eRegisterKindLLDB) !=
+ LLDB_INVALID_REGNUM) {
+ if (IsFrameZero()) {
lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc;
new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::
eRegisterInLiveRegisterContext;
@@ -1408,6 +1408,17 @@ RegisterContextUnwind::SavedLocationForRegister(
return_address_reg.GetAsKind(eRegisterKindLLDB),
return_address_reg.GetAsKind(eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ } else if (BehavesLikeZerothFrame()) {
+ // This function was interrupted asynchronously -- it faulted,
+ // an async interrupt, a timer fired, a debugger expression etc.
+ // The caller's pc is in the Return Address register, but the
+ // UnwindPlan for this function may have no location rule for
+ // the RA reg.
+ // This means that the caller's return address is in the RA reg
+ // when the function was interrupted--descend down one stack frame
+ // to retrieve it from the trap handler's saved context.
+ unwindplan_regloc.SetSame();
+ have_unwindplan_regloc = true;
}
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/138805
More information about the lldb-commits
mailing list