xref: /openbsd-src/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1import gdbremote_testcase
2
3
4class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase):
5    fork_regex = ("[$]T[0-9a-fA-F]{{2}}thread:p([0-9a-f]+)[.]([0-9a-f]+);.*"
6                  "{}:p([0-9a-f]+)[.]([0-9a-f]+).*")
7    fork_regex_nonstop = ("%Stop:T[0-9a-fA-F]{{2}}"
8                          "thread:p([0-9a-f]+)[.]([0-9a-f]+);.*"
9                          "{}:p([0-9a-f]+)[.]([0-9a-f]+).*")
10    fork_capture = {1: "parent_pid", 2: "parent_tid",
11                    3: "child_pid", 4: "child_tid"}
12    stop_regex_base = "T[0-9a-fA-F]{{2}}thread:p{}.{};.*reason:signal.*"
13    stop_regex = "^[$]" + stop_regex_base
14
15    def start_fork_test(self, args, variant="fork", nonstop=False):
16        self.build()
17        self.prep_debug_monitor_and_inferior(inferior_args=args)
18        self.add_qSupported_packets(["multiprocess+",
19                                     "{}-events+".format(variant)])
20        ret = self.expect_gdbremote_sequence()
21        self.assertIn("{}-events+".format(variant), ret["qSupported_response"])
22        self.reset_test_sequence()
23
24        # continue and expect fork
25        if nonstop:
26            self.test_sequence.add_log_lines([
27                "read packet: $QNonStop:1#00",
28                "send packet: $OK#00",
29                "read packet: $c#00",
30                "send packet: $OK#00",
31                {"direction": "send",
32                 "regex": self.fork_regex_nonstop.format(variant),
33                 "capture": self.fork_capture},
34                "read packet: $vStopped#00",
35                "send packet: $OK#00",
36            ], True)
37        else:
38            self.test_sequence.add_log_lines([
39                "read packet: $c#00",
40                {"direction": "send", "regex": self.fork_regex.format(variant),
41                 "capture": self.fork_capture},
42            ], True)
43        ret = self.expect_gdbremote_sequence()
44        self.reset_test_sequence()
45
46        return tuple(ret[x] for x in ("parent_pid", "parent_tid",
47                                      "child_pid", "child_tid"))
48
49    def fork_and_detach_test(self, variant, nonstop=False):
50        parent_pid, parent_tid, child_pid, child_tid = (
51            self.start_fork_test([variant], variant, nonstop=nonstop))
52
53        # detach the forked child
54        self.test_sequence.add_log_lines([
55            "read packet: $D;{}#00".format(child_pid),
56            "send packet: $OK#00",
57            # verify that the current process is correct
58            "read packet: $qC#00",
59            "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid),
60            # verify that the correct processes are detached/available
61            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
62            "send packet: $Eff#00",
63            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
64            "send packet: $OK#00",
65        ], True)
66        self.expect_gdbremote_sequence()
67        self.reset_test_sequence()
68        return parent_pid, parent_tid
69
70    def fork_and_follow_test(self, variant, nonstop=False):
71        parent_pid, parent_tid, child_pid, child_tid = (
72            self.start_fork_test([variant], variant, nonstop=nonstop))
73
74        # switch to the forked child
75        self.test_sequence.add_log_lines([
76            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
77            "send packet: $OK#00",
78            "read packet: $Hcp{}.{}#00".format(child_pid, child_tid),
79            "send packet: $OK#00",
80            # detach the parent
81            "read packet: $D;{}#00".format(parent_pid),
82            "send packet: $OK#00",
83            # verify that the correct processes are detached/available
84            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
85            "send packet: $Eff#00",
86            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
87            "send packet: $OK#00",
88            # then resume the child
89            "read packet: $c#00",
90        ], True)
91
92        if nonstop:
93            self.test_sequence.add_log_lines([
94                "send packet: $OK#00",
95                "send packet: %Stop:W00;process:{}#00".format(child_pid),
96                "read packet: $vStopped#00",
97                "send packet: $OK#00",
98            ], True)
99        else:
100            self.test_sequence.add_log_lines([
101                "send packet: $W00;process:{}#00".format(child_pid),
102            ], True)
103        self.expect_gdbremote_sequence()
104
105    def detach_all_test(self, nonstop=False):
106        parent_pid, parent_tid, child_pid, child_tid = (
107            self.start_fork_test(["fork"], nonstop=nonstop))
108
109        self.test_sequence.add_log_lines([
110            # double-check our PIDs
111            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
112            "send packet: $OK#00",
113            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
114            "send packet: $OK#00",
115            # detach all processes
116            "read packet: $D#00",
117            "send packet: $OK#00",
118            # verify that both PIDs are invalid now
119            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
120            "send packet: $Eff#00",
121            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
122            "send packet: $Eff#00",
123        ], True)
124        self.expect_gdbremote_sequence()
125
126    def vkill_test(self, kill_parent=False, kill_child=False, nonstop=False):
127        assert kill_parent or kill_child
128        parent_pid, parent_tid, child_pid, child_tid = (
129            self.start_fork_test(["fork"], nonstop=nonstop))
130
131        if kill_parent:
132            self.test_sequence.add_log_lines([
133                # kill the process
134                "read packet: $vKill;{}#00".format(parent_pid),
135                "send packet: $OK#00",
136            ], True)
137        if kill_child:
138            self.test_sequence.add_log_lines([
139                # kill the process
140                "read packet: $vKill;{}#00".format(child_pid),
141                "send packet: $OK#00",
142            ], True)
143        self.test_sequence.add_log_lines([
144            # check child PID/TID
145            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
146            "send packet: ${}#00".format("Eff" if kill_child else "OK"),
147            # check parent PID/TID
148            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
149            "send packet: ${}#00".format("Eff" if kill_parent else "OK"),
150        ], True)
151        self.expect_gdbremote_sequence()
152
153    def resume_one_test(self, run_order, use_vCont=False, nonstop=False):
154        parent_pid, parent_tid, child_pid, child_tid = (
155            self.start_fork_test(["fork", "stop"], nonstop=nonstop))
156
157        parent_expect = [
158            self.stop_regex_base.format(parent_pid, parent_tid),
159            "W00;process:{}#.*".format(parent_pid),
160        ]
161        child_expect = [
162            self.stop_regex_base.format(child_pid, child_tid),
163            "W00;process:{}#.*".format(child_pid),
164        ]
165
166        for x in run_order:
167            if x == "parent":
168                pidtid = (parent_pid, parent_tid)
169                expect = parent_expect.pop(0)
170            elif x == "child":
171                pidtid = (child_pid, child_tid)
172                expect = child_expect.pop(0)
173            else:
174                assert False, "unexpected x={}".format(x)
175
176            if use_vCont:
177                self.test_sequence.add_log_lines([
178                    # continue the selected process
179                    "read packet: $vCont;c:p{}.{}#00".format(*pidtid),
180                ], True)
181            else:
182                self.test_sequence.add_log_lines([
183                    # continue the selected process
184                    "read packet: $Hcp{}.{}#00".format(*pidtid),
185                    "send packet: $OK#00",
186                    "read packet: $c#00",
187                ], True)
188            if nonstop:
189                self.test_sequence.add_log_lines([
190                    "send packet: $OK#00",
191                    {"direction": "send", "regex": "%Stop:" + expect},
192                    "read packet: $vStopped#00",
193                    "send packet: $OK#00",
194                ], True)
195            else:
196                self.test_sequence.add_log_lines([
197                    {"direction": "send", "regex": "[$]" + expect},
198                ], True)
199            # if at least one process remained, check both PIDs
200            if parent_expect or child_expect:
201                self.test_sequence.add_log_lines([
202                    "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
203                    "send packet: ${}#00".format("OK" if parent_expect else "Eff"),
204                    "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
205                    "send packet: ${}#00".format("OK" if child_expect else "Eff"),
206                ], True)
207        self.expect_gdbremote_sequence()
208