[Lldb-commits] [lldb] r238549 - Report inferior SIGSEGV as a signal instead of an exception on linux

Pavel Labath labath at google.com
Fri May 29 03:13:03 PDT 2015


Author: labath
Date: Fri May 29 05:13:03 2015
New Revision: 238549

URL: http://llvm.org/viewvc/llvm-project?rev=238549&view=rev
Log:
Report inferior SIGSEGV as a signal instead of an exception on linux

Summary:
Previously, we reported inferior receiving SIGSEGV (or SIGILL, SIGFPE, SIGBUS) as an "exception"
to LLDB, presumably to match OSX behaviour. Beside the fact that we were basically lying to the
user, this was also causing problems with inferiors which handle SIGSEGV by themselves, since
LLDB was unable to reinject this signal back into the inferior.

This commit changes LLGS to report SIGSEGV as a signal. This has necessitated some changes in the
test-suite, which had previously used eStopReasonException to locate threads that crashed. Now it
uses platform-specific logic, which in the case of linux searches for eStopReasonSignaled with
signal=SIGSEGV.

I have also added the ability to set the description of StopInfoUnixSignal using the description
field of the gdb-remote packet. The linux stub uses this to display additional information about
the segfault (invalid address, address access protected, etc.).

Test Plan: All tests pass on linux and osx.

Reviewers: ovyalov, clayborg, emaste

Subscribers: emaste, lldb-commits

Differential Revision: http://reviews.llvm.org/D10057

Added:
    lldb/trunk/test/functionalities/signal/handle-segv/
    lldb/trunk/test/functionalities/signal/handle-segv/Makefile
    lldb/trunk/test/functionalities/signal/handle-segv/TestHandleSegv.py
    lldb/trunk/test/functionalities/signal/handle-segv/main.c
Modified:
    lldb/trunk/include/lldb/Target/StopInfo.h
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
    lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Target/StopInfo.cpp
    lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py
    lldb/trunk/test/functionalities/inferior-crashing/TestInferiorCrashing.py
    lldb/trunk/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py
    lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
    lldb/trunk/test/lldbutil.py

Modified: lldb/trunk/include/lldb/Target/StopInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StopInfo.h?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StopInfo.h (original)
+++ lldb/trunk/include/lldb/Target/StopInfo.h Fri May 29 05:13:03 2015
@@ -164,7 +164,7 @@ public:
     CreateStopReasonWithWatchpointID (Thread &thread, lldb::break_id_t watch_id);
 
     static lldb::StopInfoSP
