Skip to content

Commit f8603c1

Browse files
committed
[lldb] [llgs] Support resuming multiple processes via vCont w/ nonstop
Support using the vCont packet to resume multiple processes simultaneously when in non-stop mode. The new logic now assumes that: - actions without a thread-id or with process id of "p-1" apply to all debugged processes - actions with a thread-id without process id apply to the current process (m_continue_process) As with the other continue packets, it is only possible to resume processes that are currently stopped (or stop these that are running). It is unsupported to resume or stop individual threads of a running process. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D128989
1 parent 0806927 commit f8603c1

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
17621762
break;
17631763
}
17641764

1765+
// If there's no thread-id (e.g. "vCont;c"), it's "p-1.-1".
17651766
lldb::pid_t pid = StringExtractorGDBRemote::AllProcesses;
17661767
lldb::tid_t tid = StringExtractorGDBRemote::AllThreads;
17671768

@@ -1770,7 +1771,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
17701771
// Consume the separator.
17711772
packet.GetChar();
17721773

1773-
auto pid_tid = packet.GetPidTid(StringExtractorGDBRemote::AllProcesses);
1774+
auto pid_tid = packet.GetPidTid(LLDB_INVALID_PROCESS_ID);
17741775
if (!pid_tid)
17751776
return SendIllFormedResponse(packet, "Malformed thread-id");
17761777

@@ -1784,29 +1785,35 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
17841785
packet, "'t' action not supported for individual threads");
17851786
}
17861787

1787-
if (pid == StringExtractorGDBRemote::AllProcesses) {
1788-
if (m_debugged_processes.size() > 1)
1789-
return SendIllFormedResponse(
1790-
packet, "Resuming multiple processes not supported yet");
1788+
// If we get TID without PID, it's the current process.
1789+
if (pid == LLDB_INVALID_PROCESS_ID) {
17911790
if (!m_continue_process) {
1792-
LLDB_LOG(log, "no debugged process");
1791+
LLDB_LOG(log, "no process selected via Hc");
17931792
return SendErrorResponse(0x36);
17941793
}
17951794
pid = m_continue_process->GetID();
17961795
}
17971796

1797+
assert(pid != LLDB_INVALID_PROCESS_ID);
17981798
if (tid == StringExtractorGDBRemote::AllThreads)
17991799
tid = LLDB_INVALID_THREAD_ID;
1800-
18011800
thread_action.tid = tid;
18021801

1803-
thread_actions[pid].Append(thread_action);
1802+
if (pid == StringExtractorGDBRemote::AllProcesses) {
1803+
if (tid != LLDB_INVALID_THREAD_ID)
1804+
return SendIllFormedResponse(
1805+
packet, "vCont: p-1 is not valid with a specific tid");
1806+
for (auto &process_it : m_debugged_processes)
1807+
thread_actions[process_it.first].Append(thread_action);
1808+
} else
1809+
thread_actions[pid].Append(thread_action);
18041810
}
18051811

18061812
assert(thread_actions.size() >= 1);
1807-
if (thread_actions.size() > 1)
1813+
if (thread_actions.size() > 1 && !m_non_stop)
18081814
return SendIllFormedResponse(
1809-
packet, "Resuming multiple processes not supported yet");
1815+
packet,
1816+
"Resuming multiple processes is supported in non-stop mode only");
18101817

18111818
for (std::pair<lldb::pid_t, ResumeActionList> x : thread_actions) {
18121819
auto process_it = m_debugged_processes.find(x.first);

lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,55 @@ def test_c_both_nonstop(self):
150150
self.assertEqual(output.count(b"PID: "), 2)
151151
self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output)
152152
self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output)
153+
154+
@add_test_categories(["fork"])
155+
def test_vCont_both_nonstop(self):
156+
lock1 = self.getBuildArtifact("lock1")
157+
lock2 = self.getBuildArtifact("lock2")
158+
parent_pid, parent_tid, child_pid, child_tid = (
159+
self.start_fork_test(["fork", "process:sync:" + lock1, "print-pid",
160+
"process:sync:" + lock2, "stop"],
161+
nonstop=True))
162+
163+
self.test_sequence.add_log_lines([
164+
"read packet: $vCont;c:p{}.{};c:p{}.{}#00".format(
165+
parent_pid, parent_tid, child_pid, child_tid),
166+
"send packet: $OK#00",
167+
{"direction": "send", "regex": "%Stop:T.*"},
168+
], True)
169+
self.expect_gdbremote_sequence()
170+
171+
output = self.get_all_output_via_vStdio(
172+
lambda output: output.count(b"PID: ") >= 2)
173+
self.assertEqual(output.count(b"PID: "), 2)
174+
self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output)
175+
self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output)
176+
177+
def vCont_both_nonstop_test(self, vCont_packet):
178+
lock1 = self.getBuildArtifact("lock1")
179+
lock2 = self.getBuildArtifact("lock2")
180+
parent_pid, parent_tid, child_pid, child_tid = (
181+
self.start_fork_test(["fork", "process:sync:" + lock1, "print-pid",
182+
"process:sync:" + lock2, "stop"],
183+
nonstop=True))
184+
185+
self.test_sequence.add_log_lines([
186+
"read packet: ${}#00".format(vCont_packet),
187+
"send packet: $OK#00",
188+
{"direction": "send", "regex": "%Stop:T.*"},
189+
], True)
190+
self.expect_gdbremote_sequence()
191+
192+
output = self.get_all_output_via_vStdio(
193+
lambda output: output.count(b"PID: ") >= 2)
194+
self.assertEqual(output.count(b"PID: "), 2)
195+
self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output)
196+
self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output)
197+
198+
@add_test_categories(["fork"])
199+
def test_vCont_both_implicit_nonstop(self):
200+
self.vCont_both_nonstop_test("vCont;c")
201+
202+
@add_test_categories(["fork"])
203+
def test_vCont_both_minus_one_nonstop(self):
204+
self.vCont_both_nonstop_test("vCont;c:p-1.-1")

0 commit comments

Comments
 (0)