1import gdbremote_testcase 2 3 4class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase): 5 fork_regex = ( 6 "[$]T[0-9a-fA-F]{{2}}thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" 7 "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" 8 ) 9 fork_regex_nonstop = ( 10 "%Stop:T[0-9a-fA-F]{{2}}" 11 "thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" 12 "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" 13 ) 14 fork_capture = {1: "parent_pid", 2: "parent_tid", 3: "child_pid", 4: "child_tid"} 15 stop_regex_base = "T[0-9a-fA-F]{{2}}thread:p{}.{};.*reason:signal.*" 16 stop_regex = "^[$]" + stop_regex_base 17 18 def start_fork_test(self, args, variant="fork", nonstop=False): 19 self.build() 20 self.prep_debug_monitor_and_inferior(inferior_args=args) 21 self.add_qSupported_packets(["multiprocess+", "{}-events+".format(variant)]) 22 ret = self.expect_gdbremote_sequence() 23 self.assertIn("{}-events+".format(variant), ret["qSupported_response"]) 24 self.reset_test_sequence() 25 26 # continue and expect fork 27 if nonstop: 28 self.test_sequence.add_log_lines( 29 [ 30 "read packet: $QNonStop:1#00", 31 "send packet: $OK#00", 32 "read packet: $c#00", 33 "send packet: $OK#00", 34 { 35 "direction": "send", 36 "regex": self.fork_regex_nonstop.format(variant), 37 "capture": self.fork_capture, 38 }, 39 "read packet: $vStopped#00", 40 "send packet: $OK#00", 41 ], 42 True, 43 ) 44 else: 45 self.test_sequence.add_log_lines( 46 [ 47 "read packet: $c#00", 48 { 49 "direction": "send", 50 "regex": self.fork_regex.format(variant), 51 "capture": self.fork_capture, 52 }, 53 ], 54 True, 55 ) 56 ret = self.expect_gdbremote_sequence() 57 self.reset_test_sequence() 58 59 return tuple( 60 ret[x] for x in ("parent_pid", "parent_tid", "child_pid", "child_tid") 61 ) 62 63 def fork_and_detach_test(self, variant, nonstop=False): 64 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( 65 [variant], variant, nonstop=nonstop 66 ) 67 68 # detach the forked child 69 self.test_sequence.add_log_lines( 70 [ 71 "read packet: $D;{}#00".format(child_pid), 72 "send packet: $OK#00", 73 # verify that the current process is correct 74 "read packet: $qC#00", 75 "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid), 76 # verify that the correct processes are detached/available 77 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 78 "send packet: $Eff#00", 79 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 80 "send packet: $OK#00", 81 ], 82 True, 83 ) 84 self.expect_gdbremote_sequence() 85 self.reset_test_sequence() 86 return parent_pid, parent_tid 87 88 def fork_and_follow_test(self, variant, nonstop=False): 89 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( 90 [variant], variant, nonstop=nonstop 91 ) 92 93 # switch to the forked child 94 self.test_sequence.add_log_lines( 95 [ 96 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 97 "send packet: $OK#00", 98 "read packet: $Hcp{}.{}#00".format(child_pid, child_tid), 99 "send packet: $OK#00", 100 # detach the parent 101 "read packet: $D;{}#00".format(parent_pid), 102 "send packet: $OK#00", 103 # verify that the correct processes are detached/available 104 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 105 "send packet: $Eff#00", 106 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 107 "send packet: $OK#00", 108 # then resume the child 109 "read packet: $c#00", 110 ], 111 True, 112 ) 113 114 if nonstop: 115 self.test_sequence.add_log_lines( 116 [ 117 "send packet: $OK#00", 118 "send packet: %Stop:W00;process:{}#00".format(child_pid), 119 "read packet: $vStopped#00", 120 "send packet: $OK#00", 121 ], 122 True, 123 ) 124 else: 125 self.test_sequence.add_log_lines( 126 [ 127 "send packet: $W00;process:{}#00".format(child_pid), 128 ], 129 True, 130 ) 131 self.expect_gdbremote_sequence() 132 133 def detach_all_test(self, nonstop=False): 134 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( 135 ["fork"], nonstop=nonstop 136 ) 137 138 self.test_sequence.add_log_lines( 139 [ 140 # double-check our PIDs 141 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 142 "send packet: $OK#00", 143 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 144 "send packet: $OK#00", 145 # detach all processes 146 "read packet: $D#00", 147 "send packet: $OK#00", 148 # verify that both PIDs are invalid now 149 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 150 "send packet: $Eff#00", 151 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 152 "send packet: $Eff#00", 153 ], 154 True, 155 ) 156 self.expect_gdbremote_sequence() 157 158 def vkill_test(self, kill_parent=False, kill_child=False, nonstop=False): 159 assert kill_parent or kill_child 160 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( 161 ["fork"], nonstop=nonstop 162 ) 163 164 if kill_parent: 165 self.test_sequence.add_log_lines( 166 [ 167 # kill the process 168 "read packet: $vKill;{}#00".format(parent_pid), 169 "send packet: $OK#00", 170 ], 171 True, 172 ) 173 if kill_child: 174 self.test_sequence.add_log_lines( 175 [ 176 # kill the process 177 "read packet: $vKill;{}#00".format(child_pid), 178 "send packet: $OK#00", 179 ], 180 True, 181 ) 182 self.test_sequence.add_log_lines( 183 [ 184 # check child PID/TID 185 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 186 "send packet: ${}#00".format("Eff" if kill_child else "OK"), 187 # check parent PID/TID 188 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 189 "send packet: ${}#00".format("Eff" if kill_parent else "OK"), 190 ], 191 True, 192 ) 193 self.expect_gdbremote_sequence() 194 195 def resume_one_test(self, run_order, use_vCont=False, nonstop=False): 196 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( 197 ["fork", "stop"], nonstop=nonstop 198 ) 199 200 parent_expect = [ 201 self.stop_regex_base.format(parent_pid, parent_tid), 202 "W00;process:{}#.*".format(parent_pid), 203 ] 204 child_expect = [ 205 self.stop_regex_base.format(child_pid, child_tid), 206 "W00;process:{}#.*".format(child_pid), 207 ] 208 209 for x in run_order: 210 if x == "parent": 211 pidtid = (parent_pid, parent_tid) 212 expect = parent_expect.pop(0) 213 elif x == "child": 214 pidtid = (child_pid, child_tid) 215 expect = child_expect.pop(0) 216 else: 217 assert False, "unexpected x={}".format(x) 218 219 if use_vCont: 220 self.test_sequence.add_log_lines( 221 [ 222 # continue the selected process 223 "read packet: $vCont;c:p{}.{}#00".format(*pidtid), 224 ], 225 True, 226 ) 227 else: 228 self.test_sequence.add_log_lines( 229 [ 230 # continue the selected process 231 "read packet: $Hcp{}.{}#00".format(*pidtid), 232 "send packet: $OK#00", 233 "read packet: $c#00", 234 ], 235 True, 236 ) 237 if nonstop: 238 self.test_sequence.add_log_lines( 239 [ 240 "send packet: $OK#00", 241 {"direction": "send", "regex": "%Stop:" + expect}, 242 "read packet: $vStopped#00", 243 "send packet: $OK#00", 244 ], 245 True, 246 ) 247 else: 248 self.test_sequence.add_log_lines( 249 [ 250 {"direction": "send", "regex": "[$]" + expect}, 251 ], 252 True, 253 ) 254 # if at least one process remained, check both PIDs 255 if parent_expect or child_expect: 256 self.test_sequence.add_log_lines( 257 [ 258 "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), 259 "send packet: ${}#00".format("OK" if parent_expect else "Eff"), 260 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), 261 "send packet: ${}#00".format("OK" if child_expect else "Eff"), 262 ], 263 True, 264 ) 265 self.expect_gdbremote_sequence() 266