JosephTremoulet created this revision.
JosephTremoulet added reviewers: labath, jankratochvil, compnerd.
Herald added subscribers: kristof.beyls, javed.absar.
Herald added a reviewer: jfb.
Herald added a project: LLDB.

Add __kernel_rt_sigreturn to the list of trap handlers for Linux (it's
used as such on aarch64 at least).

Skip decrement-and-recompute for trap handlers in
InitializeNonZerothFrame, as signal dispatch may point the child frame's
return address to the start of the return trampoline.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D63667

Files:
  
lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/Makefile
  
lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/TestHandleAbort.py
  lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/main.c
  lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
  lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp

Index: lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -472,20 +472,30 @@
     m_sym_ctx_valid = false;
   }
 
-  bool decr_pc_and_recompute_addr_range = false;
+  bool decr_pc_and_recompute_addr_range;
 
-  // If the symbol lookup failed...
-  if (!m_sym_ctx_valid)
+  if (!m_sym_ctx_valid) {
+    // Always decrement and recompute if the symbol lookup failed
     decr_pc_and_recompute_addr_range = true;
-
-  // 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 (GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
-      GetNextFrame()->m_frame_type != eDebuggerFrame &&
-      (!m_sym_ctx_valid ||
-       (addr_range.GetBaseAddress().IsValid() &&
-        addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
-        addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()))) {
+  } else if (GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
+             GetNextFrame()->m_frame_type == eDebuggerFrame) {
+    // Don't decrement if we're "above" an asynchronous event like
+    // sigtramp.
+    decr_pc_and_recompute_addr_range = false;
+  } else if (!addr_range.GetBaseAddress().IsValid() ||
+             addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() ||
+             addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) {
+    // If our "current" pc isn't the start of a function, no need
+    // to decrement and recompute.
+    decr_pc_and_recompute_addr_range = false;
+  } else if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+    // Signal dispatch may set the return address of the handler it calls to
+    // point to the first byte of a return trampoline (like __kernel_rt_sigreturn),
+    // so do not decrement and recompute if the symbol we already found is a trap
+    // handler.
+    decr_pc_and_recompute_addr_range = false;
+  } else {
+    // Decrement to find the function containing the call.
     decr_pc_and_recompute_addr_range = true;
   }
 
Index: lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
===================================================================
--- lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
+++ lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
@@ -396,6 +396,7 @@
 
 void PlatformLinux::CalculateTrapHandlerSymbolNames() {
   m_trap_handlers.push_back(ConstString("_sigtramp"));
+  m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));
 }
 
 MmapArgList PlatformLinux::GetMmapArgumentList(const ArchSpec &arch,
Index: lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/main.c
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/main.c
@@ -0,0 +1,25 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void handler(int sig)
+{
+    printf("Set a breakpoint here.\n");
+    exit(0);
+}
+
+void abort_caller() {
+    abort();
+}
+
+int main()
+{
+    if (signal(SIGABRT, handler) == SIG_ERR)
+    {
+        perror("signal");
+        return 1;
+    }
+
+    abort_caller();
+    return 2;
+}
Index: lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/TestHandleAbort.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/TestHandleAbort.py
@@ -0,0 +1,72 @@
+"""Test that we can unwind out of a SIGABRT handler"""
+
+from __future__ import print_function
+
+
+import os
+import re
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class HandleAbortTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIfWindows  # signals do not exist on Windows
+    def test_inferior_handle_sigabrt(self):
+        """Inferierior calls abort() and handles the resultant sigabrt().
+           Stopped at a breakpoint in the handler, verify that the backtrace
+           includes the function that called abort()."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        # Create a target by the debugger.
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # launch
+        process = target.LaunchSimple(
+            None, None, self.get_process_working_directory())
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+        signo = process.GetUnixSignals().GetSignalNumberFromName("SIGABRT")
+
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
+        self.assertTrue(
+            thread and thread.IsValid(),
+            "Thread should be stopped due to a signal")
+        self.assertTrue(
+            thread.GetStopReasonDataCount() >= 1,
+            "There should be data in the event.")
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0),
+                         signo, "The stop signal should be SIGABRT")
+
+        # Continue to breakpoint in abort handler
+        bkpt = target.FindBreakpointByID(
+            lldbutil.run_break_set_by_source_regexp(self, "Set a breakpoint here"))
+        threads = lldbutil.continue_to_breakpoint(process, bkpt)
+        self.assertEqual(len(threads), 1, "Expected single thread")
+        thread = threads[0]
+
+        # Expect breakpoint in 'handler'
+        frame = thread.GetFrameAtIndex(0)
+        self.assertEqual(frame.GetDisplayFunctionName(), "handler", "Unexpected break?")
+
+        # Expect that unwinding should find 'abort_caller'
+        foundFoo = False
+        for frame in thread:
+            if frame.GetDisplayFunctionName() == "abort_caller":
+                foundFoo = True
+
+        self.assertTrue(foundFoo, "Unwinding did not find func that called abort")
+
+        # Continue until we exit.
+        process.Continue()
+        self.assertEqual(process.GetState(), lldb.eStateExited)
+        self.assertEqual(process.GetExitStatus(), 0)
Index: lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to