-    CreateStopReasonWithSignal (Thread &thread, int signo);
+    CreateStopReasonWithSignal (Thread &thread, int signo, const char *description = nullptr);
 
     static lldb::StopInfoSP
     CreateStopReasonToTrace (Thread &thread);

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Fri May 29 05:13:03 2015
@@ -2177,7 +2177,7 @@ NativeProcessLinux::MonitorSignal(const
                 // leave the signal intact if this is the thread that was chosen as the
                 // triggering thread.
                 if (m_pending_notification_up && m_pending_notification_up->triggering_tid == pid)
-                    linux_thread_sp->SetStoppedBySignal(SIGSTOP);
+                    linux_thread_sp->SetStoppedBySignal(SIGSTOP, info);
                 else
                     linux_thread_sp->SetStoppedBySignal(0);
 
@@ -2217,22 +2217,8 @@ NativeProcessLinux::MonitorSignal(const
     // This thread is stopped.
     ThreadDidStop (pid, false);
 
-    switch (signo)
-    {
-    case SIGSEGV:
-    case SIGILL:
-    case SIGFPE:
-    case SIGBUS:
-        if (thread_sp)
-            std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetCrashedWithException (*info);
-        break;
-    default:
-        // This is just a pre-signal-delivery notification of the incoming signal.
-        if (thread_sp)
-            std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStoppedBySignal (signo);
-
-        break;
-    }
+    if (thread_sp)
+        std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStoppedBySignal(signo, info);
 
     // Send a stop to the debugger after we get all other threads to stop.
     StopRunningThreads (pid);

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Fri May 29 05:13:03 2015
@@ -125,15 +125,7 @@ NativeThreadLinux::GetStopReason (Thread
         if (log)
             LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:");
         stop_info = m_stop_info;
-        switch (m_stop_info.reason)
-        {
-            case StopReason::eStopReasonException:
-            case StopReason::eStopReasonBreakpoint:
-            case StopReason::eStopReasonWatchpoint:
-                description = m_stop_description;
-            default:
-                break;
-        }
+        description = m_stop_description;
         if (log)
             LogThreadStopInfo (*log, stop_info, "returned stop_info:");
 
@@ -250,7 +242,7 @@ NativeThreadLinux::SetStepping ()
 }
 
 void
-NativeThreadLinux::SetStoppedBySignal (uint32_t signo)
+NativeThreadLinux::SetStoppedBySignal(uint32_t signo, const siginfo_t *info)
 {
     Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
     if (log)
@@ -262,6 +254,20 @@ NativeThreadLinux::SetStoppedBySignal (u
 
     m_stop_info.reason = StopReason::eStopReasonSignal;
     m_stop_info.details.signal.signo = signo;
+
+    m_stop_description.clear();
+    switch (signo)
+    {
+    case SIGSEGV:
+    case SIGBUS:
+    case SIGFPE:
+    case SIGILL:
+        if (! info)
+            break;
+        const auto reason = GetCrashReason(*info);
+        m_stop_description = GetCrashReasonString(reason, reinterpret_cast<uintptr_t>(info->si_addr));
+        break;
+    }
 }
 
 bool
@@ -356,20 +362,6 @@ NativeThreadLinux::SetStoppedByTrace ()
 }
 
 void
-NativeThreadLinux::SetCrashedWithException (const siginfo_t& info)
-{
-    const StateType new_state = StateType::eStateCrashed;
-    MaybeLogStateChange (new_state);
-    m_state = new_state;
-
-    m_stop_info.reason = StopReason::eStopReasonException;
-    m_stop_info.details.signal.signo = info.si_signo;
-
-    const auto reason = GetCrashReason (info);
-    m_stop_description = GetCrashReasonString (reason, reinterpret_cast<uintptr_t>(info.si_addr));
-}
-
-void
 NativeThreadLinux::SetSuspended ()
 {
     const StateType new_state = StateType::eStateSuspended;

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Fri May 29 05:13:03 2015
@@ -60,7 +60,7 @@ namespace process_linux {
         SetStepping ();
 
         void
-        SetStoppedBySignal (uint32_t signo);
+        SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
 
         /// Return true if the thread is stopped.
         /// If stopped by a signal, indicate the signo in the signo argument.

Modified: lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp Fri May 29 05:13:03 2015
@@ -134,69 +134,69 @@ GetCrashReasonString (CrashReason reason
         break;
 
     case CrashReason::eInvalidAddress:
-        str = "invalid address";
+        str = "signal SIGSEGV: invalid address";
         AppendFaultAddr (str, fault_addr);
         break;
     case CrashReason::ePrivilegedAddress:
-        str = "address access protected";
+        str = "signal SIGSEGV: address access protected";
         AppendFaultAddr (str, fault_addr);
         break;
     case CrashReason::eIllegalOpcode:
-        str = "illegal instruction";
+        str = "signal SIGILL: illegal instruction";
         break;
     case CrashReason::eIllegalOperand:
-        str = "illegal instruction operand";
+        str = "signal SIGILL: illegal instruction operand";
         break;
     case CrashReason::eIllegalAddressingMode:
-        str = "illegal addressing mode";
+        str = "signal SIGILL: illegal addressing mode";
         break;
     case CrashReason::eIllegalTrap:
-        str = "illegal trap";
+        str = "signal SIGILL: illegal trap";
         break;
     case CrashReason::ePrivilegedOpcode:
-        str = "privileged instruction";
+        str = "signal SIGILL: privileged instruction";
         break;
     case CrashReason::ePrivilegedRegister:
-        str = "privileged register";
+        str = "signal SIGILL: privileged register";
         break;
     case CrashReason::eCoprocessorError:
-        str = "coprocessor error";
+        str = "signal SIGILL: coprocessor error";
         break;
     case CrashReason::eInternalStackError:
-        str = "internal stack error";
+        str = "signal SIGILL: internal stack error";
         break;
     case CrashReason::eIllegalAlignment:
-        str = "illegal alignment";
+        str = "signal SIGBUS: illegal alignment";
         break;
     case CrashReason::eIllegalAddress:
-        str = "illegal address";
+        str = "signal SIGBUS: illegal address";
         break;
     case CrashReason::eHardwareError:
-        str = "hardware error";
+        str = "signal SIGBUS: hardware error";
         break;
     case CrashReason::eIntegerDivideByZero:
-        str = "integer divide by zero";
+        str = "signal SIGFPE: integer divide by zero";
         break;
     case CrashReason::eIntegerOverflow:
-        str = "integer overflow";
+        str = "signal SIGFPE: integer overflow";
         break;
     case CrashReason::eFloatDivideByZero:
-        str = "floating point divide by zero";
+        str = "signal SIGFPE: floating point divide by zero";
         break;
     case CrashReason::eFloatOverflow:
-        str = "floating point overflow";
+        str = "signal SIGFPE: floating point overflow";
         break;
     case CrashReason::eFloatUnderflow:
-        str = "floating point underflow";
+        str = "signal SIGFPE: floating point underflow";
         break;
     case CrashReason::eFloatInexactResult:
-        str = "inexact floating point result";
+        str = "signal SIGFPE: inexact floating point result";
         break;
     case CrashReason::eFloatInvalidOperation:
-        str = "invalid floating point operation";
+        str = "signal SIGFPE: invalid floating point operation";
         break;
     case CrashReason::eFloatSubscriptRange:
-        str = "invalid floating point subscript range";
+        str = "signal SIGFPE: invalid floating point subscript range";
         break;
     }
 

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Fri May 29 05:13:03 2015
@@ -2080,11 +2080,11 @@ ProcessGDBRemote::SetThreadStopInfo (Str
                                 if (thread_sp->GetTemporaryResumeState() == eStateStepping)
                                     thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
                                 else
-                                    thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo));
+                                    thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str()));
                             }
                         }
                         if (!handled)
