xref: /llvm-project/lldb/tools/lldb-server/lldb-platform.cpp (revision 82ee31f75ac1316006fa9e21dddfddec37cf7072)
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 "Acceptor.h"
30 #include "LLDBServerUtilities.h"
31 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
32 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
33 #include "lldb/Host/ConnectionFileDescriptor.h"
34 #include "lldb/Host/HostGetOpt.h"
35 #include "lldb/Host/OptionParser.h"
36 #include "lldb/Host/Socket.h"
37 #include "lldb/Host/common/TCPSocket.h"
38 #include "lldb/Utility/FileSpec.h"
39 #include "lldb/Utility/LLDBLog.h"
40 #include "lldb/Utility/Status.h"
41 
42 using namespace lldb;
43 using namespace lldb_private;
44 using namespace lldb_private::lldb_server;
45 using namespace lldb_private::process_gdb_remote;
46 using namespace llvm;
47 
48 // option descriptors for getopt_long_only()
49 
50 #ifdef _WIN32
51 typedef pipe_t shared_fd_t;
52 const shared_fd_t kInvalidSharedFD = LLDB_INVALID_PIPE;
53 #else
54 typedef NativeSocket shared_fd_t;
55 const shared_fd_t kInvalidSharedFD = Socket::kInvalidSocketValue;
56 #endif
57 
58 class SharedSocket {
59 public:
60   SharedSocket(Connection *conn, Status &error) {
61     m_fd = kInvalidSharedFD;
62 
63     const Socket *socket =
64         static_cast<const Socket *>(conn->GetReadObject().get());
65     if (socket == nullptr) {
66       error = Status("invalid conn socket");
67       return;
68     }
69 
70 #ifdef _WIN32
71     m_socket = socket->GetNativeSocket();
72 
73     // Create a pipe to transfer WSAPROTOCOL_INFO to the child process.
74     error = m_socket_pipe.CreateNew(true);
75     if (error.Fail())
76       return;
77 
78     m_fd = m_socket_pipe.GetReadPipe();
79 #else
80     m_fd = socket->GetNativeSocket();
81     error = Status();
82 #endif
83   }
84 
85   shared_fd_t GetSendableFD() { return m_fd; }
86 
87   Status CompleteSending(lldb::pid_t child_pid) {
88 #ifdef _WIN32
89     // Transfer WSAPROTOCOL_INFO to the child process.
90     m_socket_pipe.CloseReadFileDescriptor();
91 
92     WSAPROTOCOL_INFO protocol_info;
93     if (::WSADuplicateSocket(m_socket, child_pid, &protocol_info) ==
94         SOCKET_ERROR) {
95       int last_error = ::WSAGetLastError();
96       return Status("WSADuplicateSocket() failed, error: %d", last_error);
97     }
98 
99     size_t num_bytes;
100     Status error =
101         m_socket_pipe.WriteWithTimeout(&protocol_info, sizeof(protocol_info),
102                                        std::chrono::seconds(10), num_bytes);
103     if (error.Fail())
104       return error;
105     if (num_bytes != sizeof(protocol_info))
106       return Status("WriteWithTimeout(WSAPROTOCOL_INFO) failed: %d bytes",
107                     num_bytes);
108 #endif
109     return Status();
110   }
111 
112   static Status GetNativeSocket(shared_fd_t fd, NativeSocket &socket) {
113 #ifdef _WIN32
114     socket = Socket::kInvalidSocketValue;
115     // Read WSAPROTOCOL_INFO from the parent process and create NativeSocket.
116     WSAPROTOCOL_INFO protocol_info;
117     {
118       Pipe socket_pipe(fd, LLDB_INVALID_PIPE);
119       size_t num_bytes;
120       Status error =
121           socket_pipe.ReadWithTimeout(&protocol_info, sizeof(protocol_info),
122                                       std::chrono::seconds(10), num_bytes);
123       if (error.Fail())
124         return error;
125       if (num_bytes != sizeof(protocol_info)) {
126         return Status(
127             "socket_pipe.ReadWithTimeout(WSAPROTOCOL_INFO) failed: % d bytes",
128             num_bytes);
129       }
130     }
131     socket = ::WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
132                          FROM_PROTOCOL_INFO, &protocol_info, 0, 0);
133     if (socket == INVALID_SOCKET) {
134       return Status("WSASocket(FROM_PROTOCOL_INFO) failed: error %d",
135                     ::WSAGetLastError());
136     }
137     return Status();
138 #else
139     socket = fd;
140     return Status();
141 #endif
142   }
143 
144 private:
145 #ifdef _WIN32
146   Pipe m_socket_pipe;
147   NativeSocket m_socket;
148 #endif
149   shared_fd_t m_fd;
150 };
151 
152 static int g_debug = 0;
153 static int g_verbose = 0;
154 static int g_server = 0;
155 
156 static struct option g_long_options[] = {
157     {"debug", no_argument, &g_debug, 1},
158     {"verbose", no_argument, &g_verbose, 1},
159     {"log-file", required_argument, nullptr, 'l'},
160     {"log-channels", required_argument, nullptr, 'c'},
161     {"listen", required_argument, nullptr, 'L'},
162     {"port-offset", required_argument, nullptr, 'p'},
163     {"gdbserver-port", required_argument, nullptr, 'P'},
164     {"min-gdbserver-port", required_argument, nullptr, 'm'},
165     {"max-gdbserver-port", required_argument, nullptr, 'M'},
166     {"socket-file", required_argument, nullptr, 'f'},
167     {"server", no_argument, &g_server, 1},
168     {"child-platform-fd", required_argument, nullptr, 2},
169     {nullptr, 0, nullptr, 0}};
170 
171 #if defined(__APPLE__)
172 #define LOW_PORT (IPPORT_RESERVED)
173 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
174 #else
175 #define LOW_PORT (1024u)
176 #define HIGH_PORT (49151u)
177 #endif
178 
179 #if !defined(_WIN32)
180 // Watch for signals
181 static void signal_handler(int signo) {
182   switch (signo) {
183   case SIGHUP:
184     // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
185     // And we should not call exit() here because it results in the global
186     // destructors to be invoked and wreaking havoc on the threads still
187     // running.
188     llvm::errs() << "SIGHUP received, exiting lldb-server...\n";
189     abort();
190     break;
191   }
192 }
193 #endif
194 
195 static void display_usage(const char *progname, const char *subcommand) {
196   fprintf(stderr, "Usage:\n  %s %s [--log-file log-file-name] [--log-channels "
197                   "log-channel-list] [--port-file port-file-path] --server "
198                   "--listen port\n",
199           progname, subcommand);
200   exit(0);
201 }
202 
203 static Status save_socket_id_to_file(const std::string &socket_id,
204                                      const FileSpec &file_spec) {
205   FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef());
206   Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
207   if (error.Fail())
208     return Status("Failed to create directory %s: %s",
209                   temp_file_spec.GetPath().c_str(), error.AsCString());
210 
211   Status status;
212   if (auto Err = llvm::writeToOutput(file_spec.GetPath(),
213                                      [&socket_id](llvm::raw_ostream &OS) {
214                                        OS << socket_id;
215                                        return llvm::Error::success();
216                                      }))
217     return Status("Failed to atomically write file %s: %s",
218                   file_spec.GetPath().c_str(),
219                   llvm::toString(std::move(Err)).c_str());
220   return status;
221 }
222 
223 static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
224                           const lldb_private::Args &args) {
225   if (!platform.IsConnected())
226     return;
227 
228   if (args.GetArgumentCount() > 0) {
229     lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
230     std::optional<uint16_t> port;
231     std::string socket_name;
232     Status error = platform.LaunchGDBServer(args,
233                                             "", // hostname
234                                             pid, port, socket_name);
235     if (error.Success())
236       platform.SetPendingGdbServer(pid, *port, socket_name);
237     else
238       fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
239   }
240 
241   bool interrupt = false;
242   bool done = false;
243   Status error;
244   while (!interrupt && !done) {
245     if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,
246                                           done) !=
247         GDBRemoteCommunication::PacketResult::Success)
248       break;
249   }
250 
251   printf("Disconnected.\n");
252 }
253 
254 static GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
255 static std::mutex gdbserver_portmap_mutex;
256 
257 static void spawn_process_reaped(lldb::pid_t pid, int signal, int status) {
258   std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
259   gdbserver_portmap.FreePortForProcess(pid);
260 }
261 
262 static Status spawn_process(const char *progname, Connection *conn,
263                             uint16_t gdb_port, uint16_t port_offset,
264                             const lldb_private::Args &args,
265                             const std::string &log_file,
266                             const StringRef log_channels) {
267   Status error;
268   SharedSocket shared_socket(conn, error);
269   if (error.Fail())
270     return error;
271 
272   ProcessLaunchInfo launch_info;
273 
274   FileSpec self_spec(progname, FileSpec::Style::native);
275   launch_info.SetExecutableFile(self_spec, true);
276   Args &self_args = launch_info.GetArguments();
277   self_args.AppendArgument(llvm::StringRef("platform"));
278   self_args.AppendArgument(llvm::StringRef("--child-platform-fd"));
279   self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD()));
280   if (gdb_port) {
281     self_args.AppendArgument(llvm::StringRef("--gdbserver-port"));
282     self_args.AppendArgument(llvm::to_string(gdb_port));
283   }
284   if (port_offset > 0) {
285     self_args.AppendArgument(llvm::StringRef("--port-offset"));
286     self_args.AppendArgument(llvm::to_string(port_offset));
287   }
288   if (!log_file.empty()) {
289     self_args.AppendArgument(llvm::StringRef("--log-file"));
290     self_args.AppendArgument(log_file);
291   }
292   if (!log_channels.empty()) {
293     self_args.AppendArgument(llvm::StringRef("--log-channels"));
294     self_args.AppendArgument(log_channels);
295   }
296   if (args.GetArgumentCount() > 0) {
297     self_args.AppendArgument("--");
298     self_args.AppendArguments(args);
299   }
300 
301   launch_info.SetLaunchInSeparateProcessGroup(false);
302   launch_info.SetMonitorProcessCallback(&spawn_process_reaped);
303 
304   // Copy the current environment.
305   launch_info.GetEnvironment() = Host::GetEnvironment();
306 
307   launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
308 
309   // Close STDIN, STDOUT and STDERR.
310   launch_info.AppendCloseFileAction(STDIN_FILENO);
311   launch_info.AppendCloseFileAction(STDOUT_FILENO);
312   launch_info.AppendCloseFileAction(STDERR_FILENO);
313 
314   // Redirect STDIN, STDOUT and STDERR to "/dev/null".
315   launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
316   launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
317   launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
318 
319   std::string cmd;
320   self_args.GetCommandString(cmd);
321 
322   error = Host::LaunchProcess(launch_info);
323   if (error.Fail())
324     return error;
325 
326   lldb::pid_t child_pid = launch_info.GetProcessID();
327   if (child_pid == LLDB_INVALID_PROCESS_ID)
328     return Status("invalid pid");
329 
330   LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}",
331            cmd, child_pid);
332 
333   {
334     std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
335     gdbserver_portmap.AssociatePortWithProcess(gdb_port, child_pid);
336   }
337 
338   error = shared_socket.CompleteSending(child_pid);
339   if (error.Fail()) {
340     Host::Kill(child_pid, SIGTERM);
341     return error;
342   }
343 
344   return Status();
345 }
346 
347 // main
348 int main_platform(int argc, char *argv[]) {
349   const char *progname = argv[0];
350   const char *subcommand = argv[1];
351   argc--;
352   argv++;
353 #if !defined(_WIN32)
354   signal(SIGPIPE, SIG_IGN);
355   signal(SIGHUP, signal_handler);
356 #endif
357   int long_option_index = 0;
358   Status error;
359   std::string listen_host_port;
360   int ch;
361 
362   std::string log_file;
363   StringRef
364       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
365 
366   shared_fd_t fd = kInvalidSharedFD;
367 
368   int min_gdbserver_port = 0;
369   int max_gdbserver_port = 0;
370   uint16_t port_offset = 0;
371 
372   FileSpec socket_file;
373   bool show_usage = false;
374   int option_error = 0;
375   int socket_error = -1;
376 
377   std::string short_options(OptionParser::GetShortOptionString(g_long_options));
378 
379 #if __GLIBC__
380   optind = 0;
381 #else
382   optreset = 1;
383   optind = 1;
384 #endif
385 
386   while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
387                                 g_long_options, &long_option_index)) != -1) {
388     switch (ch) {
389     case 0: // Any optional that auto set themselves will return 0
390       break;
391 
392     case 'L':
393       listen_host_port.append(optarg);
394       break;
395 
396     case 'l': // Set Log File
397       if (optarg && optarg[0])
398         log_file.assign(optarg);
399       break;
400 
401     case 'c': // Log Channels
402       if (optarg && optarg[0])
403         log_channels = StringRef(optarg);
404       break;
405 
406     case 'f': // Socket file
407       if (optarg && optarg[0])
408         socket_file.SetFile(optarg, FileSpec::Style::native);
409       break;
410 
411     case 'p': {
412       if (!llvm::to_integer(optarg, port_offset)) {
413         WithColor::error() << "invalid port offset string " << optarg << "\n";
414         option_error = 4;
415         break;
416       }
417       if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
418         WithColor::error() << llvm::formatv(
419             "port offset {0} is not in the "
420             "valid user port range of {1} - {2}\n",
421             port_offset, LOW_PORT, HIGH_PORT);
422         option_error = 5;
423       }
424     } break;
425 
426     case 'P':
427     case 'm':
428     case 'M': {
429       uint16_t portnum;
430       if (!llvm::to_integer(optarg, portnum)) {
431         WithColor::error() << "invalid port number string " << optarg << "\n";
432         option_error = 2;
433         break;
434       }
435       if (portnum < LOW_PORT || portnum > HIGH_PORT) {
436         WithColor::error() << llvm::formatv(
437             "port number {0} is not in the "
438             "valid user port range of {1} - {2}\n",
439             portnum, LOW_PORT, HIGH_PORT);
440         option_error = 1;
441         break;
442       }
443       if (ch == 'P')
444         gdbserver_portmap.AllowPort(portnum);
445       else if (ch == 'm')
446         min_gdbserver_port = portnum;
447       else
448         max_gdbserver_port = portnum;
449     } break;
450 
451     case 2: {
452       uint64_t _fd;
453       if (!llvm::to_integer(optarg, _fd)) {
454         WithColor::error() << "invalid fd " << optarg << "\n";
455         option_error = 6;
456       } else
457         fd = (shared_fd_t)_fd;
458     } break;
459 
460     case 'h': /* fall-through is intentional */
461     case '?':
462       show_usage = true;
463       break;
464     }
465   }
466 
467   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
468     return -1;
469 
470   // Make a port map for a port range that was specified.
471   if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) {
472     gdbserver_portmap = GDBRemoteCommunicationServerPlatform::PortMap(
473         min_gdbserver_port, max_gdbserver_port);
474   } else if (min_gdbserver_port || max_gdbserver_port) {
475     WithColor::error() << llvm::formatv(
476         "--min-gdbserver-port ({0}) is not lower than "
477         "--max-gdbserver-port ({1})\n",
478         min_gdbserver_port, max_gdbserver_port);
479     option_error = 3;
480   }
481 
482   // Print usage and exit if no listening port is specified.
483   if (listen_host_port.empty() && fd == kInvalidSharedFD)
484     show_usage = true;
485 
486   if (show_usage || option_error) {
487     display_usage(progname, subcommand);
488     exit(option_error);
489   }
490 
491   // Skip any options we consumed with getopt_long_only.
492   argc -= optind;
493   argv += optind;
494   lldb_private::Args inferior_arguments;
495   inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
496 
497   if (fd != kInvalidSharedFD) {
498     // Child process will handle the connection and exit.
499     Log *log = GetLog(LLDBLog::Platform);
500     if (!listen_host_port.empty()) {
501       LLDB_LOGF(log, "lldb-platform child: "
502                      "ambiguous parameters --listen and --child-platform-fd");
503       return socket_error;
504     }
505 
506     NativeSocket socket;
507     error = SharedSocket::GetNativeSocket(fd, socket);
508     if (error.Fail()) {
509       LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString());
510       return socket_error;
511     }
512 
513     Connection *conn =
514         new ConnectionFileDescriptor(new TCPSocket(socket, true, false));
515     GDBRemoteCommunicationServerPlatform platform(Socket::ProtocolTcp, "tcp");
516     if (port_offset > 0)
517       platform.SetPortOffset(port_offset);
518     platform.SetPortMap(std::move(gdbserver_portmap));
519     platform.SetConnection(std::unique_ptr<Connection>(conn));
520     client_handle(platform, inferior_arguments);
521     return 0;
522   }
523 
524   const bool children_inherit_listen_socket = false;
525   // the test suite makes many connections in parallel, let's not miss any.
526   // The highest this should get reasonably is a function of the number
527   // of target CPUs. For now, let's just use 100.
528   const int backlog = 100;
529 
530   std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
531       listen_host_port, children_inherit_listen_socket, error));
532   if (error.Fail()) {
533     fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
534     exit(socket_error);
535   }
536 
537   error = acceptor_up->Listen(backlog);
538   if (error.Fail()) {
539     printf("failed to listen: %s\n", error.AsCString());
540     exit(socket_error);
541   }
542   if (socket_file) {
543     error =
544         save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
545     if (error.Fail()) {
546       fprintf(stderr, "failed to write socket id to %s: %s\n",
547               socket_file.GetPath().c_str(), error.AsCString());
548       return 1;
549     }
550   }
551 
552   GDBRemoteCommunicationServerPlatform platform(
553       acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
554   if (port_offset > 0)
555     platform.SetPortOffset(port_offset);
556 
557   do {
558     const bool children_inherit_accept_socket = true;
559     Connection *conn = nullptr;
560     error = acceptor_up->Accept(children_inherit_accept_socket, conn);
561     if (error.Fail()) {
562       WithColor::error() << error.AsCString() << '\n';
563       exit(socket_error);
564     }
565     printf("Connection established.\n");
566 
567     if (g_server) {
568       std::optional<uint16_t> available_port;
569       {
570         std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
571         auto port = gdbserver_portmap.GetNextAvailablePort();
572         if (port)
573           available_port = *port;
574         else
575           llvm::consumeError(port.takeError());
576       }
577       if (!available_port) {
578         fprintf(stderr,
579                 "no available gdbserver port for connection - dropping...\n");
580       } else {
581         error = spawn_process(progname, conn, *available_port, port_offset,
582                               inferior_arguments, log_file, log_channels);
583         if (error.Fail()) {
584           {
585 
586             std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
587             gdbserver_portmap.FreePort(*available_port);
588           }
589           LLDB_LOGF(GetLog(LLDBLog::Platform), "spawn_process failed: %s",
590                     error.AsCString());
591           WithColor::error()
592               << "spawn_process failed: " << error.AsCString() << "\n";
593         }
594       }
595       // Parent doesn't need a connection to the lldb client
596       delete conn;
597 
598       // Parent will continue to listen for new connections.
599       continue;
600     } else {
601       // If not running as a server, this process will not accept
602       // connections while a connection is active.
603       acceptor_up.reset();
604 
605       // When not running in server mode, use all available ports
606       platform.SetPortMap(std::move(gdbserver_portmap));
607     }
608 
609     platform.SetConnection(std::unique_ptr<Connection>(conn));
610     client_handle(platform, inferior_arguments);
611   } while (g_server);
612 
613   fprintf(stderr, "lldb-server exiting...\n");
614 
615   return 0;
616 }
617