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