-                            thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo));
+                            thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str()));
                     }
 
                     if (!description.empty())

Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Fri May 29 05:13:03 2015
@@ -871,9 +871,10 @@ class StopInfoUnixSignal : public StopIn
 {
 public:
 
-    StopInfoUnixSignal (Thread &thread, int signo) :
+    StopInfoUnixSignal (Thread &thread, int signo, const char *description) :
         StopInfo (thread, signo)
     {
+        SetDescription (description);
     }
     
     virtual ~StopInfoUnixSignal ()
@@ -1161,9 +1162,9 @@ StopInfo::CreateStopReasonWithWatchpoint
 }
 
 StopInfoSP
-StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo)
+StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo, const char *description)
 {
-    return StopInfoSP (new StopInfoUnixSignal (thread, signo));
+    return StopInfoSP (new StopInfoUnixSignal (thread, signo, description));
 }
 
 StopInfoSP

Modified: lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py (original)
+++ lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py Fri May 29 05:13:03 2015
@@ -49,20 +49,14 @@ class ChangedInferiorTestCase(TestBase):
 
         self.runCmd("run", RUN_FAILED)
 
-        if self.platformIsDarwin():
-            stop_reason = 'stop reason = EXC_BAD_ACCESS'
-        else:
-            stop_reason = 'stop reason = invalid address'
-
-        # The stop reason of the thread should be a bad access exception.
-        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
-            substrs = ['stopped',
-                       stop_reason])
+        # We should have one crashing thread
+        self.assertEquals(
+                len(lldbutil.get_crashed_threads(self, self.dbg.GetSelectedTarget().GetProcess())),
+                1,
+                STOPPED_DUE_TO_EXC_BAD_ACCESS)
 
         # And it should report the correct line number.
