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