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