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