1import re
2
3import gdbremote_testcase
4from lldbsuite.test.decorators import *
5from lldbsuite.test.lldbtest import *
6from lldbsuite.test import lldbutil
7
8
9class TestSignal(gdbremote_testcase.GdbRemoteTestCaseBase):
10    def start_threads(self, num):
11        procs = self.prep_debug_monitor_and_inferior(inferior_args=[str(num)])
12        self.test_sequence.add_log_lines([
13            "read packet: $c#63",
14            {"direction": "send", "regex": "[$]T.*;reason:signal.*"},
15        ], True)
16        self.add_threadinfo_collection_packets()
17
18        context = self.expect_gdbremote_sequence()
19        self.assertIsNotNone(context)
20        threads = self.parse_threadinfo_packets(context)
21        self.assertIsNotNone(threads)
22        self.assertEqual(len(threads), num + 1)
23
24        self.reset_test_sequence()
25        return threads
26
27    SIGNAL_MATCH_RE = re.compile(r"received SIGUSR1 on thread id: ([0-9a-f]+)")
28
29    def send_and_check_signal(self, vCont_data, threads):
30        self.test_sequence.add_log_lines([
31            "read packet: $vCont;{0}#00".format(vCont_data),
32            "send packet: $W00#00",
33        ], True)
34        exp = self.expect_gdbremote_sequence()
35        self.reset_test_sequence()
36        tids = []
37        for line in exp["O_content"].decode().splitlines():
38            m = self.SIGNAL_MATCH_RE.match(line)
39            if m is not None:
40                tids.append(int(m.group(1), 16))
41        self.assertEqual(sorted(tids), sorted(threads))
42
43    def get_pid(self):
44        self.add_process_info_collection_packets()
45        context = self.expect_gdbremote_sequence()
46        self.assertIsNotNone(context)
47        procinfo = self.parse_process_info_response(context)
48        return int(procinfo['pid'], 16)
49
50    @skipIfWindows
51    @skipIfDarwin
52    @expectedFailureNetBSD
53    @expectedFailureAll(oslist=["freebsd"],
54                        bugnumber="github.com/llvm/llvm-project/issues/56086")
55    @skipIfAsan # Times out under asan
56    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
57    def test_signal_process_without_tid(self):
58        self.build()
59        self.set_inferior_startup_launch()
60
61        threads = self.start_threads(1)
62        self.send_and_check_signal(
63            "C{0:x}".format(lldbutil.get_signal_number('SIGUSR1')),
64            threads)
65
66    @skipUnlessPlatform(["netbsd"])
67    @expectedFailureNetBSD
68    @skipIfAsan # Times out under asan
69    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
70    def test_signal_one_thread(self):
71        self.build()
72        self.set_inferior_startup_launch()
73
74        threads = self.start_threads(1)
75        # try sending a signal to one of the two threads
76        self.send_and_check_signal(
77            "C{0:x}:{1:x};c".format(lldbutil.get_signal_number('SIGUSR1')),
78            threads[:1])
79
80    @skipIfWindows
81    @skipIfDarwin
82    @expectedFailureNetBSD
83    @expectedFailureAll(oslist=["freebsd"],
84                        bugnumber="github.com/llvm/llvm-project/issues/56086")
85    @skipIfAsan # Times out under asan
86    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
87    def test_signal_all_threads(self):
88        self.build()
89        self.set_inferior_startup_launch()
90
91        threads = self.start_threads(1)
92        # try sending a signal to two threads (= the process)
93        self.send_and_check_signal(
94            "C{0:x}:{1:x};C{0:x}:{2:x}".format(
95                lldbutil.get_signal_number('SIGUSR1'),
96                *threads),
97            threads)
98
99    @skipIfWindows
100    @expectedFailureNetBSD
101    @expectedFailureAll(oslist=["freebsd"],
102                        bugnumber="github.com/llvm/llvm-project/issues/56086")
103    @add_test_categories(["llgs"])
104    @skipIfAsan # Times out under asan
105    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
106    def test_signal_process_by_pid(self):
107        self.build()
108        self.set_inferior_startup_launch()
109
110        threads = self.start_threads(1)
111        self.send_and_check_signal(
112            "C{0:x}:p{1:x}".format(
113                lldbutil.get_signal_number('SIGUSR1'),
114                self.get_pid()),
115            threads)
116
117    @skipIfWindows
118    @expectedFailureNetBSD
119    @expectedFailureAll(oslist=["freebsd"],
120                        bugnumber="github.com/llvm/llvm-project/issues/56086")
121    @add_test_categories(["llgs"])
122    @skipIfAsan # Times out under asan
123    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
124    def test_signal_process_minus_one(self):
125        self.build()
126        self.set_inferior_startup_launch()
127
128        threads = self.start_threads(1)
129        self.send_and_check_signal(
130            "C{0:x}:p-1".format(
131                lldbutil.get_signal_number('SIGUSR1')),
132            threads)
133
134    @skipIfWindows
135    @expectedFailureNetBSD
136    @expectedFailureAll(oslist=["freebsd"],
137                        bugnumber="github.com/llvm/llvm-project/issues/56086")
138    @add_test_categories(["llgs"])
139    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
140    def test_signal_minus_one(self):
141        self.build()
142        self.set_inferior_startup_launch()
143
144        threads = self.start_threads(1)
145        self.send_and_check_signal(
146            "C{0:x}:-1".format(lldbutil.get_signal_number('SIGUSR1')),
147            threads)
148
149    @skipIfWindows
150    @expectedFailureNetBSD
151    @expectedFailureAll(oslist=["freebsd"],
152                        bugnumber="github.com/llvm/llvm-project/issues/56086")
153    @add_test_categories(["llgs"])
154    @skipIfAsan # Times out under asan
155    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
156    def test_signal_all_threads_by_pid(self):
157        self.build()
158        self.set_inferior_startup_launch()
159
160        threads = self.start_threads(1)
161        # try sending a signal to two threads (= the process)
162        self.send_and_check_signal(
163            "C{0:x}:p{1:x}.{2:x};C{0:x}:p{1:x}.{3:x}".format(
164                lldbutil.get_signal_number('SIGUSR1'),
165                self.get_pid(),
166                *threads),
167            threads)
168
169    @skipIfWindows
170    @expectedFailureNetBSD
171    @expectedFailureAll(oslist=["freebsd"],
172                        bugnumber="github.com/llvm/llvm-project/issues/56086")
173    @add_test_categories(["llgs"])
174    @skipIfAsan # Times out under asan
175    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
176    def test_signal_minus_one_by_pid(self):
177        self.build()
178        self.set_inferior_startup_launch()
179
180        threads = self.start_threads(1)
181        self.send_and_check_signal(
182            "C{0:x}:p{1:x}.-1".format(
183                lldbutil.get_signal_number('SIGUSR1'),
184                self.get_pid()),
185            threads)
186
187    @skipIfWindows
188    @expectedFailureNetBSD
189    @expectedFailureAll(oslist=["freebsd"],
190                        bugnumber="github.com/llvm/llvm-project/issues/56086")
191    @add_test_categories(["llgs"])
192    @skipIfAsan # Times out under asan
193    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
194    def test_signal_minus_one_by_minus_one(self):
195        self.build()
196        self.set_inferior_startup_launch()
197
198        threads = self.start_threads(1)
199        self.send_and_check_signal(
200            "C{0:x}:p-1.-1".format(
201                lldbutil.get_signal_number('SIGUSR1')),
202            threads)
203
204    @skipUnlessPlatform(["netbsd"])
205    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
206    def test_signal_two_of_three_threads(self):
207        self.build()
208        self.set_inferior_startup_launch()
209
210        threads = self.start_threads(2)
211        # try sending a signal to 2 out of 3 threads
212        self.test_sequence.add_log_lines([
213            "read packet: $vCont;C{0:x}:{1:x};C{0:x}:{2:x};c#00".format(
214                lldbutil.get_signal_number('SIGUSR1'),
215                threads[1], threads[2]),
216            {"direction": "send", "regex": r"^\$E1e#db$"},
217        ], True)
218
219        context = self.expect_gdbremote_sequence()
220        self.assertIsNotNone(context)
221
222    @skipUnlessPlatform(["netbsd"])
223    @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) # Randomly fails on buildbot
224    def test_signal_two_signals(self):
225        self.build()
226        self.set_inferior_startup_launch()
227
228        threads = self.start_threads(1)
229        # try sending two different signals to two threads
230        self.test_sequence.add_log_lines([
231            "read packet: $vCont;C{0:x}:{1:x};C{2:x}:{3:x}#00".format(
232                lldbutil.get_signal_number('SIGUSR1'), threads[0],
233                lldbutil.get_signal_number('SIGUSR2'), threads[1]),
234            {"direction": "send", "regex": r"^\$E1e#db$"},
235        ], True)
236
237        context = self.expect_gdbremote_sequence()
238        self.assertIsNotNone(context)
239