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#.*"},
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#.*"},
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        procinfo_regex = "[$]pid:([0-9a-f]+);.*"
105        fork_regex = "[$]T.*;{}:p([0-9a-f]+)[.]([0-9a-f]+).*".format(variant)
106        self.test_sequence.add_log_lines([
107            "read packet: $qProcessInfo#00",
108            {"direction": "send", "regex": procinfo_regex,
109             "capture": {1: "parent_pid"}},
110            "read packet: $c#00",
111            {"direction": "send", "regex": fork_regex,
112             "capture": {1: "pid", 2: "tid"}},
113        ], True)
114        ret = self.expect_gdbremote_sequence()
115        parent_pid, pid, tid = (int(ret[x], 16) for x
116                                in ("parent_pid", "pid", "tid"))
117        self.reset_test_sequence()
118
119        # switch to the forked child
120        self.test_sequence.add_log_lines([
121            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid),
122            {"direction": "send", "regex": r"[$]OK#.*"},
123            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid),
124            {"direction": "send", "regex": r"[$]OK#.*"},
125        ], True)
126
127        # detach the parent
128        self.test_sequence.add_log_lines([
129            "read packet: $D;{:x}#00".format(parent_pid),
130            {"direction": "send", "regex": r"[$]OK#.*"},
131        ], True)
132        ret = self.expect_gdbremote_sequence()
133        self.reset_test_sequence()
134
135        # resume the child
136        self.test_sequence.add_log_lines([
137            "read packet: $c#00",
138            {"direction": "send", "regex": r"[$]W00#.*"},
139        ], True)
140        self.expect_gdbremote_sequence()
141
142    @add_test_categories(["fork"])
143    def test_fork_follow(self):
144        self.fork_and_follow_test("fork")
145
146    @add_test_categories(["fork"])
147    def test_vfork_follow(self):
148        self.fork_and_follow_test("vfork")
149
150    @add_test_categories(["fork"])
151    def test_select_wrong_pid(self):
152        self.build()
153        self.prep_debug_monitor_and_inferior()
154        self.add_qSupported_packets(["multiprocess+"])
155        ret = self.expect_gdbremote_sequence()
156        self.assertIn("multiprocess+", ret["qSupported_response"])
157        self.reset_test_sequence()
158
159        # get process pid
160        procinfo_regex = "[$]pid:([0-9a-f]+);.*"
161        self.test_sequence.add_log_lines([
162            "read packet: $qProcessInfo#00",
163            {"direction": "send", "regex": procinfo_regex,
164             "capture": {1: "pid"}},
165            "read packet: $qC#00",
166            {"direction": "send", "regex": "[$]QC([0-9a-f]+)#.*",
167             "capture": {1: "tid"}},
168        ], True)
169        ret = self.expect_gdbremote_sequence()
170        pid, tid = (int(ret[x], 16) for x in ("pid", "tid"))
171        self.reset_test_sequence()
172
173        # try switching to correct pid
174        self.test_sequence.add_log_lines([
175            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid),
176            {"direction": "send", "regex": r"[$]OK#.*"},
177            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid),
178            {"direction": "send", "regex": r"[$]OK#.*"},
179        ], True)
180        ret = self.expect_gdbremote_sequence()
181
182        # try switching to invalid tid
183        self.test_sequence.add_log_lines([
184            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid+1),
185            {"direction": "send", "regex": r"[$]E15#.*"},
186            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid+1),
187            {"direction": "send", "regex": r"[$]E15#.*"},
188        ], True)
189        ret = self.expect_gdbremote_sequence()
190
191        # try switching to invalid pid
192        self.test_sequence.add_log_lines([
193            "read packet: $Hgp{:x}.{:x}#00".format(pid+1, tid),
194            {"direction": "send", "regex": r"[$]Eff#.*"},
195            "read packet: $Hcp{:x}.{:x}#00".format(pid+1, tid),
196            {"direction": "send", "regex": r"[$]Eff#.*"},
197        ], True)
198        ret = self.expect_gdbremote_sequence()
199
200    @add_test_categories(["fork"])
201    def test_detach_current(self):
202        self.build()
203        self.prep_debug_monitor_and_inferior()
204        self.add_qSupported_packets(["multiprocess+"])
205        ret = self.expect_gdbremote_sequence()
206        self.assertIn("multiprocess+", ret["qSupported_response"])
207        self.reset_test_sequence()
208
209        # get process pid
210        procinfo_regex = "[$]pid:([0-9a-f]+);.*"
211        self.test_sequence.add_log_lines([
212            "read packet: $qProcessInfo#00",
213            {"direction": "send", "regex": procinfo_regex,
214             "capture": {1: "pid"}},
215        ], True)
216        ret = self.expect_gdbremote_sequence()
217        pid = int(ret["pid"], 16)
218        self.reset_test_sequence()
219
220        # detach the process
221        self.test_sequence.add_log_lines([
222            "read packet: $D;{:x}#00".format(pid),
223            {"direction": "send", "regex": r"[$]OK#.*"},
224            "read packet: $qC#00",
225            {"direction": "send", "regex": r"[$]E44#.*"},
226        ], True)
227        ret = self.expect_gdbremote_sequence()
228