-        self.expect("thread backtrace all",
-            substrs = [stop_reason,
-                       'main.c:%d' % self.line1])
+        self.expect("thread backtrace all", substrs = ['main.c:%d' % self.line1])
 
     def inferior_not_crashing(self):
         """Test lldb reloads the inferior after it was changed during the session."""
@@ -73,13 +67,10 @@ class ChangedInferiorTestCase(TestBase):
         self.runCmd("run", RUN_FAILED)
         self.runCmd("process status")
 
-        if self.platformIsDarwin():
-            stop_reason = 'EXC_BAD_ACCESS'
-        else:
-            stop_reason = 'invalid address'
-
-        if stop_reason in self.res.GetOutput():
-            self.fail("Inferior changed, but lldb did not perform a reload")
+        self.assertNotEquals(
+                len(lldbutil.get_crashed_threads(self, self.dbg.GetSelectedTarget().GetProcess())),
+                1,
+                "Inferior changed, but lldb did not perform a reload")
 
         # Break inside the main.
         lldbutil.run_break_set_by_file_and_line (self, "main2.c", self.line2, num_expected_locations=1, loc_exact=True)

Modified: lldb/trunk/test/functionalities/inferior-crashing/TestInferiorCrashing.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/inferior-crashing/TestInferiorCrashing.py?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/inferior-crashing/TestInferiorCrashing.py (original)
+++ lldb/trunk/test/functionalities/inferior-crashing/TestInferiorCrashing.py Fri May 29 05:13:03 2015
@@ -79,7 +79,7 @@ class CrashingInferiorTestCase(TestBase)
         self.inferior_crashing_expr_step_expr()
 
     @expectedFailureFreeBSD('llvm.org/pr15989') # Couldn't allocate space for the stack frame
-    @expectedFailureAll("llvm.org/pr23139", oslist=["linux"], compiler="gcc", compiler_version=[">=","4.9"], archs=["i386"])
+    @skipIfLinux # Inferior exits after stepping after a segfault. This is working as intended IMHO.
     def test_inferior_crashing_expr_step_and_expr_dwarf(self):
         """Test that lldb expressions work before and after stepping after a crash."""
         self.buildDwarf()
@@ -89,17 +89,11 @@ class CrashingInferiorTestCase(TestBase)
         lldbutil.run_break_set_by_file_and_line (self, "main.c", line, num_expected_locations=1, loc_exact=True)
 
     def check_stop_reason(self):
-        if self.platformIsDarwin():
-            stop_reason = 'stop reason = EXC_BAD_ACCESS'
-        else:
-            stop_reason = 'stop reason = invalid address'
-
-        # The stop reason of the thread should be a bad access exception.
-        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
-            substrs = ['stopped',
-                       stop_reason])
-
-        return stop_reason
+        # We should have one crashing thread
+        self.assertEquals(
+                len(lldbutil.get_crashed_threads(self, self.dbg.GetSelectedTarget().GetProcess())),
+                1,
+                STOPPED_DUE_TO_EXC_BAD_ACCESS)
 
     def get_api_stop_reason(self):
         return lldb.eStopReasonException
@@ -116,7 +110,16 @@ class CrashingInferiorTestCase(TestBase)
         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         self.runCmd("run", RUN_FAILED)
-        stop_reason = self.check_stop_reason()
+        # The exact stop reason depends on the platform
+        if self.platformIsDarwin():
+            stop_reason = 'stop reason = EXC_BAD_ACCESS'
+        elif self.getPlatform() == "linux":
+            stop_reason = 'stop reason = signal SIGSEGV'
+        else:
+            stop_reason = 'stop reason = invalid address'
+        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
+            substrs = ['stopped',
+                       stop_reason])
 
         # And it should report the correct line number.
         self.expect("thread backtrace all",
@@ -139,12 +142,11 @@ class CrashingInferiorTestCase(TestBase)
                       "instead the actual state is: '%s'" %
                       lldbutil.state_type_to_str(process.GetState()))
 
-        thread = lldbutil.get_stopped_thread(process, self.get_api_stop_reason())
-        if not thread:
-            self.fail("Fail to stop the thread upon bad access exception")
+        threads = lldbutil.get_crashed_threads(self, process)
+        self.assertEqual(len(threads), 1, "Failed to stop the thread upon bad access exception")
 
         if self.TraceOn():
-            lldbutil.print_stacktrace(thread)
+            lldbutil.print_stacktrace(threads[0])
 
     def inferior_crashing_registers(self):
         """Test that lldb can read registers after crashing."""
@@ -185,7 +187,7 @@ class CrashingInferiorTestCase(TestBase)
                        'stop reason = breakpoint'])
 
         self.runCmd("next")
-        stop_reason = self.check_stop_reason()
+        self.check_stop_reason()
 
         # The lldb expression interpreter should be able to read from addresses of the inferior after a crash.
         self.expect("p argv[0]",
@@ -198,8 +200,7 @@ class CrashingInferiorTestCase(TestBase)
 
         # And it should report the correct line number.
         self.expect("thread backtrace all",
-            substrs = [stop_reason,
-                       'main.c:%d' % self.line])
+            substrs = ['main.c:%d' % self.line])
 
     def inferior_crashing_step_after_break(self):
         """Test that lldb behaves correctly when stepping after a crash."""
@@ -209,8 +210,17 @@ class CrashingInferiorTestCase(TestBase)
         self.runCmd("run", RUN_FAILED)
         self.check_stop_reason()
 
-        self.runCmd("next")
-        self.check_stop_reason()
+        expected_state = 'exited' # Provide the exit code.
+        if self.platformIsDarwin():
+            expected_state = 'stopped' # TODO: Determine why 'next' and 'continue' have no effect after a crash.
+
+        self.expect("next",
+            substrs = ['Process', expected_state])
+
+        if expected_state == 'exited':
+            self.expect("thread list", error=True,substrs = ['Process must be launched'])
+        else:
+            self.check_stop_reason()
 
     def inferior_crashing_expr_step_expr(self):
         """Test that lldb expressions work before and after stepping after a crash."""

Modified: lldb/trunk/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py (original)
+++ lldb/trunk/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py Fri May 29 05:13:03 2015
@@ -79,6 +79,7 @@ class CrashingRecursiveInferiorTestCase(
         self.recursive_inferior_crashing_expr_step_expr()
 
     @expectedFailureFreeBSD('llvm.org/pr15989') # Couldn't allocate space for the stack frame
+    @skipIfLinux # Inferior exits after stepping after a segfault. This is working as intended IMHO.
     def test_recursive_inferior_crashing_expr_step_and_expr_dwarf(self):
         """Test that lldb expressions work before and after stepping after a crash."""
         self.buildDwarf()
@@ -88,17 +89,11 @@ class CrashingRecursiveInferiorTestCase(
         lldbutil.run_break_set_by_file_and_line (self, "main.c", line, num_expected_locations=1, loc_exact=True)
 
     def check_stop_reason(self):
-        if self.platformIsDarwin():
-            stop_reason = 'stop reason = EXC_BAD_ACCESS'
-        else:
-            stop_reason = 'stop reason = invalid address'
-
-        # The stop reason of the thread should be a bad access exception.
-        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
-            substrs = ['stopped',
-                       stop_reason])
-
-        return stop_reason
+        # We should have one crashing thread
+        self.assertEquals(
+                len(lldbutil.get_crashed_threads(self, self.dbg.GetSelectedTarget().GetProcess())),
+                1,
+                STOPPED_DUE_TO_EXC_BAD_ACCESS)
 
     def setUp(self):
         # Call super's setUp().
@@ -112,7 +107,17 @@ class CrashingRecursiveInferiorTestCase(
         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         self.runCmd("run", RUN_FAILED)
-        stop_reason = self.check_stop_reason()
+
+        # The exact stop reason depends on the platform
+        if self.platformIsDarwin():
+            stop_reason = 'stop reason = EXC_BAD_ACCESS'
+        elif self.getPlatform() == "linux":
+            stop_reason = 'stop reason = signal SIGSEGV'
+        else:
+            stop_reason = 'stop reason = invalid address'
+        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
+            substrs = ['stopped',
+                       stop_reason])
 
         # And it should report a backtrace that includes main and the crash site.
         self.expect("thread backtrace all",
@@ -139,12 +144,11 @@ class CrashingRecursiveInferiorTestCase(
                       "instead the actual state is: '%s'" %
                       lldbutil.state_type_to_str(process.GetState()))
 
-        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonException)
-        if not thread:
-            self.fail("Fail to stop the thread upon bad access exception")
+        threads = lldbutil.get_crashed_threads(self, process)
+        self.assertEqual(len(threads), 1, "Failed to stop the thread upon bad access exception")
 
         if self.TraceOn():
-            lldbutil.print_stacktrace(thread)
+            lldbutil.print_stacktrace(threads[0])
 
     def recursive_inferior_crashing_registers(self):
         """Test that lldb can read registers after crashing."""
@@ -182,7 +186,7 @@ class CrashingRecursiveInferiorTestCase(
                        'stop reason = breakpoint'])
 
         self.runCmd("next")
-        stop_reason = self.check_stop_reason()
+        self.check_stop_reason()
 
         # The lldb expression interpreter should be able to read from addresses of the inferior after a crash.
         self.expect("p i",
@@ -193,8 +197,7 @@ class CrashingRecursiveInferiorTestCase(
 
         # And it should report the correct line number.
         self.expect("thread backtrace all",
-            substrs = [stop_reason,
-                       'main.c:%d' % self.line])
+            substrs = ['main.c:%d' % self.line])
 
     def recursive_inferior_crashing_step_after_break(self):
         """Test that lldb behaves correctly when stepping after a crash."""
@@ -205,7 +208,7 @@ class CrashingRecursiveInferiorTestCase(
         self.check_stop_reason()
 
         expected_state = 'exited' # Provide the exit code.
-        if self.platformIsDarwin() or self.getPlatform() == "linux":
+        if self.platformIsDarwin():
             expected_state = 'stopped' # TODO: Determine why 'next' and 'continue' have no effect after a crash.
 
         self.expect("next",

Added: lldb/trunk/test/functionalities/signal/handle-segv/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/signal/handle-segv/Makefile?rev=238549&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/signal/handle-segv/Makefile (added)
+++ lldb/trunk/test/functionalities/signal/handle-segv/Makefile Fri May 29 05:13:03 2015
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/signal/handle-segv/TestHandleSegv.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/signal/handle-segv/TestHandleSegv.py?rev=238549&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/signal/handle-segv/TestHandleSegv.py (added)
+++ lldb/trunk/test/functionalities/signal/handle-segv/TestHandleSegv.py Fri May 29 05:13:03 2015
@@ -0,0 +1,45 @@
+"""Test that we can debug inferiors that handle SIGSEGV by themselves"""
+
+import os
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+import re
+
+
+class HandleSegvTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipIfWindows # signals do not exist on Windows
+    @skipIfDarwin
+    def test_inferior_handle_sigsegv_with_dwarf(self):
+        self.buildDefault()
+        exe = os.path.join(os.getcwd(), "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("SIGSEGV")
+
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
+        self.assertTrue(thread.IsValid(), "Thread should be stopped due to a signal")
+        self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.")
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo, "The stop signal was SIGSEGV")
+
+        # Continue until we exit.
+        process.Continue()
+        self.assertEqual(process.GetState(), lldb.eStateExited)
+        self.assertEqual(process.GetExitStatus(), 0)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/signal/handle-segv/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/signal/handle-segv/main.c?rev=238549&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/signal/handle-segv/main.c (added)
+++ lldb/trunk/test/functionalities/signal/handle-segv/main.c Fri May 29 05:13:03 2015
@@ -0,0 +1,58 @@
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+enum {
+    kMmapSize = 0x1000,
+    kMagicValue = 47,
+};
+
+void *address;
+volatile sig_atomic_t signaled = 0;
+
+void handler(int sig)
+{
+    signaled = 1;
+    if (munmap(address, kMmapSize) != 0)
+    {
+        perror("munmap");
+        _exit(5);
+    }
+
+    void* newaddr = mmap(address, kMmapSize, PROT_READ | PROT_WRITE,
+            MAP_ANON | MAP_FIXED | MAP_PRIVATE, -1, 0);
+    if (newaddr != address)
+    {
+        fprintf(stderr, "Newly mmaped address (%p) does not equal old address (%p).\n",
+                newaddr, address);
+        _exit(6);
+    }
+    *(int*)newaddr = kMagicValue;
+}
+
+int main()
+{
+    if (signal(SIGSEGV, handler) == SIG_ERR)
+    {
+        perror("signal");
+        return 1;
+    }
+
+    address = mmap(NULL, kMmapSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (address == MAP_FAILED)
+    {
+        perror("mmap");
+        return 2;
+    }
+
+    // This should first trigger a segfault. Our handler will make the memory readable and write
+    // the magic value into memory.
+    if (*(int*)address != kMagicValue)
+        return 3;
+
+    if (! signaled)
+        return 4;
+
+    return 0;
+}

Modified: lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py (original)
+++ lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py Fri May 29 05:13:03 2015
@@ -390,6 +390,13 @@ class ConcurrentEventsTestCase(TestBase)
                 self.crash_count > 0 or \
                 self.inferior_process.GetState() == lldb.eStateExited
 
+    def count_signaled_threads(self):
+        count = 0
+        for thread in self.inferior_process:
+            if thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(0) == self.inferior_process.GetUnixSignals().GetSignalNumberFromName('SIGUSR1'):
+                count += 1
+        return count
+
     def do_thread_actions(self,
                           num_breakpoint_threads = 0,
                           num_signal_threads = 0,
@@ -470,16 +477,16 @@ class ConcurrentEventsTestCase(TestBase)
                                                                          num_threads,
                                                                          "\n\t".join(self.describe_threads())))
 
-        self.signal_count = len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonSignal))
-        self.crash_count = len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonException))
+        self.signal_count = self.count_signaled_threads()
+        self.crash_count = len(lldbutil.get_crashed_threads(self, self.inferior_process))
 
         # Run to completion (or crash)
         while not self.inferior_done(): 
             if self.TraceOn():
                 self.runCmd("thread backtrace all")
             self.runCmd("continue")
