xref: /llvm-project/lldb/tools/lldb-server/lldb-platform.cpp (revision c1dff7152592f1beee9059ee8e2cb3cc68baea4d)
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>(/*should_close=*/true);
185   Status error = gdb_sock->Listen(gdb_address, backlog);
186   if (error.Fail())
187     return error;
188 
189   if (gdbserver_port == 0)
190     gdbserver_port = gdb_sock->GetLocalPortNumber();
191 
192   return Status();
193 }
194 
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>();
202 
203   return gdb_sock->Accept(main_loop, [gdbserver_port,
204                                       &args](std::unique_ptr<Socket> sock_up) {
205     Log *log = GetLog(LLDBLog::Platform);
206     Status error;
207     SharedSocket shared_socket(sock_up.get(), error);
208     if (error.Fail()) {
209       LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", error.AsCString());
210       return;
211     }
212     lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID;
213     std::string socket_name;
214     GDBRemoteCommunicationServerPlatform platform(Socket::ProtocolTcp,
215                                                   gdbserver_port);
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);
220       if (error.Fail()) {
221         Host::Kill(child_pid, SIGTERM);
222         LLDB_LOGF(log, "gdbserver CompleteSending failed: %s",
223                   error.AsCString());
224         return;
225       }
226     }
227   });
228 }
229 
230 static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
231                           const lldb_private::Args &args) {
232   if (!platform.IsConnected())
233     return;
234 
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);
240     if (error.Success())
241       platform.SetPendingGdbServer(socket_name);
242     else
243       fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
244   }
245 
246   bool interrupt = false;
247   bool done = false;
248   Status error;
249   while (!interrupt && !done) {
250     if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,
251                                           done) !=
252         GDBRemoteCommunication::PacketResult::Success)
253       break;
254   }
255 
256   printf("Disconnected.\n");
257 }
258 
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) {
263   Status error;
264   SharedSocket shared_socket(conn_socket, error);
265   if (error.Fail())
266     return error;
267 
268   ProcessLaunchInfo launch_info;
269 
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()));
276 #ifndef _WIN32
277   launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(),
278                                         (int)shared_socket.GetSendableFD());
279 #endif
280   if (gdb_port) {
281     self_args.AppendArgument(llvm::StringRef("--gdbserver-port"));
282     self_args.AppendArgument(llvm::to_string(gdb_port));
283   }
284   if (!log_file.empty()) {
285     self_args.AppendArgument(llvm::StringRef("--log-file"));
286     self_args.AppendArgument(log_file);
287   }
288   if (!log_channels.empty()) {
289     self_args.AppendArgument(llvm::StringRef("--log-channels"));
290     self_args.AppendArgument(log_channels);
291   }
292   if (args.GetArgumentCount() > 0) {
293     self_args.AppendArgument("--");
294     self_args.AppendArguments(args);
295   }
296 
297   launch_info.SetLaunchInSeparateProcessGroup(false);
298 
299   if (g_server)
300     launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
301   else
302     launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
303       main_loop.AddPendingCallback(
304           [](MainLoopBase &loop) { loop.RequestTermination(); });
305     });
306 
307   // Copy the current environment.
308   launch_info.GetEnvironment() = Host::GetEnvironment();
309 
310   launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
311 
312   // Close STDIN, STDOUT and STDERR.
313   launch_info.AppendCloseFileAction(STDIN_FILENO);
314   launch_info.AppendCloseFileAction(STDOUT_FILENO);
315   launch_info.AppendCloseFileAction(STDERR_FILENO);
316 
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);
321 
322   std::string cmd;
323   self_args.GetCommandString(cmd);
324 
325   error = Host::LaunchProcess(launch_info);
326   if (error.Fail())
327     return error;
328 
329   lldb::pid_t child_pid = launch_info.GetProcessID();
330   if (child_pid == LLDB_INVALID_PROCESS_ID)
331     return Status::FromErrorString("invalid pid");
332 
333   LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}",
334            cmd, child_pid);
335 
336   error = shared_socket.CompleteSending(child_pid);
337   if (error.Fail()) {
338     Host::Kill(child_pid, SIGTERM);
339     return error;
340   }
341 
342   return Status();
343 }
344 
345 // main
346 int main_platform(int argc, char *argv[]) {
347   const char *progname = argv[0];
348   const char *subcommand = argv[1];
349   argc--;
350   argv++;
351 #if !defined(_WIN32)
352   signal(SIGPIPE, SIG_IGN);
353   signal(SIGHUP, signal_handler);
354 #endif
355   int long_option_index = 0;
356   Status error;
357   std::string listen_host_port;
358   int ch;
359 
360   std::string log_file;
361   StringRef
362       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
363 
364   shared_fd_t fd = SharedSocket::kInvalidFD;
365 
366   uint16_t gdbserver_port = 0;
367 
368   FileSpec socket_file;
369   bool show_usage = false;
370   int option_error = 0;
371 
372   std::string short_options(OptionParser::GetShortOptionString(g_long_options));
373 
374 #if __GLIBC__
375   optind = 0;
376 #else
377   optreset = 1;
378   optind = 1;
379 #endif
380 
381   while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
382                                 g_long_options, &long_option_index)) != -1) {
383     switch (ch) {
384     case 0: // Any optional that auto set themselves will return 0
385       break;
386 
387     case 'L':
388       listen_host_port.append(optarg);
389       break;
390 
391     case 'l': // Set Log File
392       if (optarg && optarg[0])
393         log_file.assign(optarg);
394       break;
395 
396     case 'c': // Log Channels
397       if (optarg && optarg[0])
398         log_channels = StringRef(optarg);
399       break;
400 
401     case 'f': // Socket file
402       if (optarg && optarg[0])
403         socket_file.SetFile(optarg, FileSpec::Style::native);
404       break;
405 
406     case 'P':
407     case 'm':
408     case 'M': {
409       uint16_t portnum;
410       if (!llvm::to_integer(optarg, portnum)) {
411         WithColor::error() << "invalid port number string " << optarg << "\n";
412         option_error = 2;
413         break;
414       }
415       // Note the condition gdbserver_port > HIGH_PORT is valid in case of using
416       // --child-platform-fd. Check gdbserver_port later.
417       if (ch == 'P')
418         gdbserver_port = portnum;
419       else if (gdbserver_port == 0)
420         gdbserver_port = portnum;
421     } break;
422 
423     case 2: {
424       uint64_t _fd;
425       if (!llvm::to_integer(optarg, _fd)) {
426         WithColor::error() << "invalid fd " << optarg << "\n";
427         option_error = 6;
428       } else
429         fd = (shared_fd_t)_fd;
430     } break;
431 
432     case 'h': /* fall-through is intentional */
433     case '?':
434       show_usage = true;
435       break;
436     }
437   }
438 
439   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
440     return -1;
441 
442   // Print usage and exit if no listening port is specified.
443   if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD)
444     show_usage = true;
445 
446   if (show_usage || option_error) {
447     display_usage(progname, subcommand);
448     exit(option_error);
449   }
450 
451   // Skip any options we consumed with getopt_long_only.
452   argc -= optind;
453   argv += optind;
454   lldb_private::Args inferior_arguments;
455   inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
456 
457   Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain;
458 
459   if (fd != SharedSocket::kInvalidFD) {
460     // Child process will handle the connection and exit.
461     if (gdbserver_port)
462       protocol = Socket::ProtocolTcp;
463 
464     Log *log = GetLog(LLDBLog::Platform);
465 
466     NativeSocket sockfd;
467     error = SharedSocket::GetNativeSocket(fd, sockfd);
468     if (error.Fail()) {
469       LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString());
470       return socket_error;
471     }
472 
473     GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port);
474     Socket *socket;
475     if (protocol == Socket::ProtocolTcp)
476       socket = new TCPSocket(sockfd, /*should_close=*/true);
477     else {
478 #if LLDB_ENABLE_POSIX
479       socket = new DomainSocket(sockfd, /*should_close=*/true);
480 #else
481       WithColor::error() << "lldb-platform child: Unix domain sockets are not "
482                             "supported on this platform.";
483       return socket_error;
484 #endif
485     }
486     platform.SetConnection(
487         std::unique_ptr<Connection>(new ConnectionFileDescriptor(socket)));
488     client_handle(platform, inferior_arguments);
489     return 0;
490   }
491 
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);
497     return 1;
498   }
499 
500   std::string address;
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);
505   if (error.Fail()) {
506     printf("Failed to parse listen address: %s\n", error.AsCString());
507     return socket_error;
508   }
509 
510   std::unique_ptr<Socket> platform_sock = Socket::Create(protocol, error);
511   if (error.Fail()) {
512     printf("Failed to create platform socket: %s\n", error.AsCString());
513     return socket_error;
514   }
515   error = platform_sock->Listen(address, backlog);
516   if (error.Fail()) {
517     printf("Failed to listen platform: %s\n", error.AsCString());
518     return socket_error;
519   }
520   if (protocol == Socket::ProtocolTcp && platform_port == 0)
521     platform_port =
522         static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber();
523 
524   if (socket_file) {
525     error = save_socket_id_to_file(
526         protocol == Socket::ProtocolTcp
527             ? (platform_port ? llvm::to_string(platform_port) : "")
528             : address,
529         socket_file);
530     if (error.Fail()) {
531       fprintf(stderr, "failed to write socket id to %s: %s\n",
532               socket_file.GetPath().c_str(), error.AsCString());
533       return 1;
534     }
535   }
536 
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,
540                                        gdbserver_port);
541   if (error.Fail()) {
542     printf("Failed to listen gdb: %s\n", error.AsCString());
543     return socket_error;
544   }
545 
546   MainLoop main_loop;
547   {
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);
557               if (error.Fail()) {
558                 Log *log = GetLog(LLDBLog::Platform);
559                 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
560                 WithColor::error()
561                     << "spawn_process failed: " << error.AsCString() << "\n";
562                 if (!g_server)
563                   main_loop.RequestTermination();
564               }
565               if (!g_server)
566                 platform_handles->clear();
567             });
568     if (!platform_handles) {
569       printf("Failed to accept platform: %s\n",
570              llvm::toString(platform_handles.takeError()).c_str());
571       return socket_error;
572     }
573 
574     llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles =
575         AcceptGdbConnectionsIfNeeded(protocol, gdb_sock, main_loop,
576                                      gdbserver_port, inferior_arguments);
577     if (!gdb_handles) {
578       printf("Failed to accept gdb: %s\n",
579              llvm::toString(gdb_handles.takeError()).c_str());
580       return socket_error;
581     }
582 
583     main_loop.Run();
584   }
585 
586   fprintf(stderr, "lldb-server exiting...\n");
587 
588   return 0;
589 }
590