1import gdbremote_testcase
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6class TestGdbRemoteFork(gdbremote_testcase.GdbRemoteTestCaseBase):
7
8    @add_test_categories(["fork"])
9    def test_fork_multithreaded(self):
10        self.build()
11        self.prep_debug_monitor_and_inferior(inferior_args=["thread:new"]*2 + ["fork"])
12        self.add_qSupported_packets(["multiprocess+", "fork-events+"])
13        ret = self.expect_gdbremote_sequence()
14        self.assertIn("fork-events+", ret["qSupported_response"])
15        self.reset_test_sequence()
16
17        # continue and expect fork
18        fork_regex = "[$]T.*;fork:p([0-9a-f]+)[.]([0-9a-f]+).*"
19        self.test_sequence.add_log_lines([
20            "read packet: $c#00",
21            {"direction": "send", "regex": fork_regex,
22             "capture": {1: "pid", 2: "tid"}},
23        ], True)
24        ret = self.expect_gdbremote_sequence()
25        pid = int(ret["pid"], 16)
26        self.reset_test_sequence()
27
28        # detach the forked child
29        self.test_sequence.add_log_lines([
30            "read packet: $D;{:x}#00".format(pid),
31            {"direction": "send", "regex": r"[$]OK#.*"},
32        ], True)
33        ret = self.expect_gdbremote_sequence()
34        self.reset_test_sequence()
35
36        # resume the parent
37        self.test_sequence.add_log_lines([
38            "read packet: $k#00",
39        ], True)
40        self.expect_gdbremote_sequence()
41
42    def fork_and_detach_test(self, variant):
43        self.build()
44        self.prep_debug_monitor_and_inferior(inferior_args=[variant])
45        self.add_qSupported_packets(["multiprocess+",
46                                     "{}-events+".format(variant)])
47        ret = self.expect_gdbremote_sequence()
48        self.assertIn("{}-events+".format(variant), ret["qSupported_response"])
49        self.reset_test_sequence()
50
51        # continue and expect fork
52        fork_regex = "[$]T.*;{}:p([0-9a-f]+)[.]([0-9a-f]+).*".format(variant)
53        self.test_sequence.add_log_lines([
54            "read packet: $c#00",
55            {"direction": "send", "regex": fork_regex,
56             "capture": {1: "pid", 2: "tid"}},
57        ], True)
58        ret = self.expect_gdbremote_sequence()
59        pid = int(ret["pid"], 16)
60        self.reset_test_sequence()
61
62        # detach the forked child
63        self.test_sequence.add_log_lines([
64            "read packet: $D;{:x}#00".format(pid),
65            {"direction": "send", "regex": r"[$]OK#.*"},
66        ], True)
67        ret = self.expect_gdbremote_sequence()
68        self.reset_test_sequence()
69
70    @add_test_categories(["fork"])
71    def test_fork(self):
72        self.fork_and_detach_test("fork")
73
74        # resume the parent
75        self.test_sequence.add_log_lines([
76            "read packet: $c#00",
77            {"direction": "send", "regex": r"[$]W00;process:[0-9a-f]+#.*"},
78        ], True)
79        self.expect_gdbremote_sequence()
80
81    @add_test_categories(["fork"])
82    def test_vfork(self):
83        self.fork_and_detach_test("vfork")
84
85        # resume the parent
86        self.test_sequence.add_log_lines([
87            "read packet: $c#00",
88            {"direction": "send", "regex": r"[$]T.*vforkdone.*"},
89            "read packet: $c#00",
90            {"direction": "send", "regex": r"[$]W00;process:[0-9a-f]+#.*"},
91        ], True)
92        self.expect_gdbremote_sequence()
93
94    def fork_and_follow_test(self, variant):
95        self.build()
96        self.prep_debug_monitor_and_inferior(inferior_args=[variant])
97        self.add_qSupported_packets(["multiprocess+",
98                                     "{}-events+".format(variant)])
99        ret = self.expect_gdbremote_sequence()
100        self.assertIn("{}-events+".format(variant), ret["qSupported_response"])
101        self.reset_test_sequence()
102
103        # continue and expect fork
104        fork_regex = ("[$]T[0-9a-f]{{2}}thread:p([0-9a-f]+)[.][0-9a-f]+;.*"
105                      "{}:p([0-9a-f]+)[.]([0-9a-f]+).*".format(variant))
106        self.test_sequence.add_log_lines([
107            "read packet: $c#00",
108            {"direction": "send", "regex": fork_regex,
109             "capture": {1: "parent_pid", 2: "pid", 3: "tid"}},
110        ], True)
111        ret = self.expect_gdbremote_sequence()
112        parent_pid, pid, tid = (int(ret[x], 16) for x
113                                in ("parent_pid", "pid", "tid"))
114        self.reset_test_sequence()
115
116        # switch to the forked child
117        self.test_sequence.add_log_lines([
118            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid),
119            {"direction": "send", "regex": r"[$]OK#.*"},
120            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid),
121            {"direction": "send", "regex": r"[$]OK#.*"},
122        ], True)
123
124        # detach the parent
125        self.test_sequence.add_log_lines([
126            "read packet: $D;{:x}#00".format(parent_pid),
127            {"direction": "send", "regex": r"[$]OK#.*"},
128        ], True)
129        ret = self.expect_gdbremote_sequence()
130        self.reset_test_sequence()
131
132        # resume the child
133        self.test_sequence.add_log_lines([
134            "read packet: $c#00",
135            {"direction": "send", "regex": r"[$]W00;process:[0-9a-f]+#.*"},
136        ], True)
137        self.expect_gdbremote_sequence()
138
139    @add_test_categories(["fork"])
140    def test_fork_follow(self):
141        self.fork_and_follow_test("fork")
142
143    @add_test_categories(["fork"])
144    def test_vfork_follow(self):
145        self.fork_and_follow_test("vfork")
146
147    @add_test_categories(["fork"])
148    def test_select_wrong_pid(self):
149        self.build()
150        self.prep_debug_monitor_and_inferior()
151        self.add_qSupported_packets(["multiprocess+"])
152        ret = self.expect_gdbremote_sequence()
153        self.assertIn("multiprocess+", ret["qSupported_response"])
154        self.reset_test_sequence()
155
156        # get process pid
157        procinfo_regex = "[$]pid:([0-9a-f]+);.*"
158        self.test_sequence.add_log_lines([
159            "read packet: $qProcessInfo#00",
160            {"direction": "send", "regex": procinfo_regex,
161             "capture": {1: "pid"}},
162            "read packet: $qC#00",
163            {"direction": "send", "regex": "[$]QC([0-9a-f]+)#.*",
164             "capture": {1: "tid"}},
165        ], True)
166        ret = self.expect_gdbremote_sequence()
167        pid, tid = (int(ret[x], 16) for x in ("pid", "tid"))
168        self.reset_test_sequence()
169
170        # try switching to correct pid
171        self.test_sequence.add_log_lines([
172            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid),
173            {"direction": "send", "regex": r"[$]OK#.*"},
174            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid),
175            {"direction": "send", "regex": r"[$]OK#.*"},
176        ], True)
177        ret = self.expect_gdbremote_sequence()
178
179        # try switching to invalid tid
180        self.test_sequence.add_log_lines([
181            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid+1),
182            {"direction": "send", "regex": r"[$]E15#.*"},
183            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid+1),
184            {"direction": "send", "regex": r"[$]E15#.*"},
185        ], True)
186        ret = self.expect_gdbremote_sequence()
187
188        # try switching to invalid pid
189        self.test_sequence.add_log_lines([
190            "read packet: $Hgp{:x}.{:x}#00".format(pid+1, tid),
191            {"direction": "send", "regex": r"[$]Eff#.*"},
192            "read packet: $Hcp{:x}.{:x}#00".format(pid+1, tid),
193            {"direction": "send", "regex": r"[$]Eff#.*"},
194        ], True)
195        ret = self.expect_gdbremote_sequence()
196
197    @add_test_categories(["fork"])
198    def test_detach_current(self):
199        self.build()
200        self.prep_debug_monitor_and_inferior()
201        self.add_qSupported_packets(["multiprocess+"])
202        ret = self.expect_gdbremote_sequence()
203        self.assertIn("multiprocess+", ret["qSupported_response"])
204        self.reset_test_sequence()
205
206        # get process pid
207        procinfo_regex = "[$]pid:([0-9a-f]+);.*"
208        self.test_sequence.add_log_lines([
209            "read packet: $qProcessInfo#00",
210            {"direction": "send", "regex": procinfo_regex,
211             "capture": {1: "pid"}},
212        ], True)
213        ret = self.expect_gdbremote_sequence()
214        pid = int(ret["pid"], 16)
215        self.reset_test_sequence()
216
217        # detach the process
218        self.test_sequence.add_log_lines([
219            "read packet: $D;{:x}#00".format(pid),
220            {"direction": "send", "regex": r"[$]OK#.*"},
221            "read packet: $qC#00",
222            {"direction": "send", "regex": r"[$]E44#.*"},
223        ], True)
224        ret = self.expect_gdbremote_sequence()
225