[Lldb-commits] [lldb] r221575 - Fix a corner case with the handling of noreturn functions.

Jason Molenda jmolenda at apple.com
Fri Nov 7 21:38:18 PST 2014


Author: jmolenda
Date: Fri Nov  7 23:38:17 2014
New Revision: 221575

URL: http://llvm.org/viewvc/llvm-project?rev=221575&view=rev
Log:
Fix a corner case with the handling of noreturn functions.
If a noreturn function was the last function in a section,
we wouldn't correctly back up the saved-pc value into the
correct section leading to us showing the wrong function in
the backtrace.

Also add a backtrace test with an attempt to elicit this 
particular layout.  It happens to work out with clang -Os
but other compilers may not quite get the same layout I'm
getting at that opt setting.  We'll still be exercising the
basic noreturn handling in the unwinder even if we don't get
one function at the very end of a section.

<rdar://problem/16051613> 

Added:
    lldb/trunk/test/functionalities/unwind/
    lldb/trunk/test/functionalities/unwind/noreturn/
    lldb/trunk/test/functionalities/unwind/noreturn/Makefile
    lldb/trunk/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
    lldb/trunk/test/functionalities/unwind/noreturn/main.c
Modified:
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Target/StackFrame.cpp

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=221575&r1=221574&r2=221575&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Fri Nov  7 23:38:17 2014
@@ -172,6 +172,21 @@ RegisterContextLLDB::InitializeZerothFra
         m_sym_ctx_valid = true;
     }
 
+    if (m_sym_ctx.symbol)
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+                      current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+    }
+    else if (m_sym_ctx.function)
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
+                      current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString());
+    }
+    else
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", current_pc);
+    }
+
     AddressRange addr_range;
     m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
 
@@ -294,12 +309,12 @@ RegisterContextLLDB::InitializeNonZeroth
 
     if (log)
     {
-        UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+        UnwindLogMsg ("pc = 0x%" PRIx64, pc);
         addr_t reg_val;
         if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
-            UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+            UnwindLogMsg ("fp = 0x%" PRIx64, reg_val);
         if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
-            UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+            UnwindLogMsg ("sp = 0x%" PRIx64, reg_val);
     }
 
     // A pc of 0x0 means it's the end of the stack crawl
@@ -442,6 +457,21 @@ RegisterContextLLDB::InitializeNonZeroth
         m_sym_ctx_valid = true;
     }
 
