Skip to content

Commit

Permalink
[lldb] [test] Split TestGdbRemoteFork in two
Browse files Browse the repository at this point in the history
Split the test that's gotten very long in two, in hope that it will
resolve the arm/aarch64 buildbot failures.  Even if it does not, it
could help pinpointing where the problem lies.

Sponsored by: The FreeBSD Foundation
  • Loading branch information
mgorny committed Jun 29, 2022
1 parent 9c04851 commit 7fc12da
Show file tree
Hide file tree
Showing 3 changed files with 322 additions and 313 deletions.
204 changes: 204 additions & 0 deletions lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import gdbremote_testcase


class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase):
fork_regex = ("[$]T05thread:p([0-9a-f]+)[.]([0-9a-f]+);.*"
"{}:p([0-9a-f]+)[.]([0-9a-f]+).*")
fork_regex_nonstop = ("%Stop:T05thread: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"}

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", "trap"], nonstop=nonstop))

parent_expect = [
"T05thread:p{}.{};.*".format(parent_pid, parent_tid),
"W00;process:{}#.*".format(parent_pid),
]
child_expect = [
"T05thread:p{}.{};.*".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()
Loading

0 comments on commit 7fc12da

Please sign in to comment.