xref: /freebsd/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp (revision a521f2116473fbd8c09db395518f060a27d02334)
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 
108   Status status;
109   if (auto Err =
110           handleErrors(llvm::writeFileAtomically(
111                            temp_file_path, temp_file_spec.GetPath(), socket_id),
112                        [&status, &file_spec](const AtomicFileWriteError &E) {
113                          std::string ErrorMsgBuffer;
114                          llvm::raw_string_ostream S(ErrorMsgBuffer);
115                          E.log(S);
116 
117                          switch (E.Error) {
118                          case atomic_write_error::failed_to_create_uniq_file:
119                            status = Status("Failed to create temp file: %s",
120                                            ErrorMsgBuffer.c_str());
121                            break;
122                          case atomic_write_error::output_stream_error:
123                            status = Status("Failed to write to port file.");
124                            break;
125                          case atomic_write_error::failed_to_rename_temp_file:
126                            status = Status("Failed to rename file %s to %s: %s",
127                                            ErrorMsgBuffer.c_str(),
128                                            file_spec.GetPath().c_str(),
129                                            ErrorMsgBuffer.c_str());
130                            break;
131                          }
132                        })) {
133     return Status("Failed to atomically write file %s",
134                   file_spec.GetPath().c_str());
135   }
136   return status;
137 }
138 
139 // main
140 int main_platform(int argc, char *argv[]) {
141   const char *progname = argv[0];
142   const char *subcommand = argv[1];
143   argc--;
144   argv++;
145 #if !defined(_WIN32)
146   signal(SIGPIPE, SIG_IGN);
147   signal(SIGHUP, signal_handler);
148 #endif
149   int long_option_index = 0;
150   Status error;
151   std::string listen_host_port;
152   int ch;
153 
154   std::string log_file;
155   StringRef
156       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
157 
158   GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
159   int min_gdbserver_port = 0;
160   int max_gdbserver_port = 0;
161   uint16_t port_offset = 0;
162 
163   FileSpec socket_file;
164   bool show_usage = false;
165   int option_error = 0;
166   int socket_error = -1;
167 
168   std::string short_options(OptionParser::GetShortOptionString(g_long_options));
169 
170 #if __GLIBC__
171   optind = 0;
172 #else
173   optreset = 1;
174   optind = 1;
175 #endif
176 
177   while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
178                                 g_long_options, &long_option_index)) != -1) {
179     switch (ch) {
180     case 0: // Any optional that auto set themselves will return 0
181       break;
182 
183     case 'L':
184       listen_host_port.append(optarg);
185       break;
186 
187     case 'l': // Set Log File
188       if (optarg && optarg[0])
189         log_file.assign(optarg);
190       break;
191 
192     case 'c': // Log Channels
193       if (optarg && optarg[0])
194         log_channels = StringRef(optarg);
195       break;
196 
197     case 'f': // Socket file
198       if (optarg && optarg[0])
199         socket_file.SetFile(optarg, FileSpec::Style::native);
200       break;
201 
202     case 'p': {
203       if (!llvm::to_integer(optarg, port_offset)) {
204         llvm::errs() << "error: invalid port offset string " << optarg << "\n";
205         option_error = 4;
206         break;
207       }
208       if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
209         llvm::errs() << llvm::formatv("error: port offset {0} is not in the "
210                                       "valid user port range of {1} - {2}\n",
211                                       port_offset, LOW_PORT, HIGH_PORT);
212         option_error = 5;
213       }
214     } break;
215 
216     case 'P':
217     case 'm':
218     case 'M': {
219       uint16_t portnum;
220       if (!llvm::to_integer(optarg, portnum)) {
221         llvm::errs() << "error: invalid port number string " << optarg << "\n";
222         option_error = 2;
223         break;
224       }
225       if (portnum < LOW_PORT || portnum > HIGH_PORT) {
226         llvm::errs() << llvm::formatv("error: port number {0} is not in the "
227                                       "valid user port range of {1} - {2}\n",
228                                       portnum, LOW_PORT, HIGH_PORT);
229         option_error = 1;
230         break;
231       }
232       if (ch == 'P')
233         gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID;
234       else if (ch == 'm')
235         min_gdbserver_port = portnum;
236       else
237         max_gdbserver_port = portnum;
238     } break;
239 
240     case 'h': /* fall-through is intentional */
241     case '?':
242       show_usage = true;
243       break;
244     }
245   }
246 
247   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
248     return -1;
249 
250   // Make a port map for a port range that was specified.
251   if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) {
252     for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
253       gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
254   } else if (min_gdbserver_port || max_gdbserver_port) {
255     fprintf(stderr, "error: --min-gdbserver-port (%u) is not lower than "
256                     "--max-gdbserver-port (%u)\n",
257             min_gdbserver_port, max_gdbserver_port);
258     option_error = 3;
259   }
260 
261   // Print usage and exit if no listening port is specified.
262   if (listen_host_port.empty())
263     show_usage = true;
264 
265   if (show_usage || option_error) {
266     display_usage(progname, subcommand);
267     exit(option_error);
268   }
269 
270   // Skip any options we consumed with getopt_long_only.
271   argc -= optind;
272   argv += optind;
273   lldb_private::Args inferior_arguments;
274   inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
275 
276   const bool children_inherit_listen_socket = false;
277   // the test suite makes many connections in parallel, let's not miss any.
278   // The highest this should get reasonably is a function of the number
279   // of target CPUs. For now, let's just use 100.
280   const int backlog = 100;
281 
282   std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
283       listen_host_port, children_inherit_listen_socket, error));
284   if (error.Fail()) {
285     fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
286     exit(socket_error);
287   }
288 
289   error = acceptor_up->Listen(backlog);
290   if (error.Fail()) {
291     printf("failed to listen: %s\n", error.AsCString());
292     exit(socket_error);
293   }
294   if (socket_file) {
295     error =
296         save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
297     if (error.Fail()) {
298       fprintf(stderr, "failed to write socket id to %s: %s\n",
299               socket_file.GetPath().c_str(), error.AsCString());
300       return 1;
301     }
302   }
303 
304   do {
305     GDBRemoteCommunicationServerPlatform platform(
306         acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
307 
308     if (port_offset > 0)
309       platform.SetPortOffset(port_offset);
310 
311     if (!gdbserver_portmap.empty()) {
312       platform.SetPortMap(std::move(gdbserver_portmap));
313     }
314 
315     const bool children_inherit_accept_socket = true;
316     Connection *conn = nullptr;
317     error = acceptor_up->Accept(children_inherit_accept_socket, conn);
318     if (error.Fail()) {
319       printf("error: %s\n", error.AsCString());
320       exit(socket_error);
321     }
322     printf("Connection established.\n");
323     if (g_server) {
324       // Collect child zombie processes.
325 #if !defined(_WIN32)
326       while (waitpid(-1, nullptr, WNOHANG) > 0)
327         ;
328 #endif
329       if (fork()) {
330         // Parent doesn't need a connection to the lldb client
331         delete conn;
332 
333         // Parent will continue to listen for new connections.
334         continue;
335       } else {
336         // Child process will handle the connection and exit.
337         g_server = 0;
338         // Listening socket is owned by parent process.
339         acceptor_up.release();
340       }
341     } else {
342       // If not running as a server, this process will not accept
343       // connections while a connection is active.
344       acceptor_up.reset();
345     }
346     platform.SetConnection(std::unique_ptr<Connection>(conn));
347 
348     if (platform.IsConnected()) {
349       if (inferior_arguments.GetArgumentCount() > 0) {
350         lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
351         uint16_t port = 0;
352         std::string socket_name;
353         Status error = platform.LaunchGDBServer(inferior_arguments,
354                                                 "", // hostname
355                                                 pid, port, socket_name);
356         if (error.Success())
357           platform.SetPendingGdbServer(pid, port, socket_name);
358         else
359           fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
360       }
361 
362       // After we connected, we need to get an initial ack from...
363       if (platform.HandshakeWithClient()) {
364         bool interrupt = false;
365         bool done = false;
366         while (!interrupt && !done) {
367           if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt,
368                                                 done) !=
369               GDBRemoteCommunication::PacketResult::Success)
370             break;
371         }
372 
373         if (error.Fail()) {
374           fprintf(stderr, "error: %s\n", error.AsCString());
375         }
376       } else {
377         fprintf(stderr, "error: handshake with client failed\n");
378       }
379     }
380   } while (g_server);
381 
382   fprintf(stderr, "lldb-server exiting...\n");
383 
384   return 0;
385 }
386