Skip to content

Commit 2afaf07

Browse files
augusto2112labath
authored andcommitted
Implement vAttachOrWait
Implements the required functions on gdb-remote so the '--include-existing' flag of process attach works correctly on Linux. Reviewed By: labath, clayborg Differential Revision: https://reviews.llvm.org/D94672
1 parent 50830e5 commit 2afaf07

File tree

3 files changed

+170
-9
lines changed

3 files changed

+170
-9
lines changed

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

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
162162
RegisterMemberFunctionHandler(
163163
StringExtractorGDBRemote::eServerPacketType_vAttachWait,
164164
&GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
165+
RegisterMemberFunctionHandler(
166+
StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported,
167+
&GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported);
168+
RegisterMemberFunctionHandler(
169+
StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
170+
&GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
165171
RegisterMemberFunctionHandler(
166172
StringExtractorGDBRemote::eServerPacketType_vCont,
167173
&GDBRemoteCommunicationServerLLGS::Handle_vCont);
@@ -338,7 +344,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
338344
}
339345

340346
Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
341-
llvm::StringRef process_name) {
347+
llvm::StringRef process_name, bool include_existing) {
342348
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
343349

344350
std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
@@ -347,13 +353,17 @@ Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
347353
ProcessInstanceInfoList exclusion_list;
348354
ProcessInstanceInfoMatch match_info;
349355
match_info.GetProcessInfo().GetExecutableFile().SetFile(
350-
process_name, llvm::sys::path::Style::posix);
351-
match_info.SetNameMatchType(NameMatch::EndsWith);
356+
process_name, llvm::sys::path::Style::native);
357+
match_info.SetNameMatchType(NameMatch::Equals);
352358

353-
// Create the excluded process list before polling begins.
354-
Host::FindProcesses(match_info, exclusion_list);
355-
LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
356-
exclusion_list.size());
359+
if (include_existing) {
360+
LLDB_LOG(log, "including existing processes in search");
361+
} else {
362+
// Create the excluded process list before polling begins.
363+
Host::FindProcesses(match_info, exclusion_list);
364+
LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
365+
exclusion_list.size());
366+
}
357367

358368
LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
359369

@@ -3275,7 +3285,43 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
32753285

32763286
LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
32773287

3278-
Status error = AttachWaitProcess(process_name);
3288+
Status error = AttachWaitProcess(process_name, false);
3289+
if (error.Fail()) {
3290+
LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
3291+
error);
3292+
return SendErrorResponse(error);
3293+
}
3294+
3295+
// Notify we attached by sending a stop packet.
3296+
return SendStopReasonForState(m_debugged_process_up->GetState());
3297+
}
3298+
3299+
GDBRemoteCommunication::PacketResult
3300+
GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported(
3301+
StringExtractorGDBRemote &packet) {
3302+
return SendOKResponse();
3303+
}
3304+
3305+
GDBRemoteCommunication::PacketResult
3306+
GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait(
3307+
StringExtractorGDBRemote &packet) {
3308+
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
3309+
3310+
// Consume the ';' after the identifier.
3311+
packet.SetFilePos(strlen("vAttachOrWait"));
3312+
3313+
if (!packet.GetBytesLeft() || packet.GetChar() != ';')
3314+
return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'");
3315+
3316+
// Allocate the buffer for the process name from vAttachWait.
3317+
std::string process_name;
3318+
if (!packet.GetHexByteString(process_name))
3319+
return SendIllFormedResponse(packet,
3320+
"vAttachOrWait failed to parse process name");
3321+
3322+
LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
3323+
3324+
Status error = AttachWaitProcess(process_name, true);
32793325
if (error.Fail()) {
32803326
LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
32813327
error);

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class GDBRemoteCommunicationServerLLGS
6868
/// \return
6969
/// An Status object indicating the success or failure of the
7070
/// attach operation.
71-
Status AttachWaitProcess(llvm::StringRef process_name);
71+
Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing);
7272

7373
// NativeProcessProtocol::NativeDelegate overrides
7474
void InitializeDelegate(NativeProcessProtocol *process) override;
@@ -183,6 +183,10 @@ class GDBRemoteCommunicationServerLLGS
183183

184184
PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet);
185185

186+
PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet);
187+
188+
PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet);
189+
186190
PacketResult Handle_D(StringExtractorGDBRemote &packet);
187191

