[Lldb-commits] [lldb] r200600 - Fix for failure to unwind Linux stack frames with call in final position.

Todd Fiala tfiala at google.com
Fri Jan 31 16:48:35 PST 2014


Author: tfiala
Date: Fri Jan 31 18:48:34 2014
New Revision: 200600

URL: http://llvm.org/viewvc/llvm-project?rev=200600&view=rev
Log:
Fix for failure to unwind Linux stack frames with call in final position.

Fixes http://llvm.org/bugs/show_bug.cgi?id=18656.

Note this exposes a failure on Linux of
TestInferiorAssert.test_inferior_asserting_disassemble, similar to how
it fails on FreeBSD. I'll file a bug for this next. We're now getting
another frame beyond where we used to prior to this fix, so the fix is
exposing failures in previosly not-reachable frames.

Much thanks to Jason Molenda, who had much to do with helping figure
out where unwinding was breaking.


Modified:
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
    lldb/trunk/test/functionalities/inferior-assert/TestInferiorAssert.py

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp?rev=200600&r1=200599&r2=200600&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Fri Jan 31 18:48:34 2014
@@ -83,6 +83,37 @@ RegisterContextLLDB::RegisterContextLLDB
     }
 }
 
+bool
+RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset)
+{
+    if (!unwind_plan_sp)
+        return false;
+
+    // check if m_current_pc is valid
+    if (unwind_plan_sp->PlanValidAtAddress(m_current_pc))
+    {
+        // yes - current offset can be used as is
+        valid_pc_offset = m_current_offset;
+        return true;
+    }
+
+    // if m_current_offset <= 0, we've got nothing else to try
+    if (m_current_offset <= 0)
+        return false;
+
+    // check pc - 1 to see if it's valid
+    Address pc_minus_one (m_current_pc);
+    pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1);
+    if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one))
+    {
+        // *valid_pc_offset = m_current_offset - 1;
+        valid_pc_offset = m_current_pc.GetOffset() - 1;
+        return true;
+    }
+
+    return false;
+}
+
 // Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
 // executing frame.
 
@@ -500,9 +531,10 @@ RegisterContextLLDB::InitializeNonZeroth
     else
     {
         m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
-        if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+        int valid_offset = -1;
+        if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset))
         {
-            active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+            active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset);
             row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
             if (active_row.get() && log)
             {
@@ -769,7 +801,8 @@ RegisterContextLLDB::GetFullUnwindPlanFo
 
     // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
     unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
-    if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+    int valid_offset = -1;
+    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
     {
         UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
         return unwind_plan_sp;
@@ -778,7 +811,7 @@ RegisterContextLLDB::GetFullUnwindPlanFo
     // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
     // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
     unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
-    if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
     {
         UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
         return unwind_plan_sp;

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h?rev=200600&r1=200599&r2=200600&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h Fri Jan 31 18:48:34 2014
@@ -167,6 +167,10 @@ private:
     void
     UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
 
+    bool
+    IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset);
+
+
     lldb_private::Thread& m_thread;
 
     ///

Modified: lldb/trunk/test/functionalities/inferior-assert/TestInferiorAssert.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/inferior-assert/TestInferiorAssert.py?rev=200600&r1=200599&r2=200600&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/inferior-assert/TestInferiorAssert.py (original)
+++ lldb/trunk/test/functionalities/inferior-assert/TestInferiorAssert.py Fri Jan 31 18:48:34 2014
@@ -36,6 +36,7 @@ class AssertingInferiorTestCase(TestBase
 
     @expectedFailurei386 # llvm.org/pr17384: lldb needs to be aware of linux-vdso.so to unwind stacks properly
     @expectedFailureFreeBSD('llvm.org/pr18533') # PC in __assert frame is outside of function
+    @expectedFailureLinux('') # PC in __GI___assert_fail frame is just after the function (this is a no-return so there is no epilogue afterwards)
     def test_inferior_asserting_disassemble(self):
         """Test that lldb reliably disassembles frames after asserting (command)."""
         self.buildDefault()





More information about the lldb-commits mailing list