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