1 //===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #if defined(__APPLE__)
11 #include <netinet/in.h>
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/ScopedPrinter.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
29 #include "LLDBServerUtilities.h"
30 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
31 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
32 #include "lldb/Host/ConnectionFileDescriptor.h"
33 #include "lldb/Host/HostGetOpt.h"
34 #include "lldb/Host/MainLoop.h"
35 #include "lldb/Host/OptionParser.h"
36 #include "lldb/Host/Socket.h"
37 #include "lldb/Host/common/TCPSocket.h"
39 #include "lldb/Host/posix/DomainSocket.h"
41 #include "lldb/Utility/FileSpec.h"
42 #include "lldb/Utility/LLDBLog.h"
43 #include "lldb/Utility/Status.h"
44 #include "lldb/Utility/UriParser.h"
47 using namespace lldb_private
;
48 using namespace lldb_private::lldb_server
;
49 using namespace lldb_private::process_gdb_remote
;
52 // The test suite makes many connections in parallel, let's not miss any.
53 // The highest this should get reasonably is a function of the number
54 // of target CPUs. For now, let's just use 100.
55 static const int backlog
= 100;
56 static const int socket_error
= -1;
57 static int g_debug
= 0;
58 static int g_verbose
= 0;
59 static int g_server
= 0;
61 // option descriptors for getopt_long_only()
62 static struct option g_long_options
[] = {
63 {"debug", no_argument
, &g_debug
, 1},
64 {"verbose", no_argument
, &g_verbose
, 1},
65 {"log-file", required_argument
, nullptr, 'l'},
66 {"log-channels", required_argument
, nullptr, 'c'},
67 {"listen", required_argument
, nullptr, 'L'},
68 {"gdbserver-port", required_argument
, nullptr, 'P'},
69 {"min-gdbserver-port", required_argument
, nullptr, 'm'},
70 {"max-gdbserver-port", required_argument
, nullptr, 'M'},
71 {"socket-file", required_argument
, nullptr, 'f'},
72 {"server", no_argument
, &g_server
, 1},
73 {"child-platform-fd", required_argument
, nullptr, 2},
74 {nullptr, 0, nullptr, 0}};
76 #if defined(__APPLE__)
77 #define LOW_PORT (IPPORT_RESERVED)
78 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
80 #define LOW_PORT (1024u)
81 #define HIGH_PORT (49151u)
86 static void signal_handler(int signo
) {
89 // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
90 // And we should not call exit() here because it results in the global
91 // destructors to be invoked and wreaking havoc on the threads still
93 llvm::errs() << "SIGHUP received, exiting lldb-server...\n";
100 static void display_usage(const char *progname
, const char *subcommand
) {
101 fprintf(stderr
, "Usage:\n %s %s [--log-file log-file-name] [--log-channels "
102 "log-channel-list] [--port-file port-file-path] --server "
104 progname
, subcommand
);
108 static Status
parse_listen_host_port(Socket::SocketProtocol
&protocol
,
109 const std::string
&listen_host_port
,
110 std::string
&address
,
111 uint16_t &platform_port
,
112 std::string
&gdb_address
,
113 const uint16_t gdbserver_port
) {
114 std::string hostname
;
115 // Try to match socket name as URL - e.g., tcp://localhost:5555
116 if (std::optional
<URI
> uri
= URI::Parse(listen_host_port
)) {
117 if (!Socket::FindProtocolByScheme(uri
->scheme
.str().c_str(), protocol
)) {
118 return Status::FromErrorStringWithFormat(
119 "Unknown protocol scheme \"%s\".", uri
->scheme
.str().c_str());
121 if (protocol
== Socket::ProtocolTcp
) {
122 hostname
= uri
->hostname
;
124 platform_port
= *(uri
->port
);
127 address
= listen_host_port
.substr(uri
->scheme
.size() + strlen("://"));
129 // Try to match socket name as $host:port - e.g., localhost:5555
130 llvm::Expected
<Socket::HostAndPort
> host_port
=
131 Socket::DecodeHostAndPort(listen_host_port
);
132 if (!llvm::errorToBool(host_port
.takeError())) {
133 protocol
= Socket::ProtocolTcp
;
134 hostname
= host_port
->hostname
;
135 platform_port
= host_port
->port
;
137 address
= listen_host_port
;
140 if (protocol
== Socket::ProtocolTcp
) {
141 if (platform_port
!= 0 && platform_port
== gdbserver_port
) {
142 return Status::FromErrorStringWithFormat(
143 "The same platform and gdb ports %u.", platform_port
);
145 address
= llvm::formatv("[{0}]:{1}", hostname
, platform_port
).str();
146 gdb_address
= llvm::formatv("[{0}]:{1}", hostname
, gdbserver_port
).str();
148 if (gdbserver_port
) {
149 return Status::FromErrorStringWithFormat(
150 "--gdbserver-port %u is redundant for non-tcp protocol %s.",
151 gdbserver_port
, Socket::FindSchemeByProtocol(protocol
));
157 static Status
save_socket_id_to_file(const std::string
&socket_id
,
158 const FileSpec
&file_spec
) {
159 FileSpec
temp_file_spec(file_spec
.GetDirectory().GetStringRef());
160 Status
error(llvm::sys::fs::create_directory(temp_file_spec
.GetPath()));
162 return Status::FromErrorStringWithFormat(
163 "Failed to create directory %s: %s", temp_file_spec
.GetPath().c_str(),
167 if (auto Err
= llvm::writeToOutput(file_spec
.GetPath(),
168 [&socket_id
](llvm::raw_ostream
&OS
) {
170 return llvm::Error::success();
172 return Status::FromErrorStringWithFormat(
173 "Failed to atomically write file %s: %s", file_spec
.GetPath().c_str(),
174 llvm::toString(std::move(Err
)).c_str());
178 static Status
ListenGdbConnectionsIfNeeded(
179 const Socket::SocketProtocol protocol
, std::unique_ptr
<TCPSocket
> &gdb_sock
,
180 const std::string
&gdb_address
, uint16_t &gdbserver_port
) {
181 if (protocol
!= Socket::ProtocolTcp
)
184 gdb_sock
= std::make_unique
<TCPSocket
>(/*should_close=*/true);
185 Status error
= gdb_sock
->Listen(gdb_address
, backlog
);
189 if (gdbserver_port
== 0)
190 gdbserver_port
= gdb_sock
->GetLocalPortNumber();
195 static llvm::Expected
<std::vector
<MainLoopBase::ReadHandleUP
>>
196 AcceptGdbConnectionsIfNeeded(const Socket::SocketProtocol protocol
,
197 std::unique_ptr
<TCPSocket
> &gdb_sock
,
198 MainLoop
&main_loop
, const uint16_t gdbserver_port
,
199 const lldb_private::Args
&args
) {
200 if (protocol
!= Socket::ProtocolTcp
)
201 return std::vector
<MainLoopBase::ReadHandleUP
>();
203 return gdb_sock
->Accept(main_loop
, [gdbserver_port
,
204 &args
](std::unique_ptr
<Socket
> sock_up
) {
205 Log
*log
= GetLog(LLDBLog::Platform
);
207 SharedSocket
shared_socket(sock_up
.get(), error
);
209 LLDB_LOGF(log
, "gdbserver SharedSocket failed: %s", error
.AsCString());
212 lldb::pid_t child_pid
= LLDB_INVALID_PROCESS_ID
;
213 std::string socket_name
;
214 GDBRemoteCommunicationServerPlatform
platform(Socket::ProtocolTcp
,
216 error
= platform
.LaunchGDBServer(args
, child_pid
, socket_name
,
217 shared_socket
.GetSendableFD());
218 if (error
.Success() && child_pid
!= LLDB_INVALID_PROCESS_ID
) {
219 error
= shared_socket
.CompleteSending(child_pid
);
221 Host::Kill(child_pid
, SIGTERM
);
222 LLDB_LOGF(log
, "gdbserver CompleteSending failed: %s",
230 static void client_handle(GDBRemoteCommunicationServerPlatform
&platform
,
231 const lldb_private::Args
&args
) {
232 if (!platform
.IsConnected())
235 if (args
.GetArgumentCount() > 0) {
236 lldb::pid_t pid
= LLDB_INVALID_PROCESS_ID
;
237 std::string socket_name
;
238 Status error
= platform
.LaunchGDBServer(args
, pid
, socket_name
,
239 SharedSocket::kInvalidFD
);
241 platform
.SetPendingGdbServer(socket_name
);
243 fprintf(stderr
, "failed to start gdbserver: %s\n", error
.AsCString());
246 bool interrupt
= false;
249 while (!interrupt
&& !done
) {
250 if (platform
.GetPacketAndSendResponse(std::nullopt
, error
, interrupt
,
252 GDBRemoteCommunication::PacketResult::Success
)
256 printf("Disconnected.\n");
259 static Status
spawn_process(const char *progname
, const Socket
*conn_socket
,
260 uint16_t gdb_port
, const lldb_private::Args
&args
,
261 const std::string
&log_file
,
262 const StringRef log_channels
, MainLoop
&main_loop
) {
264 SharedSocket
shared_socket(conn_socket
, error
);
268 ProcessLaunchInfo launch_info
;
270 FileSpec
self_spec(progname
, FileSpec::Style::native
);
271 launch_info
.SetExecutableFile(self_spec
, true);
272 Args
&self_args
= launch_info
.GetArguments();
273 self_args
.AppendArgument(llvm::StringRef("platform"));
274 self_args
.AppendArgument(llvm::StringRef("--child-platform-fd"));
275 self_args
.AppendArgument(llvm::to_string(shared_socket
.GetSendableFD()));
277 launch_info
.AppendDuplicateFileAction((int)shared_socket
.GetSendableFD(),
278 (int)shared_socket
.GetSendableFD());
281 self_args
.AppendArgument(llvm::StringRef("--gdbserver-port"));
282 self_args
.AppendArgument(llvm::to_string(gdb_port
));
284 if (!log_file
.empty()) {
285 self_args
.AppendArgument(llvm::StringRef("--log-file"));
286 self_args
.AppendArgument(log_file
);
288 if (!log_channels
.empty()) {
289 self_args
.AppendArgument(llvm::StringRef("--log-channels"));
290 self_args
.AppendArgument(log_channels
);
292 if (args
.GetArgumentCount() > 0) {
293 self_args
.AppendArgument("--");
294 self_args
.AppendArguments(args
);
297 launch_info
.SetLaunchInSeparateProcessGroup(false);
300 launch_info
.SetMonitorProcessCallback([](lldb::pid_t
, int, int) {});
302 launch_info
.SetMonitorProcessCallback([&main_loop
](lldb::pid_t
, int, int) {
303 main_loop
.AddPendingCallback(
304 [](MainLoopBase
&loop
) { loop
.RequestTermination(); });
307 // Copy the current environment.
308 launch_info
.GetEnvironment() = Host::GetEnvironment();
310 launch_info
.GetFlags().Set(eLaunchFlagDisableSTDIO
);
312 // Close STDIN, STDOUT and STDERR.
313 launch_info
.AppendCloseFileAction(STDIN_FILENO
);
314 launch_info
.AppendCloseFileAction(STDOUT_FILENO
);
315 launch_info
.AppendCloseFileAction(STDERR_FILENO
);
317 // Redirect STDIN, STDOUT and STDERR to "/dev/null".
318 launch_info
.AppendSuppressFileAction(STDIN_FILENO
, true, false);
319 launch_info
.AppendSuppressFileAction(STDOUT_FILENO
, false, true);
320 launch_info
.AppendSuppressFileAction(STDERR_FILENO
, false, true);
323 self_args
.GetCommandString(cmd
);
325 error
= Host::LaunchProcess(launch_info
);
329 lldb::pid_t child_pid
= launch_info
.GetProcessID();
330 if (child_pid
== LLDB_INVALID_PROCESS_ID
)
331 return Status::FromErrorString("invalid pid");
333 LLDB_LOG(GetLog(LLDBLog::Platform
), "lldb-platform launched '{0}', pid={1}",
336 error
= shared_socket
.CompleteSending(child_pid
);
338 Host::Kill(child_pid
, SIGTERM
);
346 int main_platform(int argc
, char *argv
[]) {
347 const char *progname
= argv
[0];
348 const char *subcommand
= argv
[1];
352 signal(SIGPIPE
, SIG_IGN
);
353 signal(SIGHUP
, signal_handler
);
355 int long_option_index
= 0;
357 std::string listen_host_port
;
360 std::string log_file
;
362 log_channels
; // e.g. "lldb process threads:gdb-remote default:linux all"
364 shared_fd_t fd
= SharedSocket::kInvalidFD
;
366 uint16_t gdbserver_port
= 0;
368 FileSpec socket_file
;
369 bool show_usage
= false;
370 int option_error
= 0;
372 std::string
short_options(OptionParser::GetShortOptionString(g_long_options
));
381 while ((ch
= getopt_long_only(argc
, argv
, short_options
.c_str(),
382 g_long_options
, &long_option_index
)) != -1) {
384 case 0: // Any optional that auto set themselves will return 0
388 listen_host_port
.append(optarg
);
391 case 'l': // Set Log File
392 if (optarg
&& optarg
[0])
393 log_file
.assign(optarg
);
396 case 'c': // Log Channels
397 if (optarg
&& optarg
[0])
398 log_channels
= StringRef(optarg
);
401 case 'f': // Socket file
402 if (optarg
&& optarg
[0])
403 socket_file
.SetFile(optarg
, FileSpec::Style::native
);
410 if (!llvm::to_integer(optarg
, portnum
)) {
411 WithColor::error() << "invalid port number string " << optarg
<< "\n";
415 // Note the condition gdbserver_port > HIGH_PORT is valid in case of using
416 // --child-platform-fd. Check gdbserver_port later.
418 gdbserver_port
= portnum
;
419 else if (gdbserver_port
== 0)
420 gdbserver_port
= portnum
;
425 if (!llvm::to_integer(optarg
, _fd
)) {
426 WithColor::error() << "invalid fd " << optarg
<< "\n";
429 fd
= (shared_fd_t
)_fd
;
432 case 'h': /* fall-through is intentional */
439 if (!LLDBServerUtilities::SetupLogging(log_file
, log_channels
, 0))
442 // Print usage and exit if no listening port is specified.
443 if (listen_host_port
.empty() && fd
== SharedSocket::kInvalidFD
)
446 if (show_usage
|| option_error
) {
447 display_usage(progname
, subcommand
);
451 // Skip any options we consumed with getopt_long_only.
454 lldb_private::Args inferior_arguments
;
455 inferior_arguments
.SetArguments(argc
, const_cast<const char **>(argv
));
457 Socket::SocketProtocol protocol
= Socket::ProtocolUnixDomain
;
459 if (fd
!= SharedSocket::kInvalidFD
) {
460 // Child process will handle the connection and exit.
462 protocol
= Socket::ProtocolTcp
;
464 Log
*log
= GetLog(LLDBLog::Platform
);
467 error
= SharedSocket::GetNativeSocket(fd
, sockfd
);
469 LLDB_LOGF(log
, "lldb-platform child: %s", error
.AsCString());
473 GDBRemoteCommunicationServerPlatform
platform(protocol
, gdbserver_port
);
475 if (protocol
== Socket::ProtocolTcp
)
476 socket
= new TCPSocket(sockfd
, /*should_close=*/true);
478 #if LLDB_ENABLE_POSIX
479 socket
= new DomainSocket(sockfd
, /*should_close=*/true);
481 WithColor::error() << "lldb-platform child: Unix domain sockets are not "
482 "supported on this platform.";
486 platform
.SetConnection(
487 std::unique_ptr
<Connection
>(new ConnectionFileDescriptor(socket
)));
488 client_handle(platform
, inferior_arguments
);
492 if (gdbserver_port
!= 0 &&
493 (gdbserver_port
< LOW_PORT
|| gdbserver_port
> HIGH_PORT
)) {
494 WithColor::error() << llvm::formatv("Port number {0} is not in the "
495 "valid user port range of {1} - {2}\n",
496 gdbserver_port
, LOW_PORT
, HIGH_PORT
);
501 std::string gdb_address
;
502 uint16_t platform_port
= 0;
503 error
= parse_listen_host_port(protocol
, listen_host_port
, address
,
504 platform_port
, gdb_address
, gdbserver_port
);
506 printf("Failed to parse listen address: %s\n", error
.AsCString());
510 std::unique_ptr
<Socket
> platform_sock
= Socket::Create(protocol
, error
);
512 printf("Failed to create platform socket: %s\n", error
.AsCString());
515 error
= platform_sock
->Listen(address
, backlog
);
517 printf("Failed to listen platform: %s\n", error
.AsCString());
520 if (protocol
== Socket::ProtocolTcp
&& platform_port
== 0)
522 static_cast<TCPSocket
*>(platform_sock
.get())->GetLocalPortNumber();
525 error
= save_socket_id_to_file(
526 protocol
== Socket::ProtocolTcp
527 ? (platform_port
? llvm::to_string(platform_port
) : "")
531 fprintf(stderr
, "failed to write socket id to %s: %s\n",
532 socket_file
.GetPath().c_str(), error
.AsCString());
537 std::unique_ptr
<TCPSocket
> gdb_sock
;
538 // Update gdbserver_port if it is still 0 and protocol is tcp.
539 error
= ListenGdbConnectionsIfNeeded(protocol
, gdb_sock
, gdb_address
,
542 printf("Failed to listen gdb: %s\n", error
.AsCString());
548 llvm::Expected
<std::vector
<MainLoopBase::ReadHandleUP
>> platform_handles
=
549 platform_sock
->Accept(
550 main_loop
, [progname
, gdbserver_port
, &inferior_arguments
, log_file
,
551 log_channels
, &main_loop
,
552 &platform_handles
](std::unique_ptr
<Socket
> sock_up
) {
553 printf("Connection established.\n");
554 Status error
= spawn_process(progname
, sock_up
.get(),
555 gdbserver_port
, inferior_arguments
,
556 log_file
, log_channels
, main_loop
);
558 Log
*log
= GetLog(LLDBLog::Platform
);
559 LLDB_LOGF(log
, "spawn_process failed: %s", error
.AsCString());
561 << "spawn_process failed: " << error
.AsCString() << "\n";
563 main_loop
.RequestTermination();
566 platform_handles
->clear();
568 if (!platform_handles
) {
569 printf("Failed to accept platform: %s\n",
570 llvm::toString(platform_handles
.takeError()).c_str());
574 llvm::Expected
<std::vector
<MainLoopBase::ReadHandleUP
>> gdb_handles
=
575 AcceptGdbConnectionsIfNeeded(protocol
, gdb_sock
, main_loop
,
576 gdbserver_port
, inferior_arguments
);
578 printf("Failed to accept gdb: %s\n",
579 llvm::toString(gdb_handles
.takeError()).c_str());
586 fprintf(stderr
, "lldb-server exiting...\n");