summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Target/StopInfo.h2
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp20
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp40
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.h2
-rw-r--r--lldb/source/Plugins/Process/POSIX/CrashReason.cpp42
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp4
-rw-r--r--lldb/source/Target/StopInfo.cpp7
-rw-r--r--lldb/test/functionalities/inferior-changed/TestInferiorChanged.py29
-rw-r--r--lldb/test/functionalities/inferior-crashing/TestInferiorCrashing.py54
-rw-r--r--lldb/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py43
-rw-r--r--lldb/test/functionalities/signal/handle-segv/Makefile5
-rw-r--r--lldb/test/functionalities/signal/handle-segv/TestHandleSegv.py45
-rw-r--r--lldb/test/functionalities/signal/handle-segv/main.c58
-rw-r--r--lldb/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py15
-rw-r--r--lldb/test/lldbutil.py19
15 files changed, 251 insertions, 134 deletions
diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h
index 61bc084f1bd..d09900f7637 100644
--- a/lldb/include/lldb/Target/StopInfo.h
+++ b/lldb/include/lldb/Target/StopInfo.h
@@ -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);
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 489890aa513..ec286b055c4 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -2177,7 +2177,7 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
// 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 siginfo_t *info, lldb::pid_t pid, bool e
// 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);
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index cd0dd7edc51..8950702c532 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -125,15 +125,7 @@ NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info, std::string& descri
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 (uint32_t signo)
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;
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index d78e99c166c..289387bad72 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -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.
diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
index 4dd91a6f1de..6de13f470c5 100644
--- a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
+++ b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -134,69 +134,69 @@ GetCrashReasonString (CrashReason reason, lldb::addr_t fault_addr)
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;
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 61cc89dc71b..8d01d003592 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2080,11 +2080,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
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())
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index d4957341e04..6cc16132988 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -871,9 +871,10 @@ class StopInfoUnixSignal : public StopInfo
{
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::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id)
}
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
diff --git a/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py b/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
index b4d1b1b4418..95141c45dd4 100644
--- a/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
+++ b/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
@@ -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)
diff --git a/lldb/test/functionalities/inferior-crashing/TestInferiorCrashing.py b/lldb/test/functionalities/inferior-crashing/TestInferiorCrashing.py
index dc30ea94e8a..8ad5e429c89 100644
--- a/lldb/test/functionalities/inferior-crashing/TestInferiorCrashing.py
+++ b/lldb/test/functionalities/inferior-crashing/TestInferiorCrashing.py
@@ -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."""
diff --git a/lldb/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py b/lldb/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py
index c31816fd0d0..cd89fe1cd53 100644
--- a/lldb/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py
+++ b/lldb/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py
@@ -79,6 +79,7 @@ class CrashingRecursiveInferiorTestCase(TestBase):
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(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 setUp(self):
# Call super's setUp().
@@ -112,7 +107,17 @@ class CrashingRecursiveInferiorTestCase(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 a backtrace that includes main and the crash site.
self.expect("thread backtrace all",
@@ -139,12 +144,11 @@ class CrashingRecursiveInferiorTestCase(TestBase):
"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(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 i",
@@ -193,8 +197,7 @@ class CrashingRecursiveInferiorTestCase(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 recursive_inferior_crashing_step_after_break(self):
"""Test that lldb behaves correctly when stepping after a crash."""
@@ -205,7 +208,7 @@ class CrashingRecursiveInferiorTestCase(TestBase):
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",
diff --git a/lldb/test/functionalities/signal/handle-segv/Makefile b/lldb/test/functionalities/signal/handle-segv/Makefile
new file mode 100644
index 00000000000..b09a579159d
--- /dev/null
+++ b/lldb/test/functionalities/signal/handle-segv/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/signal/handle-segv/TestHandleSegv.py b/lldb/test/functionalities/signal/handle-segv/TestHandleSegv.py
new file mode 100644
index 00000000000..2534cb5902f
--- /dev/null
+++ b/lldb/test/functionalities/signal/handle-segv/TestHandleSegv.py
@@ -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()
diff --git a/lldb/test/functionalities/signal/handle-segv/main.c b/lldb/test/functionalities/signal/handle-segv/main.c
new file mode 100644
index 00000000000..27d9b8e500a
--- /dev/null
+++ b/lldb/test/functionalities/signal/handle-segv/main.c
@@ -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;
+}
diff --git a/lldb/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py b/lldb/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
index 287a8422809..192bcf2ba9a 100644
--- a/lldb/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
+++ b/lldb/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
@@ -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
diff --git a/lldb/test/lldbutil.py b/lldb/test/lldbutil.py
index 8c0520bd413..71699826a1c 100644
--- a/lldb/test/lldbutil.py
+++ b/lldb/test/lldbutil.py
@@ -553,6 +553,25 @@ def get_threads_stopped_at_breakpoint (process, bkpt):
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()
OpenPOWER on IntegriCloud