[Lldb-commits] [lldb] r304976 - Fix backtrace of noreturn functions situated at the end of a module

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 8 06:26:35 PDT 2017


Author: labath
Date: Thu Jun  8 08:26:35 2017
New Revision: 304976

URL: http://llvm.org/viewvc/llvm-project?rev=304976&view=rev
Log:
Fix backtrace of noreturn functions situated at the end of a module

Summary:
When a call instruction is the last instruction in a function, the
backtrace PC will point past the end of the function. We already had
special code to handle that, but we did not handle the case where the PC
ends up outside of the bounds of the module containing the function,
which is a situation that occured in TestNoreturnUnwind on android for
some arch/compiler combinations.

I fix this by adding an argument to Address resolution code which states
that we are ok with addresses pointing to the end of a module/section to
resolve to that module/section.

I create a reproducible test case for this situation by hand-crafting an
executable which has a noreturn function at the end of a module.

Reviewers: jasonmolenda, jingham

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D32022

Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out   (with props)
Modified:
    lldb/trunk/include/lldb/Core/Address.h
    lldb/trunk/include/lldb/Core/Section.h
    lldb/trunk/include/lldb/Target/SectionLoadList.h
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c
    lldb/trunk/source/Core/Address.cpp
    lldb/trunk/source/Core/Section.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Target/SectionLoadList.cpp
    lldb/trunk/source/Target/StackFrame.cpp

Modified: lldb/trunk/include/lldb/Core/Address.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Address.h?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Address.h (original)
+++ lldb/trunk/include/lldb/Core/Address.h Thu Jun  8 08:26:35 2017
@@ -422,6 +422,10 @@ public:
   ///     a section + offset. The Target's SectionLoadList object
   ///     is used to resolve the address.
   ///
+  /// @param[in] allow_section_end
+  ///     If true, treat an address pointing to the end of the module as
+  ///     belonging to that module.
+  ///
   /// @return
   ///     Returns \b true if the load address was resolved to be
   ///     section/offset, \b false otherwise. It is often ok for an
@@ -429,11 +433,13 @@ public:
   ///     happens for JIT'ed code, or any load addresses on the stack
   ///     or heap.
   //------------------------------------------------------------------
-  bool SetLoadAddress(lldb::addr_t load_addr, Target *target);
+  bool SetLoadAddress(lldb::addr_t load_addr, Target *target,
+                      bool allow_section_end = false);
 
   bool SetOpcodeLoadAddress(
       lldb::addr_t load_addr, Target *target,
-      lldb::AddressClass addr_class = lldb::eAddressClassInvalid);
+      lldb::AddressClass addr_class = lldb::eAddressClassInvalid,
+      bool allow_section_end = false);
 
   bool SetCallableLoadAddress(lldb::addr_t load_addr, Target *target);
 

Modified: lldb/trunk/include/lldb/Core/Section.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Section.h?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Section.h (original)
+++ lldb/trunk/include/lldb/Core/Section.h Thu Jun  8 08:26:35 2017
@@ -143,7 +143,8 @@ public:
 
   lldb::addr_t GetLoadBaseAddress(Target *target) const;
 
-  bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr) const;
+  bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr,
+                               bool allow_section_end = false) const;
 
   lldb::offset_t GetFileOffset() const { return m_file_offset; }
 

Modified: lldb/trunk/include/lldb/Target/SectionLoadList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/SectionLoadList.h?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/SectionLoadList.h (original)
+++ lldb/trunk/include/lldb/Target/SectionLoadList.h Thu Jun  8 08:26:35 2017
@@ -47,7 +47,8 @@ public:
 
   lldb::addr_t GetSectionLoadAddress(const lldb::SectionSP &section_sp) const;
 
