| import gdbremote_testcase |
| |
| |
| class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase): |
| fork_regex = ( |
| "[$]T[0-9a-fA-F]{{2}}thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" |
| "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" |
| ) |
| fork_regex_nonstop = ( |
| "%Stop:T[0-9a-fA-F]{{2}}" |
| "thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" |
| "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" |
| ) |
| fork_capture = {1: "parent_pid", 2: "parent_tid", 3: "child_pid", 4: "child_tid"} |
| stop_regex_base = "T[0-9a-fA-F]{{2}}thread:p{}.{};.*reason:signal.*" |
| stop_regex = "^[$]" + stop_regex_base |
| |
| def start_fork_test(self, args, variant="fork", nonstop=False): |
| self.build() |
| self.prep_debug_monitor_and_inferior(inferior_args=args) |
| self.add_qSupported_packets(["multiprocess+", "{}-events+".format(variant)]) |
| ret = self.expect_gdbremote_sequence() |
| self.assertIn("{}-events+".format(variant), ret["qSupported_response"]) |
| self.reset_test_sequence() |
| |
| # continue and expect fork |
| if nonstop: |
| self.test_sequence.add_log_lines( |
| [ |
| "read packet: $QNonStop:1#00", |
| "send packet: $OK#00", |
| "read packet: $c#00", |
| "send packet: $OK#00", |
| { |
| "direction": "send", |
| "regex": self.fork_regex_nonstop.format(variant), |
| "capture": self.fork_capture, |
| }, |
| "read packet: $vStopped#00", |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| else: |
| self.test_sequence.add_log_lines( |
| [ |
| "read packet: $c#00", |
| { |
| "direction": "send", |
| "regex": self.fork_regex.format(variant), |
| "capture": self.fork_capture, |
| }, |
| ], |
| True, |
| ) |
| ret = self.expect_gdbremote_sequence() |
| self.reset_test_sequence() |
| |
| return tuple( |
| ret[x] for x in ("parent_pid", "parent_tid", "child_pid", "child_tid") |
| ) |
| |
| def fork_and_detach_test(self, variant, nonstop=False): |
| parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( |
| [variant], variant, nonstop=nonstop |
| ) |
| |
| # detach the forked child |
| self.test_sequence.add_log_lines( |
| [ |
| "read packet: $D;{}#00".format(child_pid), |
| "send packet: $OK#00", |
| # verify that the current process is correct |
| "read packet: $qC#00", |
| "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid), |
| # verify that the correct processes are detached/available |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $Eff#00", |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| self.expect_gdbremote_sequence() |
| self.reset_test_sequence() |
| return parent_pid, parent_tid |
| |
| def fork_and_follow_test(self, variant, nonstop=False): |
| parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( |
| [variant], variant, nonstop=nonstop |
| ) |
| |
| # switch to the forked child |
| self.test_sequence.add_log_lines( |
| [ |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $OK#00", |
| "read packet: $Hcp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $OK#00", |
| # detach the parent |
| "read packet: $D;{}#00".format(parent_pid), |
| "send packet: $OK#00", |
| # verify that the correct processes are detached/available |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: $Eff#00", |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $OK#00", |
| # then resume the child |
| "read packet: $c#00", |
| ], |
| True, |
| ) |
| |
| if nonstop: |
| self.test_sequence.add_log_lines( |
| [ |
| "send packet: $OK#00", |
| "send packet: %Stop:W00;process:{}#00".format(child_pid), |
| "read packet: $vStopped#00", |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| else: |
| self.test_sequence.add_log_lines( |
| [ |
| "send packet: $W00;process:{}#00".format(child_pid), |
| ], |
| True, |
| ) |
| self.expect_gdbremote_sequence() |
| |
| def detach_all_test(self, nonstop=False): |
| parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( |
| ["fork"], nonstop=nonstop |
| ) |
| |
| self.test_sequence.add_log_lines( |
| [ |
| # double-check our PIDs |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: $OK#00", |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $OK#00", |
| # detach all processes |
| "read packet: $D#00", |
| "send packet: $OK#00", |
| # verify that both PIDs are invalid now |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: $Eff#00", |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: $Eff#00", |
| ], |
| True, |
| ) |
| self.expect_gdbremote_sequence() |
| |
| def vkill_test(self, kill_parent=False, kill_child=False, nonstop=False): |
| assert kill_parent or kill_child |
| parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( |
| ["fork"], nonstop=nonstop |
| ) |
| |
| if kill_parent: |
| self.test_sequence.add_log_lines( |
| [ |
| # kill the process |
| "read packet: $vKill;{}#00".format(parent_pid), |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| if kill_child: |
| self.test_sequence.add_log_lines( |
| [ |
| # kill the process |
| "read packet: $vKill;{}#00".format(child_pid), |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| self.test_sequence.add_log_lines( |
| [ |
| # check child PID/TID |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: ${}#00".format("Eff" if kill_child else "OK"), |
| # check parent PID/TID |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: ${}#00".format("Eff" if kill_parent else "OK"), |
| ], |
| True, |
| ) |
| self.expect_gdbremote_sequence() |
| |
| def resume_one_test(self, run_order, use_vCont=False, nonstop=False): |
| parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( |
| ["fork", "stop"], nonstop=nonstop |
| ) |
| |
| parent_expect = [ |
| self.stop_regex_base.format(parent_pid, parent_tid), |
| "W00;process:{}#.*".format(parent_pid), |
| ] |
| child_expect = [ |
| self.stop_regex_base.format(child_pid, child_tid), |
| "W00;process:{}#.*".format(child_pid), |
| ] |
| |
| for x in run_order: |
| if x == "parent": |
| pidtid = (parent_pid, parent_tid) |
| expect = parent_expect.pop(0) |
| elif x == "child": |
| pidtid = (child_pid, child_tid) |
| expect = child_expect.pop(0) |
| else: |
| assert False, "unexpected x={}".format(x) |
| |
| if use_vCont: |
| self.test_sequence.add_log_lines( |
| [ |
| # continue the selected process |
| "read packet: $vCont;c:p{}.{}#00".format(*pidtid), |
| ], |
| True, |
| ) |
| else: |
| self.test_sequence.add_log_lines( |
| [ |
| # continue the selected process |
| "read packet: $Hcp{}.{}#00".format(*pidtid), |
| "send packet: $OK#00", |
| "read packet: $c#00", |
| ], |
| True, |
| ) |
| if nonstop: |
| self.test_sequence.add_log_lines( |
| [ |
| "send packet: $OK#00", |
| {"direction": "send", "regex": "%Stop:" + expect}, |
| "read packet: $vStopped#00", |
| "send packet: $OK#00", |
| ], |
| True, |
| ) |
| else: |
| self.test_sequence.add_log_lines( |
| [ |
| {"direction": "send", "regex": "[$]" + expect}, |
| ], |
| True, |
| ) |
| # if at least one process remained, check both PIDs |
| if parent_expect or child_expect: |
| self.test_sequence.add_log_lines( |
| [ |
| "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), |
| "send packet: ${}#00".format("OK" if parent_expect else "Eff"), |
| "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), |
| "send packet: ${}#00".format("OK" if child_expect else "Eff"), |
| ], |
| True, |
| ) |
| self.expect_gdbremote_sequence() |