1"""Test that we handle inferiors that send signals to themselves"""
2
3
4
5import lldb
6import re
7from lldbsuite.test.lldbplatformutil import getDarwinOSTriples
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13@skipIfWindows  # signals do not exist on Windows
14class RaiseTestCase(TestBase):
15
16    mydir = TestBase.compute_mydir(__file__)
17    NO_DEBUG_INFO_TESTCASE = True
18
19    @skipIfNetBSD  # Hangs on NetBSD
20    def test_sigstop(self):
21        self.build()
22        self.signal_test('SIGSTOP', False)
23        # passing of SIGSTOP is not correctly handled, so not testing that
24        # scenario: https://llvm.org/bugs/show_bug.cgi?id=23574
25
26    @skipIfDarwin  # darwin does not support real time signals
27    @skipIfTargetAndroid()
28    def test_sigsigrtmin(self):
29        self.build()
30        self.signal_test('SIGRTMIN', True)
31
32    @skipIfNetBSD  # Hangs on NetBSD
33    def test_sigtrap(self):
34        self.build()
35        self.signal_test('SIGTRAP', True)
36
37    def launch(self, target, signal):
38        # launch the process, do not stop at entry point.
39        # If we have gotten the default for this signal, reset that as well.
40        if len(self.default_pass) != 0:
41            lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
42
43        process = target.LaunchSimple(
44            [signal], None, self.get_process_working_directory())
45        self.assertTrue(process, PROCESS_IS_VALID)
46        self.assertEqual(process.GetState(), lldb.eStateStopped)
47        thread = lldbutil.get_stopped_thread(
48            process, lldb.eStopReasonBreakpoint)
49        self.assertTrue(
50            thread.IsValid(),
51            "Thread should be stopped due to a breakpoint")
52        return process
53
54    def set_handle(self, signal, pass_signal, stop_at_signal, notify_signal):
55        return_obj = lldb.SBCommandReturnObject()
56        self.dbg.GetCommandInterpreter().HandleCommand(
57            "process handle %s -p %s -s %s -n %s" %
58            (signal, pass_signal, stop_at_signal, notify_signal), return_obj)
59        self.assertTrue(
60            return_obj.Succeeded(),
61            "Setting signal handling failed")
62
63    def signal_test(self, signal, test_passing):
64        """Test that we handle inferior raising signals"""
65        exe = self.getBuildArtifact("a.out")
66
67        # Create a target by the debugger.
68        target = self.dbg.CreateTarget(exe)
69        self.assertTrue(target, VALID_TARGET)
70        lldbutil.run_break_set_by_symbol(self, "main")
71        self.default_pass = ""
72        self.default_stop = ""
73        self.default_notify = ""
74
75        # launch
76        process = self.launch(target, signal)
77        signo = process.GetUnixSignals().GetSignalNumberFromName(signal)
78
79        # retrieve default signal disposition
80        (self.default_pass, self.default_stop, self.default_notify) = lldbutil.get_actions_for_signal(self, signal)
81
82        # Make sure we stop at the signal
83        lldbutil.set_actions_for_signal(self, signal, "false", "true", "true")
84        process.Continue()
85        self.assertEqual(process.GetState(), lldb.eStateStopped)
86        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
87        self.assertTrue(
88            thread.IsValid(),
89            "Thread should be stopped due to a signal")
90        self.assertTrue(
91            thread.GetStopReasonDataCount() >= 1,
92            "There was data in the event.")
93        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo,
94                         "The stop signal was %s" % signal)
95
96        # Continue until we exit.
97        process.Continue()
98        self.assertEqual(process.GetState(), lldb.eStateExited)
99        self.assertEqual(process.GetExitStatus(), 0)
100
101        process = self.launch(target, signal)
102
103        # Make sure we do not stop at the signal. We should still get the
104        # notification.
105        lldbutil.set_actions_for_signal(self, signal, "false", "false", "true")
106        self.expect(
107            "process continue",
108            substrs=[
109                "stopped and restarted",
110                signal])
111        self.assertEqual(process.GetState(), lldb.eStateExited)
112        self.assertEqual(process.GetExitStatus(), 0)
113
114        # launch again
115        process = self.launch(target, signal)
116
117        # Make sure we do not stop at the signal, and we do not get the
118        # notification.
119        lldbutil.set_actions_for_signal(self, signal, "false", "false", "false")
120        self.expect(
121            "process continue",
122            substrs=["stopped and restarted"],
123            matching=False)
124        self.assertEqual(process.GetState(), lldb.eStateExited)
125        self.assertEqual(process.GetExitStatus(), 0)
126
127        if not test_passing:
128            # reset signal handling to default
129            lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
130            return
131
132        # launch again
133        process = self.launch(target, signal)
134
135        # Make sure we stop at the signal
136        lldbutil.set_actions_for_signal(self, signal, "true", "true", "true")
137        process.Continue()
138        self.assertEqual(process.GetState(), lldb.eStateStopped)
139        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
140        self.assertTrue(
141            thread.IsValid(),
142            "Thread should be stopped due to a signal")
143        self.assertTrue(
144            thread.GetStopReasonDataCount() >= 1,
145            "There was data in the event.")
146        self.assertEqual(
147            thread.GetStopReasonDataAtIndex(0),
148            process.GetUnixSignals().GetSignalNumberFromName(signal),
149            "The stop signal was %s" %
150            signal)
151
152        # Continue until we exit. The process should receive the signal.
153        process.Continue()
154        self.assertEqual(process.GetState(), lldb.eStateExited)
155        self.assertEqual(process.GetExitStatus(), signo)
156
157        # launch again
158        process = self.launch(target, signal)
159
160        # Make sure we do not stop at the signal. We should still get the notification. Process
161        # should receive the signal.
162        lldbutil.set_actions_for_signal(self, signal, "true", "false", "true")
163        self.expect(
164            "process continue",
165            substrs=[
166                "stopped and restarted",
167                signal])
168        self.assertEqual(process.GetState(), lldb.eStateExited)
169        self.assertEqual(process.GetExitStatus(), signo)
170
171        # launch again
172        process = self.launch(target, signal)
173
174        # Make sure we do not stop at the signal, and we do not get the notification. Process
175        # should receive the signal.
176        lldbutil.set_actions_for_signal(self, signal, "true", "false", "false")
177        self.expect(
178            "process continue",
179            substrs=["stopped and restarted"],
180            matching=False)
181        self.assertEqual(process.GetState(), lldb.eStateExited)
182        self.assertEqual(process.GetExitStatus(), signo)
183
184        # reset signal handling to default
185        lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
186