-            self.signal_count += len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonSignal))
-            self.crash_count += len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonException))
+            self.signal_count += self.count_signaled_threads()
+            self.crash_count += len(lldbutil.get_crashed_threads(self, self.inferior_process))
 
         if num_crash_threads > 0 or num_delay_crash_threads > 0:
             # Expecting a crash

Modified: lldb/trunk/test/lldbutil.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbutil.py?rev=238549&r1=238548&r2=238549&view=diff
==============================================================================
--- lldb/trunk/test/lldbutil.py (original)
+++ lldb/trunk/test/lldbutil.py Fri May 29 05:13:03 2015
@@ -553,6 +553,25 @@ def get_threads_stopped_at_breakpoint (p
 
     return threads
 
+def is_thread_crashed (test, thread):
+    """In the test suite we dereference a null pointer to simulate a crash. The way this is
+    reported depends on the platform."""
+    if test.platformIsDarwin():
+        return thread.GetStopReason() == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100)
+    elif test.getPlatform() == "linux":
+        return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV")
+    else:
+        return "invalid address" in thread.GetStopDescription(100)
+
+def get_crashed_threads (test, process):
+    threads = []
+    if process.GetState() != lldb.eStateStopped:
+        return threads
+    for thread in process:
+        if is_thread_crashed(test, thread):
+            threads.append(thread)
+    return threads
+
 def continue_to_breakpoint (process, bkpt):
     """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
     process.Continue()





More information about the lldb-commits mailing list