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