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/Core/Error.h" 34 #include "lldb/Host/ConnectionFileDescriptor.h" 35 #include "lldb/Host/FileSpec.h" 36 #include "lldb/Host/FileSystem.h" 37 #include "lldb/Host/HostGetOpt.h" 38 #include "lldb/Host/OptionParser.h" 39 #include "lldb/Host/common/TCPSocket.h" 40 41 using namespace lldb; 42 using namespace lldb_private; 43 using namespace lldb_private::lldb_server; 44 using namespace lldb_private::process_gdb_remote; 45 using namespace llvm; 46 47 //---------------------------------------------------------------------- 48 // option descriptors for getopt_long_only() 49 //---------------------------------------------------------------------- 50 51 static int g_debug = 0; 52 static int g_verbose = 0; 53 static int g_server = 0; 54 55 static struct option g_long_options[] = { 56 {"debug", no_argument, &g_debug, 1}, 57 {"verbose", no_argument, &g_verbose, 1}, 58 {"log-file", required_argument, NULL, 'l'}, 59 {"log-channels", required_argument, NULL, 'c'}, 60 {"listen", required_argument, NULL, 'L'}, 61 {"port-offset", required_argument, NULL, 'p'}, 62 {"gdbserver-port", required_argument, NULL, 'P'}, 63 {"min-gdbserver-port", required_argument, NULL, 'm'}, 64 {"max-gdbserver-port", required_argument, NULL, 'M'}, 65 {"socket-file", required_argument, NULL, 'f'}, 66 {"server", no_argument, &g_server, 1}, 67 {NULL, 0, NULL, 0}}; 68 69 #if defined(__APPLE__) 70 #define LOW_PORT (IPPORT_RESERVED) 71 #define HIGH_PORT (IPPORT_HIFIRSTAUTO) 72 #else 73 #define LOW_PORT (1024u) 74 #define HIGH_PORT (49151u) 75 #endif 76 77 //---------------------------------------------------------------------- 78 // Watch for signals 79 //---------------------------------------------------------------------- 80 static void signal_handler(int signo) { 81 switch (signo) { 82 case SIGHUP: 83 // Use SIGINT first, if that does not work, use SIGHUP as a last resort. 84 // And we should not call exit() here because it results in the global 85 // destructors 86 // to be invoked and wreaking havoc on the threads still running. 87 Host::SystemLog(Host::eSystemLogWarning, 88 "SIGHUP received, exiting lldb-server...\n"); 89 abort(); 90 break; 91 } 92 } 93 94 static void display_usage(const char *progname, const char *subcommand) { 95 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels " 96 "log-channel-list] [--port-file port-file-path] --server " 97 "--listen port\n", 98 progname, subcommand); 99 exit(0); 100 } 101 102 static Error save_socket_id_to_file(const std::string &socket_id, 103 const FileSpec &file_spec) { 104 FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false); 105 auto error = FileSystem::MakeDirectory(temp_file_spec, 106 eFilePermissionsDirectoryDefault); 107 if (error.Fail()) 108 return Error("Failed to create directory %s: %s", 109 temp_file_spec.GetCString(), error.AsCString()); 110 111 llvm::SmallString<PATH_MAX> temp_file_path; 112 temp_file_spec.AppendPathComponent("port-file.%%%%%%"); 113 auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetCString(), 114 temp_file_path); 115 if (err_code) 116 return Error("Failed to create temp file: %s", err_code.message().c_str()); 117 118 llvm::FileRemover tmp_file_remover(temp_file_path.c_str()); 119 120 { 121 std::ofstream temp_file(temp_file_path.c_str(), std::ios::out); 122 if (!temp_file.is_open()) 123 return Error("Failed to open temp file %s", temp_file_path.c_str()); 124 temp_file << socket_id; 125 } 126 127 err_code = llvm::sys::fs::rename(temp_file_path.c_str(), file_spec.GetPath()); 128 if (err_code) 129 return Error("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 Error(); 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 Error 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 Error 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