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