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