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