LLDB mainline
GDBRemoteCommunicationServerPlatform.cpp
Go to the documentation of this file.
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
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"
28#include "lldb/Host/Host.h"
29#include "lldb/Host/HostInfo.h"
34#include "lldb/Utility/Log.h"
39
41
42using namespace lldb;
44using namespace lldb_private;
45
46// GDBRemoteCommunicationServerPlatform constructor
48 FileSpec debugserver_path, const Socket::SocketProtocol socket_protocol,
49 uint16_t gdbserver_port)
50 : m_debugserver_path(std::move(debugserver_path)),
51 m_socket_protocol(socket_protocol), m_gdbserver_port(gdbserver_port) {
52
77
80 bool &interrupt, bool &quit) {
81 error = Status::FromErrorString("interrupt received");
82 interrupt = true;
84 });
85}
86
87// Destructor
89 default;
90
92 const lldb_private::Args &args, lldb::pid_t &pid, std::string &socket_name,
93 shared_fd_t fd) {
95
96 ProcessLaunchInfo debugserver_launch_info;
97 // Do not run in a new session so that it can not linger after the platform
98 // closes.
99 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
100 debugserver_launch_info.SetMonitorProcessCallback(
101 [](lldb::pid_t, int, int) {});
103 return Status::FromErrorString("debugserver does not exist");
104 debugserver_launch_info.SetExecutableFile(m_debugserver_path,
105 /*add_exe_file_as_first_arg=*/true);
106
108 if (fd == SharedSocket::kInvalidFD) {
110 // The server will be launched after accepting the connection.
111 return Status();
112 }
113
114 std::ostringstream url;
115 // debugserver does not accept the URL scheme prefix.
116#if !defined(__APPLE__)
118#endif
119 socket_name = GetDomainSocketPath("gdbserver").GetPath();
120 url << socket_name;
121 error = StartDebugserverProcess(url.str(), debugserver_launch_info, &args);
122 } else {
124 return Status::FromErrorString("protocol must be tcp");
125 error = StartDebugserverProcess(fd, debugserver_launch_info, &args);
126 }
127
128 if (error.Success()) {
129 pid = debugserver_launch_info.GetProcessID();
131 LLDB_LOGF(log,
132 "GDBRemoteCommunicationServerPlatform::%s() "
133 "debugserver launched successfully as pid %" PRIu64,
134 __FUNCTION__, pid);
135 } else {
136 LLDB_LOGF(log,
137 "GDBRemoteCommunicationServerPlatform::%s() "
138 "debugserver launch failed: %s",
139 __FUNCTION__, error.AsCString());
140 }
141 return error;
142}
143
146 StringExtractorGDBRemote &packet) {
147 // Spawn a local debugserver as a platform so we can then attach or launch a
148 // process...
149
151 LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called",
152 __FUNCTION__);
153
154 ConnectionFileDescriptor file_conn;
155 packet.SetFilePos(::strlen("qLaunchGDBServer;"));
156 llvm::StringRef name;
157 llvm::StringRef value;
158 std::optional<uint16_t> port;
159 while (packet.GetNameColonValue(name, value)) {
160 if (name == "port") {
161 // Make the Optional valid so we can use its value
162 port = 0;
163 value.getAsInteger(BASE_10, *port);
164 }
165 }
166
167 // Ignore client's hostname and the port.
168
169 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
170 std::string socket_name;
171 Status error = LaunchGDBServer(Args(), debugserver_pid, socket_name,
173 if (error.Fail())
174 return SendErrorResponse(9); // EBADF
175
176 StreamGDBRemote response;
177 uint16_t gdbserver_port = socket_name.empty() ? m_gdbserver_port : 0;
178 response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, gdbserver_port);
179 if (!socket_name.empty()) {
180 response.PutCString("socket_name:");
181 response.PutStringAsRawHex8(socket_name);
182 response.PutChar(';');
183 }
184
185 PacketResult packet_result = SendPacketNoLock(response.GetString());
186 if (packet_result != PacketResult::Success) {
187 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
188 Host::Kill(debugserver_pid, SIGINT);
189 }
190 return packet_result;
191}
192
195 StringExtractorGDBRemote &packet) {
196 namespace json = llvm::json;
197
199 return SendErrorResponse(4);
200
201 json::Object server{{"port", m_pending_gdb_server_socket_name->empty()
203 : 0}};
204
206 server.try_emplace("socket_name", *m_pending_gdb_server_socket_name);
207
208 json::Array server_list;
209 server_list.push_back(std::move(server));
210
211 StreamGDBRemote response;
212 response.AsRawOstream() << std::move(server_list);
213
214 StreamGDBRemote escaped_response;
215 escaped_response.PutEscapedBytes(response.GetString().data(),
216 response.GetSize());
217 return SendPacketNoLock(escaped_response.GetString());
218}
219
222 StringExtractorGDBRemote &packet) {
223 packet.SetFilePos(::strlen("qKillSpawnedProcess:"));
224
226
227 // verify that we know anything about this pid.
228 if (!SpawnedProcessIsRunning(pid)) {
229 // not a pid we know about
230 return SendErrorResponse(10);
231 }
232
233 // go ahead and attempt to kill the spawned process
234 if (KillSpawnedProcess(pid))
235 return SendOKResponse();
236 else
237 return SendErrorResponse(11);
238}
239
241 assert(pid != LLDB_INVALID_PROCESS_ID);
242 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
243 m_spawned_pids.insert(pid);
244}
245
247 lldb::pid_t pid) {
248 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
249 return (m_spawned_pids.find(pid) != m_spawned_pids.end());
250}
251
253 // make sure we know about this process
254 if (!SpawnedProcessIsRunning(pid)) {
255 // it seems the process has been finished recently
256 return true;
257 }
258
259 // first try a SIGTERM (standard kill)
260 Host::Kill(pid, SIGTERM);
261
262 // check if that worked
263 for (size_t i = 0; i < 10; ++i) {
264 if (!SpawnedProcessIsRunning(pid)) {
265 // it is now killed
266 return true;
267 }
268 std::this_thread::sleep_for(std::chrono::milliseconds(10));
269 }
270
271 if (!SpawnedProcessIsRunning(pid))
272 return true;
273
274 // the launched process still lives. Now try killing it again, this time
275 // with an unblockable signal.
276 Host::Kill(pid, SIGKILL);
277
278 for (size_t i = 0; i < 10; ++i) {
279 if (!SpawnedProcessIsRunning(pid)) {
280 // it is now killed
281 return true;
282 }
283 std::this_thread::sleep_for(std::chrono::milliseconds(10));
284 }
285
286 // check one more time after the final sleep
287 return !SpawnedProcessIsRunning(pid);
288}
289
292 StringExtractorGDBRemote &packet) {
293 lldb::pid_t pid = m_process_launch_info.GetProcessID();
294 m_process_launch_info.Clear();
295
296 if (pid == LLDB_INVALID_PROCESS_ID)
297 return SendErrorResponse(1);
298
299 ProcessInstanceInfo proc_info;
300 if (!Host::GetProcessInfo(pid, proc_info))
301 return SendErrorResponse(1);
302
303 StreamString response;
305 return SendPacketNoLock(response.GetString());
306}
307
310 StringExtractorGDBRemote &packet) {
311 packet.SetFilePos(::strlen("qPathComplete:"));
312 const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
313 if (packet.GetChar() != ',')
314 return SendErrorResponse(85);
315 std::string path;
316 packet.GetHexByteString(path);
317
318 StringList matches;
320 if (only_dir)
321 CommandCompletions::DiskDirectories(path, matches, resolver);
322 else
323 CommandCompletions::DiskFiles(path, matches, resolver);
324
325 StreamString response;
326 response.PutChar('M');
327 llvm::StringRef separator;
328 std::sort(matches.begin(), matches.end());
329 for (const auto &match : matches) {
330 response << separator;
331 separator = ",";
332 // encode result strings into hex bytes to avoid unexpected error caused by
333 // special characters like '$'.
334 response.PutStringAsRawHex8(match.c_str());
335 }
336
337 return SendPacketNoLock(response.GetString());
338}
339
342 StringExtractorGDBRemote &packet) {
343
344 llvm::SmallString<64> cwd;
345 if (std::error_code ec = llvm::sys::fs::current_path(cwd))
346 return SendErrorResponse(ec.value());
347
348 StreamString response;
349 response.PutBytesAsRawHex8(cwd.data(), cwd.size());
350 return SendPacketNoLock(response.GetString());
351}
352
355 StringExtractorGDBRemote &packet) {
356 packet.SetFilePos(::strlen("QSetWorkingDir:"));
357 std::string path;
358 packet.GetHexByteString(path);
359
360 if (std::error_code ec = llvm::sys::fs::set_current_path(path))
361 return SendErrorResponse(ec.value());
362 return SendOKResponse();
363}
364
367 StringExtractorGDBRemote &packet) {
368 // NOTE: lldb should now be using qProcessInfo for process IDs. This path
369 // here
370 // should not be used. It is reporting process id instead of thread id. The
371 // correct answer doesn't seem to make much sense for lldb-platform.
372 // CONSIDER: flip to "unsupported".
373 lldb::pid_t pid = m_process_launch_info.GetProcessID();
374
375 StreamString response;
376 response.Printf("QC%" PRIx64, pid);
377
378 // If we launch a process and this GDB server is acting as a platform, then
379 // we need to clear the process launch state so we can start launching
380 // another process. In order to launch a process a bunch or packets need to
381 // be sent: environment packets, working directory, disable ASLR, and many
382 // more settings. When we launch a process we then need to know when to clear
383 // this information. Currently we are selecting the 'qC' packet as that
384 // packet which seems to make the most sense.
385 if (pid != LLDB_INVALID_PROCESS_ID) {
386 m_process_launch_info.Clear();
387 }
388
389 return SendPacketNoLock(response.GetString());
390}
391
393 lldb::pid_t pid) {
394 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
395 m_spawned_pids.erase(pid);
396}
397
399 if (!m_process_launch_info.GetArguments().GetArgumentCount())
401 "%s: no process command line specified to launch", __FUNCTION__);
402
403 // specify the process monitor if not already set. This should generally be
404 // what happens since we need to reap started processes.
405 if (!m_process_launch_info.GetMonitorProcessCallback())
406 m_process_launch_info.SetMonitorProcessCallback(std::bind(
408 std::placeholders::_1));
409
411 if (!error.Success()) {
412 fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
413 m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
414 return error;
415 }
416
417 printf("Launched '%s' as process %" PRIu64 "...\n",
418 m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
419 m_process_launch_info.GetProcessID());
420
421 // add to list of spawned processes. On an lldb-gdbserver, we would expect
422 // there to be only one.
423 const auto pid = m_process_launch_info.GetProcessID();
425
426 return error;
427}
428
430 static FileSpec g_domainsocket_dir;
431 static llvm::once_flag g_once_flag;
432
433 llvm::call_once(g_once_flag, []() {
434 const char *domainsocket_dir_env =
435 ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
436 if (domainsocket_dir_env != nullptr)
437 g_domainsocket_dir = FileSpec(domainsocket_dir_env);
438 else
439 g_domainsocket_dir = HostInfo::GetProcessTempDir();
440 });
441
442 return g_domainsocket_dir;
443}
444
447 llvm::SmallString<128> socket_path;
448 llvm::SmallString<128> socket_name(
449 (llvm::StringRef(prefix) + ".%%%%%%").str());
450
451 FileSpec socket_path_spec(GetDomainSocketDir());
452 socket_path_spec.AppendPathComponent(socket_name.c_str());
453
454 llvm::sys::fs::createUniqueFile(socket_path_spec.GetPath().c_str(),
455 socket_path);
456 return FileSpec(socket_path.c_str());
457}
458
460 const std::string &socket_name) {
462}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:389
void SetFilePos(uint32_t idx)
uint32_t GetHexMaxU32(bool little_endian, uint32_t fail_value)
bool GetNameColonValue(llvm::StringRef &name, llvm::StringRef &value)
uint64_t GetU64(uint64_t fail_value, int base=0)
size_t GetHexByteString(std::string &str)
char GetChar(char fail_value='\0')
A command line argument class.
Definition Args.h:33
static void DiskDirectories(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher)
static void DiskFiles(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher)
A file utility class.
Definition FileSpec.h:56
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:454
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
static FileSystem & Instance()
static Status LaunchProcess(ProcessLaunchInfo &launch_info)
Launch the process specified in launch_info.
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
Definition aix/Host.cpp:211
static void Kill(lldb::pid_t pid, int signo)
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
lldb::pid_t GetProcessID() const
Definition ProcessInfo.h:66
void SetMonitorProcessCallback(Host::MonitorChildProcessCallback callback)
void SetLaunchInSeparateProcessGroup(bool separate)
static const shared_fd_t kInvalidFD
Definition Socket.h:50
static const char * FindSchemeByProtocol(const SocketProtocol protocol)
Definition Socket.cpp:151
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
int PutEscapedBytes(const void *s, size_t src_len)
Output a block of data to the stream performing GDB-remote escaping.
Definition GDBRemote.cpp:31
llvm::StringRef GetString() const
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
size_t PutStringAsRawHex8(llvm::StringRef s)
Definition Stream.cpp:418
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
size_t PutChar(char ch)
Definition Stream.cpp:131
size_t PutBytesAsRawHex8(const void *src, size_t src_len, lldb::ByteOrder src_byte_order=lldb::eByteOrderInvalid, lldb::ByteOrder dst_byte_order=lldb::eByteOrderInvalid)
Definition Stream.cpp:391
void RegisterMemberFunctionHandler(StringExtractorGDBRemote::ServerPacketType packet_type, PacketResult(T::*handler)(StringExtractorGDBRemote &packet))
static void CreateProcessInfoResponse_DebugServerStyle(const ProcessInstanceInfo &proc_info, StreamString &response)
Status LaunchGDBServer(const lldb_private::Args &args, lldb::pid_t &pid, std::string &socket_name, shared_fd_t fd)
Status LaunchProcess() override
Launch a process with the current launch settings.
GDBRemoteCommunicationServerPlatform(FileSpec debugserver_path, const Socket::SocketProtocol socket_protocol, uint16_t gdbserver_port)
void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, PacketHandler handler)
static Status StartDebugserverProcess(std::variant< llvm::StringRef, shared_fd_t > comm, ProcessLaunchInfo &launch_info, const Args *inferior_args)
#define LLDB_INVALID_PROCESS_ID
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
NativeSocket shared_fd_t
Definition Socket.h:42
uint64_t pid_t
Definition lldb-types.h:84
#define SIGKILL