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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to