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