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