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