1//===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "GDBRemoteCommunicationServerPlatform.h"
10
11#include <cerrno>
12
13#include <chrono>
14#include <csignal>
15#include <cstring>
16#include <mutex>
17#include <optional>
18#include <sstream>
19#include <thread>
20
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/JSON.h"
23#include "llvm/Support/Threading.h"
24
25#include "lldb/Host/Config.h"
26#include "lldb/Host/ConnectionFileDescriptor.h"
27#include "lldb/Host/FileAction.h"
28#include "lldb/Host/Host.h"
29#include "lldb/Host/HostInfo.h"
30#include "lldb/Interpreter/CommandCompletions.h"
31#include "lldb/Target/Platform.h"
32#include "lldb/Target/UnixSignals.h"
33#include "lldb/Utility/GDBRemote.h"
34#include "lldb/Utility/LLDBLog.h"
35#include "lldb/Utility/Log.h"
36#include "lldb/Utility/StreamString.h"
37#include "lldb/Utility/StructuredData.h"
38#include "lldb/Utility/TildeExpressionResolver.h"
39#include "lldb/Utility/UriParser.h"
40
41#include "lldb/Utility/StringExtractorGDBRemote.h"
42
43using namespace lldb;
44using namespace lldb_private::process_gdb_remote;
45using namespace lldb_private;
46
47// GDBRemoteCommunicationServerPlatform constructor
48GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
49 const Socket::SocketProtocol socket_protocol, uint16_t gdbserver_port)
50 : GDBRemoteCommunicationServerCommon(), m_socket_protocol(socket_protocol),
51 m_gdbserver_port(gdbserver_port) {
52
53 RegisterMemberFunctionHandler(
54 packet_type: StringExtractorGDBRemote::eServerPacketType_qC,
55 handler: &GDBRemoteCommunicationServerPlatform::Handle_qC);
56 RegisterMemberFunctionHandler(
57 packet_type: StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
58 handler: &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
59 RegisterMemberFunctionHandler(
60 packet_type: StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
61 handler: &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
62 RegisterMemberFunctionHandler(
63 packet_type: StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,
64 handler: &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);
65 RegisterMemberFunctionHandler(
66 packet_type: StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
67 handler: &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
68 RegisterMemberFunctionHandler(
69 packet_type: StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
70 handler: &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
71 RegisterMemberFunctionHandler(
72 packet_type: StringExtractorGDBRemote::eServerPacketType_qPathComplete,
73 handler: &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
74 RegisterMemberFunctionHandler(
75 packet_type: StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
76 handler: &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
77 RegisterMemberFunctionHandler(
78 packet_type: StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
79 handler: &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
80
81 RegisterPacketHandler(packet_type: StringExtractorGDBRemote::eServerPacketType_interrupt,
82 handler: [](StringExtractorGDBRemote packet, Status &error,
83 bool &interrupt, bool &quit) {
84 error = Status::FromErrorString(str: "interrupt received");
85 interrupt = true;
86 return PacketResult::Success;
87 });
88}
89
90// Destructor
91GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
92 default;
93
94Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
95 const lldb_private::Args &args, lldb::pid_t &pid, std::string &socket_name,
96 shared_fd_t fd) {
97 std::ostringstream url;
98 if (fd == SharedSocket::kInvalidFD) {
99 if (m_socket_protocol == Socket::ProtocolTcp) {
100 // Just check that GDBServer exists. GDBServer must be launched after
101 // accepting the connection.
102 if (!GetDebugserverPath(platform: nullptr))
103 return Status::FromErrorString(str: "unable to locate debugserver");
104 return Status();
105 }
106
107 // debugserver does not accept the URL scheme prefix.
108#if !defined(__APPLE__)
109 url << Socket::FindSchemeByProtocol(protocol: m_socket_protocol) << "://";
110#endif
111 socket_name = GetDomainSocketPath(prefix: "gdbserver").GetPath();
112 url << socket_name;
113 } else {
114 if (m_socket_protocol != Socket::ProtocolTcp)
115 return Status::FromErrorString(str: "protocol must be tcp");
116 }
117
118 // Spawn a debugserver and try to get the port it listens to.
119 ProcessLaunchInfo debugserver_launch_info;
120 Log *log = GetLog(mask: LLDBLog::Platform);
121 LLDB_LOG(log, "Launching debugserver url='{0}', fd={1}...", url.str(), fd);
122
123 // Do not run in a new session so that it can not linger after the platform
124 // closes.
125 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
126 debugserver_launch_info.SetMonitorProcessCallback(
127 [](lldb::pid_t, int, int) {});
128
129 Status error = StartDebugserverProcess(
130 url: url.str().c_str(), platform: nullptr, launch_info&: debugserver_launch_info, port: nullptr, inferior_args: &args, pass_comm_fd: fd);
131
132 if (error.Success()) {
133 pid = debugserver_launch_info.GetProcessID();
134 AddSpawnedProcess(pid);
135 LLDB_LOGF(log,
136 "GDBRemoteCommunicationServerPlatform::%s() "
137 "debugserver launched successfully as pid %" PRIu64,
138 __FUNCTION__, pid);
139 } else {
140 LLDB_LOGF(log,
141 "GDBRemoteCommunicationServerPlatform::%s() "
142 "debugserver launch failed: %s",
143 __FUNCTION__, error.AsCString());
144 }
145 return error;
146}
147
148GDBRemoteCommunication::PacketResult
149GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
150 StringExtractorGDBRemote &packet) {
151 // Spawn a local debugserver as a platform so we can then attach or launch a
152 // process...
153
154 Log *log = GetLog(mask: LLDBLog::Platform);
155 LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called",
156 __FUNCTION__);
157
158 ConnectionFileDescriptor file_conn;
159 std::string hostname;
160 packet.SetFilePos(::strlen(s: "qLaunchGDBServer;"));
161 llvm::StringRef name;
162 llvm::StringRef value;
163 std::optional<uint16_t> port;
164 while (packet.GetNameColonValue(name, value)) {
165 if (name == "host")
166 hostname = std::string(value);
167 else if (name == "port") {
168 // Make the Optional valid so we can use its value
169 port = 0;
170 value.getAsInteger(Radix: 0, Result&: *port);
171 }
172 }
173
174 // Ignore client's hostname and the port.
175
176 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
177 std::string socket_name;
178 Status error = LaunchGDBServer(args: Args(), pid&: debugserver_pid, socket_name,
179 fd: SharedSocket::kInvalidFD);
180 if (error.Fail())
181 return SendErrorResponse(error: 9); // EBADF
182
183 StreamGDBRemote response;
184 uint16_t gdbserver_port = socket_name.empty() ? m_gdbserver_port : 0;
185 response.Printf(format: "pid:%" PRIu64 ";port:%u;", debugserver_pid, gdbserver_port);
186 if (!socket_name.empty()) {
187 response.PutCString(cstr: "socket_name:");
188 response.PutStringAsRawHex8(s: socket_name);
189 response.PutChar(ch: ';');
190 }
191
192 PacketResult packet_result = SendPacketNoLock(payload: response.GetString());
193 if (packet_result != PacketResult::Success) {
194 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
195 Host::Kill(pid: debugserver_pid, SIGINT);
196 }
197 return packet_result;
198}
199
200GDBRemoteCommunication::PacketResult
201GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer(
202 StringExtractorGDBRemote &packet) {
203 namespace json = llvm::json;
204
205 if (!m_pending_gdb_server_socket_name)
206 return SendErrorResponse(error: 4);
207
208 json::Object server{{.K: "port", .V: m_pending_gdb_server_socket_name->empty()
209 ? m_gdbserver_port
210 : 0}};
211
212 if (!m_pending_gdb_server_socket_name->empty())
213 server.try_emplace(K: "socket_name", Args&: *m_pending_gdb_server_socket_name);
214
215 json::Array server_list;
216 server_list.push_back(E: std::move(server));
217
218 StreamGDBRemote response;
219 response.AsRawOstream() << std::move(server_list);
220
221 StreamGDBRemote escaped_response;
222 escaped_response.PutEscapedBytes(s: response.GetString().data(),
223 src_len: response.GetSize());
224 return SendPacketNoLock(payload: escaped_response.GetString());
225}
226
227GDBRemoteCommunication::PacketResult
228GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess(
229 StringExtractorGDBRemote &packet) {
230 packet.SetFilePos(::strlen(s: "qKillSpawnedProcess:"));
231
232 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
233
234 // verify that we know anything about this pid.
235 if (!SpawnedProcessIsRunning(pid)) {
236 // not a pid we know about
237 return SendErrorResponse(error: 10);
238 }
239
240 // go ahead and attempt to kill the spawned process
241 if (KillSpawnedProcess(pid))
242 return SendOKResponse();
243 else
244 return SendErrorResponse(error: 11);
245}
246
247void GDBRemoteCommunicationServerPlatform::AddSpawnedProcess(lldb::pid_t pid) {
248 assert(pid != LLDB_INVALID_PROCESS_ID);
249 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
250 m_spawned_pids.insert(x: pid);
251}
252
253bool GDBRemoteCommunicationServerPlatform::SpawnedProcessIsRunning(
254 lldb::pid_t pid) {
255 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
256 return (m_spawned_pids.find(x: pid) != m_spawned_pids.end());
257}
258
259bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) {
260 // make sure we know about this process
261 if (!SpawnedProcessIsRunning(pid)) {
262 // it seems the process has been finished recently
263 return true;
264 }
265
266 // first try a SIGTERM (standard kill)
267 Host::Kill(pid, SIGTERM);
268
269 // check if that worked
270 for (size_t i = 0; i < 10; ++i) {
271 if (!SpawnedProcessIsRunning(pid)) {
272 // it is now killed
273 return true;
274 }
275 std::this_thread::sleep_for(rtime: std::chrono::milliseconds(10));
276 }
277
278 if (!SpawnedProcessIsRunning(pid))
279 return true;
280
281 // the launched process still lives. Now try killing it again, this time
282 // with an unblockable signal.
283 Host::Kill(pid, SIGKILL);
284
285 for (size_t i = 0; i < 10; ++i) {
286 if (!SpawnedProcessIsRunning(pid)) {
287 // it is now killed
288 return true;
289 }
290 std::this_thread::sleep_for(rtime: std::chrono::milliseconds(10));
291 }
292
293 // check one more time after the final sleep
294 return !SpawnedProcessIsRunning(pid);
295}
296
297GDBRemoteCommunication::PacketResult
298GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
299 StringExtractorGDBRemote &packet) {
300 lldb::pid_t pid = m_process_launch_info.GetProcessID();
301 m_process_launch_info.Clear();
302
303 if (pid == LLDB_INVALID_PROCESS_ID)
304 return SendErrorResponse(error: 1);
305
306 ProcessInstanceInfo proc_info;
307 if (!Host::GetProcessInfo(pid, proc_info))
308 return SendErrorResponse(error: 1);
309
310 StreamString response;
311 CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
312 return SendPacketNoLock(payload: response.GetString());
313}
314
315GDBRemoteCommunication::PacketResult
316GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
317 StringExtractorGDBRemote &packet) {
318 packet.SetFilePos(::strlen(s: "qPathComplete:"));
319 const bool only_dir = (packet.GetHexMaxU32(little_endian: false, fail_value: 0) == 1);
320 if (packet.GetChar() != ',')
321 return SendErrorResponse(error: 85);
322 std::string path;
323 packet.GetHexByteString(str&: path);
324
325 StringList matches;
326 StandardTildeExpressionResolver resolver;
327 if (only_dir)
328 CommandCompletions::DiskDirectories(partial_file_name: path, matches, Resolver&: resolver);
329 else
330 CommandCompletions::DiskFiles(partial_file_name: path, matches, Resolver&: resolver);
331
332 StreamString response;
333 response.PutChar(ch: 'M');
334 llvm::StringRef separator;
335 std::sort(first: matches.begin(), last: matches.end());
336 for (const auto &match : matches) {
337 response << separator;
338 separator = ",";
339 // encode result strings into hex bytes to avoid unexpected error caused by
340 // special characters like '$'.
341 response.PutStringAsRawHex8(s: match.c_str());
342 }
343
344 return SendPacketNoLock(payload: response.GetString());
345}
346
347GDBRemoteCommunication::PacketResult
348GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
349 StringExtractorGDBRemote &packet) {
350
351 llvm::SmallString<64> cwd;
352 if (std::error_code ec = llvm::sys::fs::current_path(result&: cwd))
353 return SendErrorResponse(error: ec.value());
354
355 StreamString response;
356 response.PutBytesAsRawHex8(src: cwd.data(), src_len: cwd.size());
357 return SendPacketNoLock(payload: response.GetString());
358}
359
360GDBRemoteCommunication::PacketResult
361GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(
362 StringExtractorGDBRemote &packet) {
363 packet.SetFilePos(::strlen(s: "QSetWorkingDir:"));
364 std::string path;
365 packet.GetHexByteString(str&: path);
366
367 if (std::error_code ec = llvm::sys::fs::set_current_path(path))
368 return SendErrorResponse(error: ec.value());
369 return SendOKResponse();
370}
371
372GDBRemoteCommunication::PacketResult
373GDBRemoteCommunicationServerPlatform::Handle_qC(
374 StringExtractorGDBRemote &packet) {
375 // NOTE: lldb should now be using qProcessInfo for process IDs. This path
376 // here
377 // should not be used. It is reporting process id instead of thread id. The
378 // correct answer doesn't seem to make much sense for lldb-platform.
379 // CONSIDER: flip to "unsupported".
380 lldb::pid_t pid = m_process_launch_info.GetProcessID();
381
382 StreamString response;
383 response.Printf(format: "QC%" PRIx64, pid);
384
385 // If we launch a process and this GDB server is acting as a platform, then
386 // we need to clear the process launch state so we can start launching
387 // another process. In order to launch a process a bunch or packets need to
388 // be sent: environment packets, working directory, disable ASLR, and many
389 // more settings. When we launch a process we then need to know when to clear
390 // this information. Currently we are selecting the 'qC' packet as that
391 // packet which seems to make the most sense.
392 if (pid != LLDB_INVALID_PROCESS_ID) {
393 m_process_launch_info.Clear();
394 }
395
396 return SendPacketNoLock(payload: response.GetString());
397}
398
399GDBRemoteCommunication::PacketResult
400GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
401 StringExtractorGDBRemote &packet) {
402 StructuredData::Array signal_array;
403
404 lldb::UnixSignalsSP signals = UnixSignals::CreateForHost();
405 for (auto signo = signals->GetFirstSignalNumber();
406 signo != LLDB_INVALID_SIGNAL_NUMBER;
407 signo = signals->GetNextSignalNumber(current_signal: signo)) {
408 auto dictionary = std::make_shared<StructuredData::Dictionary>();
409
410 dictionary->AddIntegerItem(key: "signo", value: signo);
411 dictionary->AddStringItem(key: "name", value: signals->GetSignalAsStringRef(signo));
412
413 bool suppress, stop, notify;
414 signals->GetSignalInfo(signo, should_suppress&: suppress, should_stop&: stop, should_notify&: notify);
415 dictionary->AddBooleanItem(key: "suppress", value: suppress);
416 dictionary->AddBooleanItem(key: "stop", value: stop);
417 dictionary->AddBooleanItem(key: "notify", value: notify);
418
419 signal_array.Push(item: dictionary);
420 }
421
422 StreamString response;
423 signal_array.Dump(s&: response);
424 return SendPacketNoLock(payload: response.GetString());
425}
426
427void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
428 lldb::pid_t pid) {
429 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
430 m_spawned_pids.erase(x: pid);
431}
432
433Status GDBRemoteCommunicationServerPlatform::LaunchProcess() {
434 if (!m_process_launch_info.GetArguments().GetArgumentCount())
435 return Status::FromErrorStringWithFormat(
436 format: "%s: no process command line specified to launch", __FUNCTION__);
437
438 // specify the process monitor if not already set. This should generally be
439 // what happens since we need to reap started processes.
440 if (!m_process_launch_info.GetMonitorProcessCallback())
441 m_process_launch_info.SetMonitorProcessCallback(std::bind(
442 f: &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, args: this,
443 args: std::placeholders::_1));
444
445 Status error = Host::LaunchProcess(launch_info&: m_process_launch_info);
446 if (!error.Success()) {
447 fprintf(stderr, format: "%s: failed to launch executable %s", __FUNCTION__,
448 m_process_launch_info.GetArguments().GetArgumentAtIndex(idx: 0));
449 return error;
450 }
451
452 printf(format: "Launched '%s' as process %" PRIu64 "...\n",
453 m_process_launch_info.GetArguments().GetArgumentAtIndex(idx: 0),
454 m_process_launch_info.GetProcessID());
455
456 // add to list of spawned processes. On an lldb-gdbserver, we would expect
457 // there to be only one.
458 const auto pid = m_process_launch_info.GetProcessID();
459 AddSpawnedProcess(pid);
460
461 return error;
462}
463
464const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
465 static FileSpec g_domainsocket_dir;
466 static llvm::once_flag g_once_flag;
467
468 llvm::call_once(flag&: g_once_flag, F: []() {
469 const char *domainsocket_dir_env =
470 ::getenv(name: "LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
471 if (domainsocket_dir_env != nullptr)
472 g_domainsocket_dir = FileSpec(domainsocket_dir_env);
473 else
474 g_domainsocket_dir = HostInfo::GetProcessTempDir();
475 });
476
477 return g_domainsocket_dir;
478}
479
480FileSpec
481GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) {
482 llvm::SmallString<128> socket_path;
483 llvm::SmallString<128> socket_name(
484 (llvm::StringRef(prefix) + ".%%%%%%").str());
485
486 FileSpec socket_path_spec(GetDomainSocketDir());
487 socket_path_spec.AppendPathComponent(component: socket_name.c_str());
488
489 llvm::sys::fs::createUniqueFile(Model: socket_path_spec.GetPath().c_str(),
490 ResultPath&: socket_path);
491 return FileSpec(socket_path.c_str());
492}
493
494void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(
495 const std::string &socket_name) {
496 m_pending_gdb_server_socket_name = socket_name;
497}
498

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp