xref: /llvm-project/lldb/tools/lldb-server/lldb-platform.cpp (revision 98b419ca7688aa2823df1e87f58051aaa8d9c37f)
1 //===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
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 <cerrno>
10 #if defined(__APPLE__)
11 #include <netinet/in.h>
12 #endif
13 #include <csignal>
14 #include <cstdint>
15 #include <cstdio>
16 #include <cstdlib>
17 #include <cstring>
18 #if !defined(_WIN32)
19 #include <sys/wait.h>
20 #endif
21 #include <fstream>
22 #include <optional>
23 
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"
28 
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"
38 #if LLDB_ENABLE_POSIX
39 #include "lldb/Host/posix/DomainSocket.h"
40 #endif
41 #include "lldb/Utility/FileSpec.h"
42 #include "lldb/Utility/LLDBLog.h"
43 #include "lldb/Utility/Status.h"
44 #include "lldb/Utility/UriParser.h"
45 
46 using namespace lldb;
47 using namespace lldb_private;
48 using namespace lldb_private::lldb_server;
49 using namespace lldb_private::process_gdb_remote;
50 using namespace llvm;
51 
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;
60 
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}};
75 
76 #if defined(__APPLE__)
77 #define LOW_PORT (IPPORT_RESERVED)
78 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
79 #else
80 #define LOW_PORT (1024u)
81 #define HIGH_PORT (49151u)
82 #endif
83 
84 #if !defined(_WIN32)
85 // Watch for signals
86 static void signal_handler(int signo) {
87   switch (signo) {
88   case SIGHUP:
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
92     // running.
93     llvm::errs() << "SIGHUP received, exiting lldb-server...\n";
94     abort();
95     break;
96   }
97 }
98 #endif
99 
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 "
103                   "--listen port\n",
104           progname, subcommand);
105   exit(0);
106 }
107 
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());
120     }
121     if (protocol == Socket::ProtocolTcp) {
122       hostname = uri->hostname;
123       if (uri->port) {
124         platform_port = *(uri->port);
125       }
126     } else
127       address = listen_host_port.substr(uri->scheme.size() + strlen("://"));
128   } else {
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;
136     } else
137       address = listen_host_port;
138   }
139 
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);
144     }
145     address = llvm::formatv("[{0}]:{1}", hostname, platform_port).str();
146     gdb_address = llvm::formatv("[{0}]:{1}", hostname, gdbserver_port).str();
147   } else {
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));
152     }
153   }
154   return Status();
155 }
156 
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()));
161   if (error.Fail())
162     return Status::FromErrorStringWithFormat(
163         "Failed to create directory %s: %s", temp_file_spec.GetPath().c_str(),
164         error.AsCString());
165 
166   Status status;
167   if (auto Err = llvm::writeToOutput(file_spec.GetPath(),
168                                      [&socket_id](llvm::raw_ostream &OS) {
169                                        OS << socket_id;
170                                        return llvm::Error::success();
171                                      }))
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());
175   return status;
176 }
177 
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)
182     return Status();
183 
184   gdb_sock = std::make_unique<TCPSocket>(
185       /*should_close=*/true, /*child_processes_inherit=*/false);
186   Status error = gdb_sock->Listen(gdb_address, backlog);
187   if (error.Fail())
188     return error;
189 
190   if (gdbserver_port == 0)
191     gdbserver_port = gdb_sock->GetLocalPortNumber();
192 
193   return Status();
194 }
195 
196 static llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
197 AcceptGdbConnectionsIfNeeded(const Socket::SocketProtocol protocol,
198                              std::unique_ptr<TCPSocket> &gdb_sock,
199                              MainLoop &main_loop, const uint16_t gdbserver_port,
200                              const lldb_private::Args &args) {
201   if (protocol != Socket::ProtocolTcp)
202     return std::vector<MainLoopBase::ReadHandleUP>();
203 
204   return gdb_sock->Accept(main_loop, [gdbserver_port,
205                                       &args](std::unique_ptr<Socket> sock_up) {
206     Log *log = GetLog(LLDBLog::Platform);
207     Status error;
208     SharedSocket shared_socket(sock_up.get(), error);
209     if (error.Fail()) {
210       LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", error.AsCString());
211       return;
212     }
213     lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID;
214     std::string socket_name;
215     GDBRemoteCommunicationServerPlatform platform(Socket::ProtocolTcp,
216                                                   gdbserver_port);
217     error = platform.LaunchGDBServer(args, child_pid, socket_name,
218                                      shared_socket.GetSendableFD());
219     if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) {
220       error = shared_socket.CompleteSending(child_pid);
221       if (error.Fail()) {
222         Host::Kill(child_pid, SIGTERM);
223         LLDB_LOGF(log, "gdbserver CompleteSending failed: %s",
224                   error.AsCString());
225         return;
226       }
227     }
228   });
229 }
230 
231 static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
232                           const lldb_private::Args &args) {
233   if (!platform.IsConnected())
234     return;
235 
236   if (args.GetArgumentCount() > 0) {
237     lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
238     std::string socket_name;
239     Status error = platform.LaunchGDBServer(args, pid, socket_name,
240                                             SharedSocket::kInvalidFD);
241     if (error.Success())
242       platform.SetPendingGdbServer(socket_name);
243     else
244       fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
245   }
246 
247   bool interrupt = false;
248   bool done = false;
249   Status error;
250   while (!interrupt && !done) {
251     if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,
252                                           done) !=
253         GDBRemoteCommunication::PacketResult::Success)
254       break;
255   }
256 
257   printf("Disconnected.\n");
258 }
259 
260 static Status spawn_process(const char *progname, const Socket *conn_socket,
261                             uint16_t gdb_port, const lldb_private::Args &args,
262                             const std::string &log_file,
263                             const StringRef log_channels, MainLoop &main_loop) {
264   Status error;
265   SharedSocket shared_socket(conn_socket, error);
266   if (error.Fail())
267     return error;
268 
269   ProcessLaunchInfo launch_info;
270 
271   FileSpec self_spec(progname, FileSpec::Style::native);
272   launch_info.SetExecutableFile(self_spec, true);
273   Args &self_args = launch_info.GetArguments();
274   self_args.AppendArgument(llvm::StringRef("platform"));
275   self_args.AppendArgument(llvm::StringRef("--child-platform-fd"));
276   self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD()));
277 #ifndef _WIN32
278   launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(),
279                                         (int)shared_socket.GetSendableFD());
280 #endif
281   if (gdb_port) {
282     self_args.AppendArgument(llvm::StringRef("--gdbserver-port"));
283     self_args.AppendArgument(llvm::to_string(gdb_port));
284   }
285   if (!log_file.empty()) {
286     self_args.AppendArgument(llvm::StringRef("--log-file"));
287     self_args.AppendArgument(log_file);
288   }
289   if (!log_channels.empty()) {
290     self_args.AppendArgument(llvm::StringRef("--log-channels"));
291     self_args.AppendArgument(log_channels);
292   }
293   if (args.GetArgumentCount() > 0) {
294     self_args.AppendArgument("--");
295     self_args.AppendArguments(args);
296   }
297 
298   launch_info.SetLaunchInSeparateProcessGroup(false);
299 
300   if (g_server)
301     launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
302   else
303     launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
304       main_loop.AddPendingCallback(
305           [](MainLoopBase &loop) { loop.RequestTermination(); });
306     });
307 
308   // Copy the current environment.
309   launch_info.GetEnvironment() = Host::GetEnvironment();
310 
311   launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
312 
313   // Close STDIN, STDOUT and STDERR.
314   launch_info.AppendCloseFileAction(STDIN_FILENO);
315   launch_info.AppendCloseFileAction(STDOUT_FILENO);
316   launch_info.AppendCloseFileAction(STDERR_FILENO);
317 
318   // Redirect STDIN, STDOUT and STDERR to "/dev/null".
319   launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
320   launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
321   launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
322 
323   std::string cmd;
324   self_args.GetCommandString(cmd);
325 
326   error = Host::LaunchProcess(launch_info);
327   if (error.Fail())
328     return error;
329 
330   lldb::pid_t child_pid = launch_info.GetProcessID();
331   if (child_pid == LLDB_INVALID_PROCESS_ID)
332     return Status::FromErrorString("invalid pid");
333 
334   LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}",
335            cmd, child_pid);
336 
337   error = shared_socket.CompleteSending(child_pid);
338   if (error.Fail()) {
339     Host::Kill(child_pid, SIGTERM);
340     return error;
341   }
342 
343   return Status();
344 }
345 
346 // main
347 int main_platform(int argc, char *argv[]) {
348   const char *progname = argv[0];
349   const char *subcommand = argv[1];
350   argc--;
351   argv++;
352 #if !defined(_WIN32)
353   signal(SIGPIPE, SIG_IGN);
354   signal(SIGHUP, signal_handler);
355 #endif
356   int long_option_index = 0;
357   Status error;
358   std::string listen_host_port;
359   int ch;
360 
361   std::string log_file;
362   StringRef
363       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
364 
365   shared_fd_t fd = SharedSocket::kInvalidFD;
366 
367   uint16_t gdbserver_port = 0;
368 
369   FileSpec socket_file;
370   bool show_usage = false;
371   int option_error = 0;
372 
373   std::string short_options(OptionParser::GetShortOptionString(g_long_options));
374 
375 #if __GLIBC__
376   optind = 0;
377 #else
378   optreset = 1;
379   optind = 1;
380 #endif
381 
382   while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
383                                 g_long_options, &long_option_index)) != -1) {
384     switch (ch) {
385     case 0: // Any optional that auto set themselves will return 0
386       break;
387 
388     case 'L':
389       listen_host_port.append(optarg);
390       break;
391 
392     case 'l': // Set Log File
393       if (optarg && optarg[0])
394         log_file.assign(optarg);
395       break;
396 
397     case 'c': // Log Channels
398       if (optarg && optarg[0])
399         log_channels = StringRef(optarg);
400       break;
401 
402     case 'f': // Socket file
403       if (optarg && optarg[0])
404         socket_file.SetFile(optarg, FileSpec::Style::native);
405       break;
406 
407     case 'P':
408     case 'm':
409     case 'M': {
410       uint16_t portnum;
411       if (!llvm::to_integer(optarg, portnum)) {
412         WithColor::error() << "invalid port number string " << optarg << "\n";
413         option_error = 2;
414         break;
415       }
416       // Note the condition gdbserver_port > HIGH_PORT is valid in case of using
417       // --child-platform-fd. Check gdbserver_port later.
418       if (ch == 'P')
419         gdbserver_port = portnum;
420       else if (gdbserver_port == 0)
421         gdbserver_port = portnum;
422     } break;
423 
424     case 2: {
425       uint64_t _fd;
426       if (!llvm::to_integer(optarg, _fd)) {
427         WithColor::error() << "invalid fd " << optarg << "\n";
428         option_error = 6;
429       } else
430         fd = (shared_fd_t)_fd;
431     } break;
432 
433     case 'h': /* fall-through is intentional */
434     case '?':
435       show_usage = true;
436       break;
437     }
438   }
439 
440   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
441     return -1;
442 
443   // Print usage and exit if no listening port is specified.
444   if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD)
445     show_usage = true;
446 
447   if (show_usage || option_error) {
448     display_usage(progname, subcommand);
449     exit(option_error);
450   }
451 
452   // Skip any options we consumed with getopt_long_only.
453   argc -= optind;
454   argv += optind;
455   lldb_private::Args inferior_arguments;
456   inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
457 
458   Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain;
459 
460   if (fd != SharedSocket::kInvalidFD) {
461     // Child process will handle the connection and exit.
462     if (gdbserver_port)
463       protocol = Socket::ProtocolTcp;
464 
465     Log *log = GetLog(LLDBLog::Platform);
466 
467     NativeSocket sockfd;
468     error = SharedSocket::GetNativeSocket(fd, sockfd);
469     if (error.Fail()) {
470       LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString());
471       return socket_error;
472     }
473 
474     GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port);
475     Socket *socket;
476     if (protocol == Socket::ProtocolTcp)
477       socket = new TCPSocket(sockfd, /*should_close=*/true,
478                              /*child_processes_inherit=*/false);
479     else {
480 #if LLDB_ENABLE_POSIX
481       socket = new DomainSocket(sockfd, /*should_close=*/true,
482                                 /*child_processes_inherit=*/false);
483 #else
484       WithColor::error() << "lldb-platform child: Unix domain sockets are not "
485                             "supported on this platform.";
486       return socket_error;
487 #endif
488     }
489     platform.SetConnection(
490         std::unique_ptr<Connection>(new ConnectionFileDescriptor(socket)));
491     client_handle(platform, inferior_arguments);
492     return 0;
493   }
494 
495   if (gdbserver_port != 0 &&
496       (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) {
497     WithColor::error() << llvm::formatv("Port number {0} is not in the "
498                                         "valid user port range of {1} - {2}\n",
499                                         gdbserver_port, LOW_PORT, HIGH_PORT);
500     return 1;
501   }
502 
503   std::string address;
504   std::string gdb_address;
505   uint16_t platform_port = 0;
506   error = parse_listen_host_port(protocol, listen_host_port, address,
507                                  platform_port, gdb_address, gdbserver_port);
508   if (error.Fail()) {
509     printf("Failed to parse listen address: %s\n", error.AsCString());
510     return socket_error;
511   }
512 
513   std::unique_ptr<Socket> platform_sock =
514       Socket::Create(protocol, /*child_processes_inherit=*/false, error);
515   if (error.Fail()) {
516     printf("Failed to create platform socket: %s\n", error.AsCString());
517     return socket_error;
518   }
519   error = platform_sock->Listen(address, backlog);
520   if (error.Fail()) {
521     printf("Failed to listen platform: %s\n", error.AsCString());
522     return socket_error;
523   }
524   if (protocol == Socket::ProtocolTcp && platform_port == 0)
525     platform_port =
526         static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber();
527 
528   if (socket_file) {
529     error = save_socket_id_to_file(
530         protocol == Socket::ProtocolTcp
531             ? (platform_port ? llvm::to_string(platform_port) : "")
532             : address,
533         socket_file);
534     if (error.Fail()) {
535       fprintf(stderr, "failed to write socket id to %s: %s\n",
536               socket_file.GetPath().c_str(), error.AsCString());
537       return 1;
538     }
539   }
540 
541   std::unique_ptr<TCPSocket> gdb_sock;
542   // Update gdbserver_port if it is still 0 and protocol is tcp.
543   error = ListenGdbConnectionsIfNeeded(protocol, gdb_sock, gdb_address,
544                                        gdbserver_port);
545   if (error.Fail()) {
546     printf("Failed to listen gdb: %s\n", error.AsCString());
547     return socket_error;
548   }
549 
550   MainLoop main_loop;
551   {
552     llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
553         platform_sock->Accept(
554             main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,
555                         log_channels, &main_loop,
556                         &platform_handles](std::unique_ptr<Socket> sock_up) {
557               printf("Connection established.\n");
558               Status error = spawn_process(progname, sock_up.get(),
559                                            gdbserver_port, inferior_arguments,
560                                            log_file, log_channels, main_loop);
561               if (error.Fail()) {
562                 Log *log = GetLog(LLDBLog::Platform);
563                 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
564                 WithColor::error()
565                     << "spawn_process failed: " << error.AsCString() << "\n";
566                 if (!g_server)
567                   main_loop.RequestTermination();
568               }
569               if (!g_server)
570                 platform_handles->clear();
571             });
572     if (!platform_handles) {
573       printf("Failed to accept platform: %s\n",
574              llvm::toString(platform_handles.takeError()).c_str());
575       return socket_error;
576     }
577 
578     llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles =
579         AcceptGdbConnectionsIfNeeded(protocol, gdb_sock, main_loop,
580                                      gdbserver_port, inferior_arguments);
581     if (!gdb_handles) {
582       printf("Failed to accept gdb: %s\n",
583              llvm::toString(gdb_handles.takeError()).c_str());
584       return socket_error;
585     }
586 
587     main_loop.Run();
588   }
589 
590   fprintf(stderr, "lldb-server exiting...\n");
591 
592   return 0;
593 }
594