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        process = target.LaunchSimple(
40            [signal], None, self.get_process_working_directory())
41        self.assertTrue(process, PROCESS_IS_VALID)
42        self.assertEqual(process.GetState(), lldb.eStateStopped)
43        thread = lldbutil.get_stopped_thread(
44            process, lldb.eStopReasonBreakpoint)
45        self.assertTrue(
46            thread.IsValid(),
47            "Thread should be stopped due to a breakpoint")
48        return process
49
50    def set_handle(self, signal, pass_signal, stop_at_signal, notify_signal):
51        return_obj = lldb.SBCommandReturnObject()
52        self.dbg.GetCommandInterpreter().HandleCommand(
53            "process handle %s -p %s -s %s -n %s" %
54            (signal, pass_signal, stop_at_signal, notify_signal), return_obj)
55        self.assertTrue(
56            return_obj.Succeeded(),
57            "Setting signal handling failed")
58
59    def signal_test(self, signal, test_passing):
60        """Test that we handle inferior raising signals"""
61        exe = self.getBuildArtifact("a.out")
62
63        # Create a target by the debugger.
64        target = self.dbg.CreateTarget(exe)
65        self.assertTrue(target, VALID_TARGET)
66        lldbutil.run_break_set_by_symbol(self, "main")
67
68        # launch
69        process = self.launch(target, signal)
70        signo = process.GetUnixSignals().GetSignalNumberFromName(signal)
71
72        # retrieve default signal disposition
73        return_obj = lldb.SBCommandReturnObject()
74        self.dbg.GetCommandInterpreter().HandleCommand(
75            "process handle %s " % signal, return_obj)
76        match = re.match(
77            'NAME *PASS *STOP *NOTIFY.*(false|true) *(false|true) *(false|true)',
78            return_obj.GetOutput(),
79            re.IGNORECASE | re.DOTALL)
80        if not match:
81            self.fail('Unable to retrieve default signal disposition.')
82        default_pass = match.group(1)
83        default_stop = match.group(2)
84        default_notify = match.group(3)
85
86        # Make sure we stop at the signal
87        self.set_handle(signal, "false", "true", "true")
88        process.Continue()
89        self.assertEqual(process.GetState(), lldb.eStateStopped)
90        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
91        self.assertTrue(
92            thread.IsValid(),
93            "Thread should be stopped due to a signal")
94        self.assertTrue(
95            thread.GetStopReasonDataCount() >= 1,
96            "There was data in the event.")
97        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo,
98                         "The stop signal was %s" % signal)
99
100        # Continue until we exit.
101        process.Continue()
102        self.assertEqual(process.GetState(), lldb.eStateExited)
103        self.assertEqual(process.GetExitStatus(), 0)
104
105        # launch again
106        process = self.launch(target, signal)
107
108        # Make sure we do not stop at the signal. We should still get the
109        # notification.
110        self.set_handle(signal, "false", "false", "true")
111        self.expect(
112            "process continue",
113            substrs=[
114                "stopped and restarted",
115                signal])
116        self.assertEqual(process.GetState(), lldb.eStateExited)
117        self.assertEqual(process.GetExitStatus(), 0)
118
119        # launch again
120        process = self.launch(target, signal)
121
122        # Make sure we do not stop at the signal, and we do not get the
123        # notification.
124        self.set_handle(signal, "false", "false", "false")
125        self.expect(
126            "process continue",
127            substrs=["stopped and restarted"],
128            matching=False)
129        self.assertEqual(process.GetState(), lldb.eStateExited)
130        self.assertEqual(process.GetExitStatus(), 0)
131
132        if not test_passing:
133            # reset signal handling to default
134            self.set_handle(signal, default_pass, default_stop, default_notify)
135            return
136
137        # launch again
138        process = self.launch(target, signal)
139
140        # Make sure we stop at the signal
141        self.set_handle(signal, "true", "true", "true")
142        process.Continue()
143        self.assertEqual(process.GetState(), lldb.eStateStopped)
144        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
145        self.assertTrue(
146            thread.IsValid(),
147            "Thread should be stopped due to a signal")
148        self.assertTrue(
149            thread.GetStopReasonDataCount() >= 1,
150            "There was data in the event.")
151        self.assertEqual(
152            thread.GetStopReasonDataAtIndex(0),
153            process.GetUnixSignals().GetSignalNumberFromName(signal),
154            "The stop signal was %s" %
155            signal)
156
157        # Continue until we exit. The process should receive the signal.
158        process.Continue()
159        self.assertEqual(process.GetState(), lldb.eStateExited)
160        self.assertEqual(process.GetExitStatus(), signo)
161
162        # launch again
163        process = self.launch(target, signal)
164
165        # Make sure we do not stop at the signal. We should still get the notification. Process
166        # should receive the signal.
167        self.set_handle(signal, "true", "false", "true")
168        self.expect(
169            "process continue",
170            substrs=[
171                "stopped and restarted",
172                signal])
173        self.assertEqual(process.GetState(), lldb.eStateExited)
174        self.assertEqual(process.GetExitStatus(), signo)
175
176        # launch again
177        process = self.launch(target, signal)
178
179        # Make sure we do not stop at the signal, and we do not get the notification. Process
180        # should receive the signal.
181        self.set_handle(signal, "true", "false", "false")
182        self.expect(
183            "process continue",
184            substrs=["stopped and restarted"],
185            matching=False)
186        self.assertEqual(process.GetState(), lldb.eStateExited)
187        self.assertEqual(process.GetExitStatus(), signo)
188
189        # reset signal handling to default
190        self.set_handle(signal, default_pass, default_stop, default_notify)
191