188192
PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
2+
import os
3+
from time import sleep
4+
5+
import gdbremote_testcase
6+
import lldbgdbserverutils
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
12+
class TestGdbRemoteAttachOrWait(gdbremote_testcase.GdbRemoteTestCaseBase):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
16+
def test_launch_before_attach_with_vAttachOrWait(self):
17+
exe = '%s_%d' % (self.testMethodName, os.getpid())
18+
self.build(dictionary={'EXE': exe})
19+
self.set_inferior_startup_attach_manually()
20+
21+
# Start the inferior, start the debug monitor, nothing is attached yet.
22+
procs = self.prep_debug_monitor_and_inferior(
23+
inferior_args=["sleep:60"],
24+
inferior_exe_path=self.getBuildArtifact(exe))
25+
self.assertIsNotNone(procs)
26+
27+
# Make sure the target process has been launched.
28+
inferior = procs.get("inferior")
29+
self.assertIsNotNone(inferior)
30+
self.assertTrue(inferior.pid > 0)
31+
self.assertTrue(
32+
lldbgdbserverutils.process_is_running(
33+
inferior.pid, True))
34+
35+
# Add attach packets.
36+
self.test_sequence.add_log_lines([
37+
# Do the attach.
38+
"read packet: $vAttachOrWait;{}#00".format(lldbgdbserverutils.gdbremote_hex_encode_string(exe)),
39+
# Expect a stop notification from the attach.
40+
{"direction": "send",
41+
"regex": r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$",
42+
"capture": {1: "stop_signal_hex"}},
43+
], True)
44+
self.add_process_info_collection_packets()
45+
46+
# Run the stream
47+
context = self.expect_gdbremote_sequence()
48+
self.assertIsNotNone(context)
49+
50+
# Gather process info response
51+
process_info = self.parse_process_info_response(context)
52+
self.assertIsNotNone(process_info)
53+
54+
# Ensure the process id matches what we expected.
55+
pid_text = process_info.get('pid', None)
56+
self.assertIsNotNone(pid_text)
57+
reported_pid = int(pid_text, base=16)
58+
self.assertEqual(reported_pid, inferior.pid)
59+
60+
def test_launch_after_attach_with_vAttachOrWait(self):
61+
exe = '%s_%d' % (self.testMethodName, os.getpid())
62+
self.build(dictionary={'EXE': exe})
63+
self.set_inferior_startup_attach_manually()
64+
65+
server = self.connect_to_debug_monitor()
66+
self.assertIsNotNone(server)
67+
68+
self.add_no_ack_remote_stream()
69+
self.test_sequence.add_log_lines([
70+
# Do the attach.
71+
"read packet: $vAttachOrWait;{}#00".format(lldbgdbserverutils.gdbremote_hex_encode_string(exe)),
72+
], True)
73+
# Run the stream until attachWait.
74+
context = self.expect_gdbremote_sequence()
75+
self.assertIsNotNone(context)
76+
77+
# Sleep so we're sure that the inferior is launched after we ask for the attach.
78+
sleep(1)
79+
80+
# Launch the inferior.
81+
inferior = self.launch_process_for_attach(
82+
inferior_args=["sleep:60"],
83+
exe_path=self.getBuildArtifact(exe))
84+
self.assertIsNotNone(inferior)
85+
self.assertTrue(inferior.pid > 0)
86+
self.assertTrue(
87+
lldbgdbserverutils.process_is_running(
88+
inferior.pid, True))
89+
90+
# Make sure the attach succeeded.
91+
self.test_sequence.add_log_lines([
92+
{"direction": "send",
93+
"regex": r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$",
94+
"capture": {1: "stop_signal_hex"}},
95+
], True)
96+
self.add_process_info_collection_packets()
97+
98+
99+
# Run the stream sending the response..
100+
context = self.expect_gdbremote_sequence()
101+
self.assertIsNotNone(context)
102+
103+
# Gather process info response.
104+
process_info = self.parse_process_info_response(context)
105+
self.assertIsNotNone(process_info)
106+
107+
# Ensure the process id matches what we expected.
108+
pid_text = process_info.get('pid', None)
109+
self.assertIsNotNone(pid_text)
110+
reported_pid = int(pid_text, base=16)
111+
self.assertEqual(reported_pid, inferior.pid)

0 commit comments

Comments
 (0)