+    if (m_sym_ctx.symbol)
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+                      pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+    }
+    else if (m_sym_ctx.function)
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
+                      pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString());
+    }
+    else
+    {
+        UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", pc);
+    }
+
     AddressRange addr_range;
     if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
     {
@@ -472,17 +502,21 @@ RegisterContextLLDB::InitializeNonZeroth
     // to the ABI plugin and consult that.
     if (decr_pc_and_recompute_addr_range)
     {
-        Address temporary_pc(m_current_pc);
-        temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
-        m_sym_ctx.Clear(false);
+        UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s",
+                      pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+        Address temporary_pc;
+        temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+        m_sym_ctx.Clear (false);
         m_sym_ctx_valid = false;
         uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
         
-        if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
+        ModuleSP temporary_module_sp = temporary_pc.GetModule();
+        if (temporary_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
         {
             if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false,  addr_range))
                 m_sym_ctx_valid = true;
         }
+        UnwindLogMsg ("Symbol is now %s", m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
     }
 
     // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
@@ -490,13 +524,15 @@ RegisterContextLLDB::InitializeNonZeroth
     if (addr_range.GetBaseAddress().IsValid())
     {
         m_start_pc = addr_range.GetBaseAddress();
-        m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+        m_current_offset = pc - m_start_pc.GetLoadAddress (&process->GetTarget());
         m_current_offset_backed_up_one = m_current_offset;
         if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
         {
             m_current_offset_backed_up_one--;
             if (m_sym_ctx_valid)
-                m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
+            {
+                m_current_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+            }
         }
     }
     else

Modified: lldb/trunk/source/Target/StackFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=221575&r1=221574&r2=221575&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrame.cpp (original)
+++ lldb/trunk/source/Target/StackFrame.cpp Fri Nov  7 23:38:17 2014
@@ -384,7 +384,31 @@ StackFrame::GetSymbolContext (uint32_t r
         {
             addr_t offset = lookup_addr.GetOffset();
             if (offset > 0)
+            {
                 lookup_addr.SetOffset(offset - 1);
+
+            }
+            else
+            {
+                // lookup_addr is the start of a section.  We need
+                // do the math on the actual load address and re-compute
+                // the section.  We're working with a 'noreturn' function
+                // at the end of a section.
+                ThreadSP thread_sp (GetThread());
+                if (thread_sp)
+                {
+                    TargetSP target_sp (thread_sp->CalculateTarget());
+                    if (target_sp)
+                    {
+                        addr_t addr_minus_one = lookup_addr.GetLoadAddress(target_sp.get()) - 1;
+                        lookup_addr.SetLoadAddress (addr_minus_one, target_sp.get());
+                    }
+                    else
+                    {
+                    lookup_addr.SetOffset(offset - 1);
+                    }
+                }
+            }
         }
 
 

Added: lldb/trunk/test/functionalities/unwind/noreturn/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/unwind/noreturn/Makefile?rev=221575&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/unwind/noreturn/Makefile (added)
+++ lldb/trunk/test/functionalities/unwind/noreturn/Makefile Fri Nov  7 23:38:17 2014
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+CFLAGS ?= -g -Os
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py?rev=221575&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py (added)
+++ lldb/trunk/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py Fri Nov  7 23:38:17 2014
@@ -0,0 +1,87 @@
+"""
+Test that we can backtrace correctly with 'noreturn' functions on the stack
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class NoreturnUnwind(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @dsym_test
+    def test_with_dsym (self):
+        """Test that we can backtrace correctly with 'noreturn' functions on the stack"""
+        self.buildDsym()
+        self.setTearDownCleanup()
+        self.noreturn_unwind_tests()
+
+    @dwarf_test
+    def test_with_dsym (self):
+        """Test that we can backtrace correctly with 'noreturn' functions on the stack"""
+        self.buildDsym()
+        self.setTearDownCleanup()
+        self.noreturn_unwind_tests()
+
+    def noreturn_unwind_tests (self):
+        exe = os.path.join(os.getcwd(), "a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        process = target.LaunchSimple (None, None, self.get_process_working_directory())
+
+        if not process:
+            self.fail("SBTarget.Launch() failed")
+
+        if process.GetState() != lldb.eStateStopped:
+            self.fail("Process should be in the 'stopped' state, "
+                      "instead the actual state is: '%s'" %
+                      lldbutil.state_type_to_str(process.GetState()))
+
+        thread = process.GetThreadAtIndex(0)
+        abort_frame_number = 0
+        for f in thread.frames:
+            if f.GetFunctionName() == "abort":
+                break
+            abort_frame_number = abort_frame_number + 1
+
+        if self.TraceOn():
+            print "Backtrace once we're stopped:"
+            for f in thread.frames:
+                print "  %d %s" % (f.GetFrameID(), f.GetFunctionName())
+
+        # I'm going to assume that abort() ends up calling/invoking another
+        # function before halting the process.  In which case if abort_frame_number
+        # equals 0, we didn't find abort() in the backtrace.
+        if abort_frame_number == 0:
+            self.fail("Unable to find abort() in backtrace.")
+
+        func_c_frame_number = abort_frame_number + 1
+        if thread.GetFrameAtIndex (func_c_frame_number).GetFunctionName() != "func_c":
+            self.fail("Did not find func_c() above abort().")
+
+        # This depends on whether we see the func_b inlined function in the backtrace
+        # or not.  I'm not interested in testing that aspect of the backtrace here
+        # right now.
+
+        if thread.GetFrameAtIndex (func_c_frame_number + 1).GetFunctionName() == "func_b":
+            func_a_frame_number = func_c_frame_number + 2
+        else:
+            func_a_frame_number = func_c_frame_number + 1
+
+        if thread.GetFrameAtIndex (func_a_frame_number).GetFunctionName() != "func_a":
+            self.fail("Did not find func_a() above func_c().")
+
+        main_frame_number = func_a_frame_number + 1
+
+        if thread.GetFrameAtIndex (main_frame_number).GetFunctionName() != "main":
+            self.fail("Did not find main() above func_a().")
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/unwind/noreturn/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/unwind/noreturn/main.c?rev=221575&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/unwind/noreturn/main.c (added)
+++ lldb/trunk/test/functionalities/unwind/noreturn/main.c Fri Nov  7 23:38:17 2014
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void func_a (void) __attribute__((noinline));
+static void func_b (void) __attribute__((noreturn));
+static void func_c (void) __attribute__((noinline));
+
+static void
+func_c (void)
+{
+	abort ();
+}
+
+static void
+func_b (void)
+{
+	func_c ();
+	while (1)
+        ;
+}
+
+static void
+func_a (void)
+{
+	func_b ();
+}
+
+int
+main (int argc, char *argv[])
+{
+    sleep (2);
+
+	func_a ();
+
+	return 0;
+}





More information about the lldb-commits mailing list