-  bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr) const;
+  bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr,
+                          bool allow_section_end = false) const;
 
   bool SetSectionLoadAddress(const lldb::SectionSP &section_sp,
                              lldb::addr_t load_addr,

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py Thu Jun  8 08:26:35 2017
@@ -17,8 +17,6 @@ class NoreturnUnwind(TestBase):
     mydir = TestBase.compute_mydir(__file__)
 
     @skipIfWindows  # clang-cl does not support gcc style attributes.
-    @expectedFailureAndroid(bugnumber="llvm.org/pr31192")
-    @expectedFailureAll(bugnumber="llvm.org/pr31192", oslist=['linux'], compiler="gcc", archs=['arm'])
     def test(self):
         """Test that we can backtrace correctly with 'noreturn' functions on the stack"""
         self.build()

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c Thu Jun  8 08:26:35 2017
@@ -29,8 +29,6 @@ func_a (void)
 int
 main (int argc, char *argv[])
 {
-    sleep (2);
-
 	func_a ();
 
 	return 0;

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py?rev=304976&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py Thu Jun  8 08:26:35 2017
@@ -0,0 +1,53 @@
+"""
+Test that we properly display the backtrace when a noreturn function happens to
+be at the end of the stack.
+"""
+
+from __future__ import print_function
+
+import shutil
+import struct
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestNoreturnModuleEnd(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        super(TestNoreturnModuleEnd, self).setUp()
+        self._initial_platform = lldb.DBG.GetSelectedPlatform()
+
+    def tearDown(self):
+        lldb.DBG.SetSelectedPlatform(self._initial_platform)
+        super(TestNoreturnModuleEnd, self).tearDown()
+
+    def test(self):
+        target = self.dbg.CreateTarget("test.out")
+        process = target.LoadCore("test.core")
+        self.assertTrue(process.IsValid(), PROCESS_IS_VALID)
+        self.assertEqual(process.GetNumThreads(), 1)
+
+        thread = process.GetSelectedThread()
+        self.assertTrue(thread.IsValid())
+
+        backtrace = [
+            ["func2", 3],
+            ["func1", 8],
+            ["_start", 8],
+        ]
+        self.assertEqual(thread.GetNumFrames(), len(backtrace))
+        for i in range(len(backtrace)):
+            frame = thread.GetFrameAtIndex(i)
+            self.assertTrue(frame.IsValid())
+            symbol = frame.GetSymbol()
+            self.assertTrue(symbol.IsValid())
+            self.assertEqual(symbol.GetName(), backtrace[i][0])
+            function_start = symbol.GetStartAddress().GetLoadAddress(target)
+            self.assertEquals(function_start + backtrace[i][1], frame.GetPC())
+
+        self.dbg.DeleteTarget(target)

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s?rev=304976&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s Thu Jun  8 08:26:35 2017
@@ -0,0 +1,35 @@
+# compile this with:
+# as a.s -o a.o --32 && ld a.o -m elf_i386
+# generate core file with:
+# ulimit -s 12 && ./a.out
+
+.text
+
+.globl func2
+.type func2, @function
+func2:
+  pushl %ebp
+  movl  %esp, %ebp
+  movl  0,    %eax
+  popl  %ebp
+  ret
+.size func2, .-func2
+
+.globl _start
+.type _start, @function
+_start:
+  pushl %ebp
+  movl  %esp, %ebp
+  call  func1
+  popl  %ebp
+  ret
+.size _start, .-_start
+
+.globl func1
+.type func1, @function
+func1:
+  pushl %ebp
+  movl  %esp, %ebp
+  call  func2
+.size func1, .-func1
+

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core?rev=304976&view=auto
==============================================================================
Binary files lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core (added) and lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core Thu Jun  8 08:26:35 2017 differ

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out?rev=304976&view=auto
==============================================================================
Binary files lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out (added) and lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out Thu Jun  8 08:26:35 2017 differ

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out
------------------------------------------------------------------------------
    svn:executable = *

Modified: lldb/trunk/source/Core/Address.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Address.cpp?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/source/Core/Address.cpp (original)
+++ lldb/trunk/source/Core/Address.cpp Thu Jun  8 08:26:35 2017
@@ -361,8 +361,9 @@ addr_t Address::GetOpcodeLoadAddress(Tar
 }
 
 bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target,
-                                   AddressClass addr_class) {
-  if (SetLoadAddress(load_addr, target)) {
+                                   AddressClass addr_class,
+                                   bool allow_section_end) {
+  if (SetLoadAddress(load_addr, target, allow_section_end)) {
     if (target) {
       if (addr_class == eAddressClassInvalid)
         addr_class = GetAddressClass();
@@ -1001,9 +1002,10 @@ AddressClass Address::GetAddressClass()
   return eAddressClassUnknown;
 }
 
-bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target) {
-  if (target &&
-      target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this))
+bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target,
+                             bool allow_section_end) {
+  if (target && target->GetSectionLoadList().ResolveLoadAddress(
+                    load_addr, *this, allow_section_end))
     return true;
   m_section_wp.reset();
   m_offset = load_addr;

Modified: lldb/trunk/source/Core/Section.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Section.cpp?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/source/Core/Section.cpp (original)
+++ lldb/trunk/source/Core/Section.cpp Thu Jun  8 08:26:35 2017
@@ -220,18 +220,18 @@ addr_t Section::GetLoadBaseAddress(Targe
   return load_base_addr;
 }
 
-bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr) const {
+bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,
+                                      bool allow_section_end) const {
   const size_t num_children = m_children.GetSize();
-  if (num_children > 0) {
-    for (size_t i = 0; i < num_children; i++) {
-      Section *child_section = m_children.GetSectionAtIndex(i).get();
+  for (size_t i = 0; i < num_children; i++) {
+    Section *child_section = m_children.GetSectionAtIndex(i).get();
 
-      addr_t child_offset = child_section->GetOffset();
-      if (child_offset <= offset &&
-          offset - child_offset < child_section->GetByteSize())
-        return child_section->ResolveContainedAddress(offset - child_offset,
-                                                      so_addr);
-    }
+    addr_t child_offset = child_section->GetOffset();
+    if (child_offset <= offset &&
+        offset - child_offset <
+            child_section->GetByteSize() + (allow_section_end ? 1 : 0))
+      return child_section->ResolveContainedAddress(offset - child_offset,
+                                                    so_addr, allow_section_end);
   }
   so_addr.SetOffset(offset);
   so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());

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=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Thu Jun  8 08:26:35 2017
@@ -329,7 +329,8 @@ void RegisterContextLLDB::InitializeNonZ
   if (abi)
     pc = abi->FixCodeAddress(pc);
 
-  m_current_pc.SetLoadAddress(pc, &process->GetTarget());
+  const bool allow_section_end = true;
+  m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end);
 
   // If we don't have a Module for some reason, we're not going to find
   // symbol/function information - just
@@ -477,11 +478,12 @@ void RegisterContextLLDB::InitializeNonZ
   // Or if we're in the middle of the stack (and not "above" an asynchronous
   // event like sigtramp),
   // and our "current" pc is the start of a function...
-  if (m_sym_ctx_valid && GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
+  if (GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
       GetNextFrame()->m_frame_type != eDebuggerFrame &&
-      addr_range.GetBaseAddress().IsValid() &&
-      addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
-      addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) {
+      (!m_sym_ctx_valid ||
+       (addr_range.GetBaseAddress().IsValid() &&
+        addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
+        addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()))) {
     decr_pc_and_recompute_addr_range = true;
   }
 

Modified: lldb/trunk/source/Target/SectionLoadList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/SectionLoadList.cpp?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/source/Target/SectionLoadList.cpp (original)
+++ lldb/trunk/source/Target/SectionLoadList.cpp Thu Jun  8 08:26:35 2017
@@ -207,8 +207,8 @@ bool SectionLoadList::SetSectionUnloaded
   return erased;
 }
 
-bool SectionLoadList::ResolveLoadAddress(addr_t load_addr,
-                                         Address &so_addr) const {
+bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, Address &so_addr,
+                                         bool allow_section_end) const {
   // First find the top level section that this load address exists in
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   if (!m_addr_to_sect.empty()) {
@@ -220,10 +220,11 @@ bool SectionLoadList::ResolveLoadAddress
       const addr_t pos_load_addr = pos->first;
       if (load_addr >= pos_load_addr) {
         addr_t offset = load_addr - pos_load_addr;
-        if (offset < pos->second->GetByteSize()) {
+        if (offset < pos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
           // We have found the top level section, now we need to find the
           // deepest child section.
-          return pos->second->ResolveContainedAddress(offset, so_addr);
+          return pos->second->ResolveContainedAddress(offset, so_addr,
+                                                      allow_section_end);
         }
       }
     } else {
@@ -233,10 +234,12 @@ bool SectionLoadList::ResolveLoadAddress
           m_addr_to_sect.rbegin();
       if (load_addr >= rpos->first) {
         addr_t offset = load_addr - rpos->first;
-        if (offset < rpos->second->GetByteSize()) {
+        if (offset <
+            rpos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
           // We have found the top level section, now we need to find the
           // deepest child section.
-          return rpos->second->ResolveContainedAddress(offset, so_addr);
+          return rpos->second->ResolveContainedAddress(offset, so_addr,
+                                                       allow_section_end);
         }
       }
     }

Modified: lldb/trunk/source/Target/StackFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=304976&r1=304975&r2=304976&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrame.cpp (original)
+++ lldb/trunk/source/Target/StackFrame.cpp Thu Jun  8 08:26:35 2017
@@ -191,9 +191,10 @@ const Address &StackFrame::GetFrameCodeA
     if (thread_sp) {
       TargetSP target_sp(thread_sp->CalculateTarget());
       if (target_sp) {
+        const bool allow_section_end = true;
         if (m_frame_code_addr.SetOpcodeLoadAddress(
                 m_frame_code_addr.GetOffset(), target_sp.get(),
-                eAddressClassCode)) {
+                eAddressClassCode, allow_section_end)) {
           ModuleSP module_sp(m_frame_code_addr.GetModule());
           if (module_sp) {
             m_sc.module_sp = module_sp;




More information about the lldb-commits mailing list