Skip to content

Commit b4f2d7c

Browse files
committed
[lldb] [llgs] Support "t" vCont action
Implement support for the "t" action that is used to stop a thread. Normally this action is used only in non-stop mode. However, there's no technical reason why it couldn't be also used in all-stop mode, e.g. to express "resume all threads except ..." (`t:...;c`). While at it, add a more complete test for vCont correctly resuming a subset of program's threads. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D126983
1 parent 48eb2bc commit b4f2d7c

File tree

6 files changed

+88
-9
lines changed

6 files changed

+88
-9
lines changed

lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) {
947947

948948
case eStateSuspended:
949949
case eStateStopped:
950-
llvm_unreachable("Unexpected state");
950+
break;
951951

952952
default:
953953
return Status("NativeProcessLinux::%s (): unexpected state %s specified "

lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
117117
}
118118
case eStateSuspended:
119119
case eStateStopped:
120-
llvm_unreachable("Unexpected state");
120+
break;
121121

122122
default:
123123
return Status(

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -1654,7 +1654,7 @@ GDBRemoteCommunication::PacketResult
16541654
GDBRemoteCommunicationServerLLGS::Handle_vCont_actions(
16551655
StringExtractorGDBRemote &packet) {
16561656
StreamString response;
1657-
response.Printf("vCont;c;C;s;S");
1657+
response.Printf("vCont;c;C;s;S;t");
16581658

16591659
return SendPacketNoLock(response.GetString());
16601660
}
@@ -1723,6 +1723,11 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
17231723
thread_action.state = eStateStepping;
17241724
break;
17251725

1726+
case 't':
1727+
// Stop
1728+
thread_action.state = eStateSuspended;
1729+
break;
1730+
17261731
default:
17271732
return SendIllFormedResponse(packet, "Unsupported vCont action");
17281733
break;

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

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ def test_vCont_supports_S(self):
3939
self.build()
4040
self.vCont_supports_mode("S")
4141

42+
def test_vCont_supports_t(self):
43+
self.build()
44+
self.vCont_supports_mode("t")
45+
4246
@skipIfWindows # No pty support to test O* & I* notification packets.
4347
@skipIf(triple='^mips')
4448
def test_single_step_only_steps_one_instruction_with_Hc_vCont_s(self):

lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py

+72-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import re
3+
import time
34

45
import gdbremote_testcase
56
from lldbsuite.test.decorators import *
@@ -13,8 +14,7 @@ def start_threads(self, num):
1314
# start the process and wait for output
1415
self.test_sequence.add_log_lines([
1516
"read packet: $c#63",
16-
{"type": "output_match", "regex": self.maybe_strict_output_regex(
17-
r"@started\r\n")},
17+
{"type": "output_match", "regex": r".*@started\r\n.*"},
1818
], True)
1919
# then interrupt it
2020
self.add_interrupt_packets()
@@ -33,9 +33,8 @@ def send_and_check_signal(self, vCont_data, threads):
3333
self.test_sequence.add_log_lines([
3434
"read packet: $vCont;{0}#00".format(vCont_data),
3535
{"type": "output_match",
36-
"regex": self.maybe_strict_output_regex(
37-
len(threads) *
38-
r"received SIGUSR1 on thread id: ([0-9a-f]+)\r\n"),
36+
"regex": len(threads) *
37+
r".*received SIGUSR1 on thread id: ([0-9a-f]+)\r\n.*",
3938
"capture": dict((i, "tid{0}".format(i)) for i
4039
in range(1, len(threads)+1)),
4140
},
@@ -243,3 +242,71 @@ def test_signal_two_signals(self):
243242

244243
context = self.expect_gdbremote_sequence()
245244
self.assertIsNotNone(context)
245+
246+
THREAD_MATCH_RE = re.compile(r"thread ([0-9a-f]+) running")
247+
248+
def continue_and_get_threads_running(self, continue_packet):
249+
self.test_sequence.add_log_lines(
250+
["read packet: ${}#00".format(continue_packet),
251+
], True)
252+
self.expect_gdbremote_sequence()
253+
self.reset_test_sequence()
254+
time.sleep(1)
255+
self.add_interrupt_packets()
256+
exp = self.expect_gdbremote_sequence()
257+
found = set()
258+
for line in exp["O_content"].decode().splitlines():
259+
m = self.THREAD_MATCH_RE.match(line)
260+
if m is not None:
261+
found.add(int(m.group(1), 16))
262+
return found
263+
264+
@add_test_categories(["llgs"])
265+
def test_vCont_run_subset_of_threads(self):
266+
self.build()
267+
self.set_inferior_startup_launch()
268+
269+
threads = set(self.start_threads(3))
270+
all_subthreads = self.continue_and_get_threads_running("c")
271+
all_subthreads_list = list(all_subthreads)
272+
self.assertEqual(len(all_subthreads), 3)
273+
self.assertEqual(threads & all_subthreads, all_subthreads)
274+
275+
# resume two threads explicitly, stop the third one implicitly
276+
self.assertEqual(
277+
self.continue_and_get_threads_running(
278+
"vCont;c:{:x};c:{:x}".format(*all_subthreads_list[:2])),
279+
set(all_subthreads_list[:2]))
280+
281+
# resume two threads explicitly, stop others explicitly
282+
self.assertEqual(
283+
self.continue_and_get_threads_running(
284+
"vCont;c:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
285+
set(all_subthreads_list[:2]))
286+
287+
# stop one thread explicitly, resume others
288+
self.assertEqual(
289+
self.continue_and_get_threads_running(
290+
"vCont;t:{:x};c".format(all_subthreads_list[-1])),
291+
set(all_subthreads_list[:2]))
292+
293+
# resume one thread explicitly, stop one explicitly,
294+
# resume others
295+
self.assertEqual(
296+
self.continue_and_get_threads_running(
297+
"vCont;c:{:x};t:{:x};c".format(*all_subthreads_list[-2:])),
298+
set(all_subthreads_list[:2]))
299+
300+
# resume one thread explicitly, stop one explicitly,
301+
# stop others implicitly
302+
self.assertEqual(
303+
self.continue_and_get_threads_running(
304+
"vCont;t:{:x};c:{:x}".format(*all_subthreads_list[:2])),
305+
set(all_subthreads_list[1:2]))
306+
307+
# resume one thread explicitly, stop one explicitly,
308+
# stop others explicitly
309+
self.assertEqual(
310+
self.continue_and_get_threads_running(
311+
"vCont;t:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
312+
set(all_subthreads_list[1:2]))

lldb/test/API/tools/lldb-server/vCont-threads/main.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ static void sigusr1_handler(int signo) {
2222

2323
static void thread_func() {
2424
pseudo_barrier_wait(barrier);
25-
std::this_thread::sleep_for(std::chrono::minutes(1));
25+
for (int i = 0; i < 300; ++i) {
26+
std::printf("thread %" PRIx64 " running\n", get_thread_id());
27+
std::this_thread::sleep_for(std::chrono::milliseconds(200));
28+
}
2629
}
2730

2831
int main(int argc, char **argv) {

0 commit comments

Comments
 (0)