summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp34
-rw-r--r--lldb/test/functionalities/signal/raise/Makefile5
-rw-r--r--lldb/test/functionalities/signal/raise/TestRaise.py95
-rw-r--r--lldb/test/functionalities/signal/raise/main.c23
4 files changed, 132 insertions, 25 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index f1ddac19e9b..048819c904f 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -2266,9 +2266,16 @@ NativeProcessLinux::MonitorCallback(lldb::pid_t pid,
if (err.GetError() == EINVAL)
{
// This is a group stop reception for this tid.
+ // We can reach here if we reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU into the
+ // tracee, triggering the group-stop mechanism. Normally receiving these would stop
+ // the process, pending a SIGCONT. Simulating this state in a debugger is hard and is
+ // generally not needed (one use case is debugging background task being managed by a
+ // shell). For general use, it is sufficient to stop the process in a signal-delivery
+ // stop which happens before the group stop. This done by MonitorSignal and works
+ // correctly for all signals.
if (log)
- log->Printf ("NativeProcessLinux::%s received a group stop for pid %" PRIu64 " tid %" PRIu64, __FUNCTION__, GetID (), pid);
- ThreadDidStop(pid, false);
+ log->Printf("NativeProcessLinux::%s received a group stop for pid %" PRIu64 " tid %" PRIu64 ". Transparent handling of group stops not supported, resuming the thread.", __FUNCTION__, GetID (), pid);
+ Resume(pid, signal);
}
else
{
@@ -2776,29 +2783,6 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
switch (signo)
{
- case SIGSTOP:
- {
- std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStoppedBySignal (signo);
- if (log)
- {
- if (is_from_llgs)
- log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " received SIGSTOP from llgs, most likely an interrupt", __FUNCTION__, GetID (), pid);
- else
- log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " received SIGSTOP from outside of debugger", __FUNCTION__, GetID (), pid);
- }
-
- // Resume this thread to get the group-stop mechanism to fire off the true group stops.
- // This thread will get stopped again as part of the group-stop completion.
- ResumeThread(pid,
- [=](lldb::tid_t tid_to_resume, bool supress_signal)
- {
- std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetRunning ();
- // Pass this signal number on to the inferior to handle.
- return Resume (tid_to_resume, (supress_signal) ? LLDB_INVALID_SIGNAL_NUMBER : signo);
- },
- true);
- }
- break;
case SIGSEGV:
case SIGILL:
case SIGFPE:
diff --git a/lldb/test/functionalities/signal/raise/Makefile b/lldb/test/functionalities/signal/raise/Makefile
new file mode 100644
index 00000000000..b09a579159d
--- /dev/null
+++ b/lldb/test/functionalities/signal/raise/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/signal/raise/TestRaise.py b/lldb/test/functionalities/signal/raise/TestRaise.py
new file mode 100644
index 00000000000..0001272c6e1
--- /dev/null
+++ b/lldb/test/functionalities/signal/raise/TestRaise.py
@@ -0,0 +1,95 @@
+"""Test that we handle inferiors that send signals to themselves"""
+
+import os
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+
+class RaiseTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows # signals do not exist on Windows
+ @skipUnlessDarwin
+ @dsym_test
+ def test_sigstop_with_dsym(self):
+ self.buildDsym()
+ self.sigstop()
+
+ @skipIfWindows # signals do not exist on Windows
+ @dwarf_test
+ def test_sigstop_with_dwarf(self):
+ self.buildDwarf()
+ self.sigstop()
+
+ def launch(self, target):
+ # launch the process, do not stop at entry point.
+ process = target.LaunchSimple(['SIGSTOP'], None, self.get_process_working_directory())
+ self.assertTrue(process, PROCESS_IS_VALID)
+ self.assertEqual(process.GetState(), lldb.eStateStopped)
+ thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ self.assertTrue(thread.IsValid(), "Thread should be stopped due to a breakpoint")
+ return process
+
+ def set_handle(self, signal, stop_at_signal, pass_signal, notify_signal):
+ return_obj = lldb.SBCommandReturnObject()
+ self.dbg.GetCommandInterpreter().HandleCommand(
+ "process handle %s -s %d -p %d -n %d" % (signal, stop_at_signal, pass_signal, notify_signal),
+ return_obj)
+ self.assertTrue (return_obj.Succeeded() == True, "Setting signal handling failed")
+
+
+ def sigstop(self):
+ """Test that we handle inferior raising SIGSTOP"""
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ # Create a target by the debugger.
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+ lldbutil.run_break_set_by_symbol(self, "main")
+
+ # launch
+ process = self.launch(target)
+
+ # Make sure we stop at the signal
+ self.set_handle("SIGSTOP", 1, 0, 1)
+ process.Continue()
+ 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),
+ process.GetUnixSignals().GetSignalNumberFromName('SIGSTOP'),
+ "The stop signal was SIGSTOP")
+
+ # Continue until we exit.
+ process.Continue()
+ self.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # launch again
+ process = self.launch(target)
+
+ # Make sure we do not stop at the signal. We should still get the notification.
+ self.set_handle("SIGSTOP", 0, 0, 1)
+ self.expect("process continue", substrs=["stopped and restarted", "SIGSTOP"])
+ self.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # launch again
+ process = self.launch(target)
+
+ # Make sure we do not stop at the signal, and we do not get the notification.
+ self.set_handle("SIGSTOP", 0, 0, 0)
+ self.expect("process continue", substrs=["stopped and restarted"], matching=False)
+ self.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # passing of SIGSTOP is not correctly handled, so not testing that scenario: https://llvm.org/bugs/show_bug.cgi?id=23574
+
+ # reset signal handling to default
+ self.set_handle("SIGSTOP", 1, 0, 1)
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/functionalities/signal/raise/main.c b/lldb/test/functionalities/signal/raise/main.c
new file mode 100644
index 00000000000..1cea4218adb
--- /dev/null
+++ b/lldb/test/functionalities/signal/raise/main.c
@@ -0,0 +1,23 @@
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+int main (int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ puts("Please specify a signal to raise");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "SIGSTOP") == 0)
+ raise(SIGSTOP);
+ else
+ {
+ printf("Unknown signal: %s\n", argv[1]);
+ return 2;
+ }
+
+ return 0;
+}
+
OpenPOWER on IntegriCloud