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 <errno.h>
10 #if defined(__APPLE__)
11 #include <netinet/in.h>
12 #endif
13 #include <signal.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #if !defined(_WIN32)
19 #include <sys/wait.h>
20 #endif
21 #include <fstream>
22 
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/FileUtilities.h"
25 #include "llvm/Support/raw_ostream.h"
26 
27 #include "Acceptor.h"
28 #include "LLDBServerUtilities.h"
29 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
30 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
31 #include "lldb/Host/ConnectionFileDescriptor.h"
32 #include "lldb/Host/HostGetOpt.h"
33 #include "lldb/Host/OptionParser.h"
34 #include "lldb/Host/common/TCPSocket.h"
35 #include "lldb/Utility/FileSpec.h"
36 #include "lldb/Utility/Status.h"
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 using namespace lldb_private::lldb_server;
41 using namespace lldb_private::process_gdb_remote;
42 using namespace llvm;
43 
44 // option descriptors for getopt_long_only()
45 
46 static int g_debug = 0;
47 static int g_verbose = 0;
48 static int g_server = 0;
49 
50 static struct option g_long_options[] = {
51     {"debug", no_argument, &g_debug, 1},
52     {"verbose", no_argument, &g_verbose, 1},
53     {"log-file", required_argument, nullptr, 'l'},
54     {"log-channels", required_argument, nullptr, 'c'},
55     {"listen", required_argument, nullptr, 'L'},
56     {"port-offset", required_argument, nullptr, 'p'},
57     {"gdbserver-port", required_argument, nullptr, 'P'},
58     {"min-gdbserver-port", required_argument, nullptr, 'm'},
59     {"max-gdbserver-port", required_argument, nullptr, 'M'},
60     {"socket-file", required_argument, nullptr, 'f'},
61     {"server", no_argument, &g_server, 1},
62     {nullptr, 0, nullptr, 0}};
63 
64 #if defined(__APPLE__)
65 #define LOW_PORT (IPPORT_RESERVED)
66 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
67 #else
68 #define LOW_PORT (1024u)
69 #define HIGH_PORT (49151u)
70 #endif
71 
72 #if !defined(_WIN32)
73 // Watch for signals
74 static void signal_handler(int signo) {
75   switch (signo) {
76   case SIGHUP:
77     // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
78     // And we should not call exit() here because it results in the global
79     // destructors
80     // to be invoked and wreaking havoc on the threads still running.
81     Host::SystemLog(Host::eSystemLogWarning,
82                     "SIGHUP received, exiting lldb-server...\n");
83     abort();
84     break;
85   }
86 }
87 #endif
88 
89 static void display_usage(const char *progname, const char *subcommand) {
90   fprintf(stderr, "Usage:\n  %s %s [--log-file log-file-name] [--log-channels "
91                   "log-channel-list] [--port-file port-file-path] --server "
92                   "--listen port\n",
93           progname, subcommand);
94   exit(0);
95 }
96 
97 static Status save_socket_id_to_file(const std::string &socket_id,
98                                      const FileSpec &file_spec) {
99   FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef());
100   Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
101   if (error.Fail())
102     return Status("Failed to create directory %s: %s",
103                   temp_file_spec.GetCString(), error.AsCString());
104 
105   llvm::SmallString<64> temp_file_path;
106   temp_file_spec.AppendPathComponent("port-file.%%%%%%");
107   temp_file_path = temp_file_spec.GetPath();
108 
109   Status status;
110   if (auto Err =
111           handleErrors(llvm::writeFileAtomically(
112                            temp_file_path, file_spec.GetPath(), socket_id),
113                        [&status, &file_spec](const AtomicFileWriteError &E) {
114                          std::string ErrorMsgBuffer;
115                          llvm::raw_string_ostream S(ErrorMsgBuffer);
116                          E.log(S);
117 
118                          switch (E.Error) {
119                          case atomic_write_error::failed_to_create_uniq_file:
120                            status = Status("Failed to create temp file: %s",
121                                            ErrorMsgBuffer.c_str());
122                            break;
123                          case atomic_write_error::output_stream_error:
124                            status = Status("Failed to write to port file.");
125                            break;
126                          case atomic_write_error::failed_to_rename_temp_file:
127                            status = Status("Failed to rename file %s to %s: %s",
128                                            ErrorMsgBuffer.c_str(),
129                                            file_spec.GetPath().c_str(),
130                                            ErrorMsgBuffer.c_str());
131                            break;
132                          }
133                        })) {
134     return Status("Failed to atomically write file %s",
135                   file_spec.GetPath().c_str());
136   }
137   return status;
138 }
139 
140 // main
141 int main_platform(int argc, char *argv[]) {
142   const char *progname = argv[0];
143   const char *subcommand = argv[1];
144   argc--;
145   argv++;
146 #if !defined(_WIN32)
147   signal(SIGPIPE, SIG_IGN);
148   signal(SIGHUP, signal_handler);
149 #endif
150   int long_option_index = 0;
151   Status error;
152   std::string listen_host_port;
153   int ch;
154 
155   std::string log_file;
156   StringRef
157       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
158 
159   GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
160   int min_gdbserver_port = 0;
161   int max_gdbserver_port = 0;
162   uint16_t port_offset = 0;
163 
164   FileSpec socket_file;
165   bool show_usage = false;
166   int option_error = 0;
167   int socket_error = -1;
168 
169   std::string short_options(OptionParser::GetShortOptionString(g_long_options));
170 
171 #if __GLIBC__
172   optind = 0;
173 #else
174   optreset = 1;
175   optind = 1;
176 #endif
177 
178   while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
179                                 g_long_options, &long_option_index)) != -1) {
180     switch (ch) {
181     case 0: // Any optional that auto set themselves will return 0
182       break;
183 
184     case 'L':
185       listen_host_port.append(optarg);
186       break;
187 
188     case 'l': // Set Log File
189       if (optarg && optarg[0])
190         log_file.assign(optarg);
191       break;
192 
193     case 'c': // Log Channels
194       if (optarg && optarg[0])
195         log_channels = StringRef(optarg);
196       break;
197 
198     case 'f': // Socket file
199       if (optarg && optarg[0])
200         socket_file.SetFile(optarg, FileSpec::Style::native);
201       break;
202 
203     case 'p': {
204       if (!llvm::to_integer(optarg, port_offset)) {
205         llvm::errs() << "error: invalid port offset string " << optarg << "\n";
206         option_error = 4;
207         break;
208       }
209       if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
210         llvm::errs() << llvm::formatv("error: port offset {0} is not in the "
211                                       "valid user port range of {1} - {2}\n",
212                                       port_offset, LOW_PORT, HIGH_PORT);
213         option_error = 5;
214       }
215     } break;
216 
217     case 'P':
218     case 'm':
219     case 'M': {
220       uint16_t portnum;
221       if (!llvm::to_integer(optarg, portnum)) {
222         llvm::errs() << "error: invalid port number string " << optarg << "\n";
223         option_error = 2;
224         break;
225       }
226       if (portnum < LOW_PORT || portnum > HIGH_PORT) {
227         llvm::errs() << llvm::formatv("error: port number {0} is not in the "
228                                       "valid user port range of {1} - {2}\n",
229                                       portnum, LOW_PORT, HIGH_PORT);
230         option_error = 1;
231         break;
232       }
233       if (ch == 'P')
234         gdbserver_portmap.AllowPort(portnum);
235       else if (ch == 'm')
236         min_gdbserver_port = portnum;
237       else
238         max_gdbserver_port = portnum;
239     } break;
240 
241     case 'h': /* fall-through is intentional */
242     case '?':
243       show_usage = true;
244       break;
245     }
246   }
247 
248   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
249     return -1;
250 
251   // Make a port map for a port range that was specified.
252   if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) {
253     gdbserver_portmap = GDBRemoteCommunicationServerPlatform::PortMap(
254         min_gdbserver_port, max_gdbserver_port);
255   } else if (min_gdbserver_port || max_gdbserver_port) {
256     fprintf(stderr, "error: --min-gdbserver-port (%u) is not lower than "
257                     "--max-gdbserver-port (%u)\n",
258             min_gdbserver_port, max_gdbserver_port);
259     option_error = 3;
260   }
261 
262   // Print usage and exit if no listening port is specified.
263   if (listen_host_port.empty())
264     show_usage = true;
265 
266   if (show_usage || option_error) {
267     display_usage(progname, subcommand);
268     exit(option_error);
269   }
270 
271   // Skip any options we consumed with getopt_long_only.
272   argc -= optind;
273   argv += optind;
274   lldb_private::Args inferior_arguments;
275   inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
276 
277   const bool children_inherit_listen_socket = false;
278   // the test suite makes many connections in parallel, let's not miss any.
279   // The highest this should get reasonably is a function of the number
280   // of target CPUs. For now, let's just use 100.
281   const int backlog = 100;
282 
283   std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
284       listen_host_port, children_inherit_listen_socket, error));
285   if (error.Fail()) {
286     fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
287     exit(socket_error);
288   }
289 
290   error = acceptor_up->Listen(backlog);
291   if (error.Fail()) {
292     printf("failed to listen: %s\n", error.AsCString());
293     exit(socket_error);
294   }
295   if (socket_file) {
296     error =
297         save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
298     if (error.Fail()) {
299       fprintf(stderr, "failed to write socket id to %s: %s\n",
300               socket_file.GetPath().c_str(), error.AsCString());
301       return 1;
302     }
303   }
304 
305   do {
306     GDBRemoteCommunicationServerPlatform platform(
307         acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
308 
309     if (port_offset > 0)
310       platform.SetPortOffset(port_offset);
311 
312     if (!gdbserver_portmap.empty()) {
313       platform.SetPortMap(std::move(gdbserver_portmap));
314     }
315 
316     const bool children_inherit_accept_socket = true;
317     Connection *conn = nullptr;
318     error = acceptor_up->Accept(children_inherit_accept_socket, conn);
319     if (error.Fail()) {
320       printf("error: %s\n", error.AsCString());
321       exit(socket_error);
322     }
323     printf("Connection established.\n");
324     if (g_server) {
325       // Collect child zombie processes.
326 #if !defined(_WIN32)
327       while (waitpid(-1, nullptr, WNOHANG) > 0)
328         ;
329 #endif
330       if (fork()) {
331         // Parent doesn't need a connection to the lldb client
332         delete conn;
333 
334         // Parent will continue to listen for new connections.
335         continue;
336       } else {
337         // Child process will handle the connection and exit.
338         g_server = 0;
339         // Listening socket is owned by parent process.
340         acceptor_up.release();
341       }
342     } else {
343       // If not running as a server, this process will not accept
344       // connections while a connection is active.
345       acceptor_up.reset();
346     }
347     platform.SetConnection(std::unique_ptr<Connection>(conn));
348 
349     if (platform.IsConnected()) {
350       if (inferior_arguments.GetArgumentCount() > 0) {
351         lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
352         llvm::Optional<uint16_t> port = 0;
353         std::string socket_name;
354         Status error = platform.LaunchGDBServer(inferior_arguments,
355                                                 "", // hostname
356                                                 pid, port, socket_name);
357         if (error.Success())
358           platform.SetPendingGdbServer(pid, *port, socket_name);
359         else
360           fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
361       }
362 
363       // After we connected, we need to get an initial ack from...
364       if (platform.HandshakeWithClient()) {
365         bool interrupt = false;
366         bool done = false;
367         while (!interrupt && !done) {
368           if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt,
369                                                 done) !=
370               GDBRemoteCommunication::PacketResult::Success)
371             break;
372         }
373 
374         if (error.Fail()) {
375           fprintf(stderr, "error: %s\n", error.AsCString());
376         }
377       } else {
378         fprintf(stderr, "error: handshake with client failed\n");
379       }
380     }
381   } while (g_server);
382 
383   fprintf(stderr, "lldb-server exiting...\n");
384 
385   return 0;
386 }
387