266 lines · python
1import gdbremote_testcase2 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_base17 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 fork27 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=nonstop66 )67 68 # detach the forked child69 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 correct74 "read packet: $qC#00",75 "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid),76 # verify that the correct processes are detached/available77 "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_tid87 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=nonstop91 )92 93 # switch to the forked child94 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 parent101 "read packet: $D;{}#00".format(parent_pid),102 "send packet: $OK#00",103 # verify that the correct processes are detached/available104 "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 child109 "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=nonstop136 )137 138 self.test_sequence.add_log_lines(139 [140 # double-check our PIDs141 "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 processes146 "read packet: $D#00",147 "send packet: $OK#00",148 # verify that both PIDs are invalid now149 "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_child160 parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test(161 ["fork"], nonstop=nonstop162 )163 164 if kill_parent:165 self.test_sequence.add_log_lines(166 [167 # kill the process168 "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 process177 "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/TID185 "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),186 "send packet: ${}#00".format("Eff" if kill_child else "OK"),187 # check parent PID/TID188 "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=nonstop198 )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 process223 "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 process231 "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 PIDs255 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