Skip to content

Commit 4fc9acd

Browse files
committed
[lldb] Provide lr value in faulting frame on arm64
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 llvm#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
1 parent e1fed24 commit 4fc9acd

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

lldb/source/Target/RegisterContextUnwind.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,7 @@ RegisterContextUnwind::SavedLocationForRegister(
13771377
}
13781378
}
13791379

1380+
// Check if the active_row has a register location listed.
13801381
if (regnum.IsValid() &&
13811382
active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
13821383
unwindplan_regloc)) {
@@ -1390,11 +1391,10 @@ RegisterContextUnwind::SavedLocationForRegister(
13901391
// This is frame 0 and we're retrieving the PC and it's saved in a Return
13911392
// Address register and it hasn't been saved anywhere yet -- that is,
13921393
// it's still live in the actual register. Handle this specially.
1393-
13941394
if (!have_unwindplan_regloc && return_address_reg.IsValid() &&
1395-
IsFrameZero()) {
1396-
if (return_address_reg.GetAsKind(eRegisterKindLLDB) !=
1397-
LLDB_INVALID_REGNUM) {
1395+
return_address_reg.GetAsKind(eRegisterKindLLDB) !=
1396+
LLDB_INVALID_REGNUM) {
1397+
if (IsFrameZero()) {
13981398
lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc;
13991399
new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::
14001400
eRegisterInLiveRegisterContext;
@@ -1408,6 +1408,17 @@ RegisterContextUnwind::SavedLocationForRegister(
14081408
return_address_reg.GetAsKind(eRegisterKindLLDB),
14091409
return_address_reg.GetAsKind(eRegisterKindLLDB));
14101410
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
1411+
} else if (BehavesLikeZerothFrame()) {
1412+
// This function was interrupted asynchronously -- it faulted,
1413+
// an async interrupt, a timer fired, a debugger expression etc.
1414+
// The caller's pc is in the Return Address register, but the
1415+
// UnwindPlan for this function may have no location rule for
1416+
// the RA reg.
1417+
// This means that the caller's return address is in the RA reg
1418+
// when the function was interrupted--descend down one stack frame
1419+
// to retrieve it from the trap handler's saved context.
1420+
unwindplan_regloc.SetSame();
1421+
have_unwindplan_regloc = true;
14111422
}
14121423
}
14131424

0 commit comments

Comments
 (0)