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 if (!llvm::to_integer(optarg, port_offset)) { 201 llvm::errs() << "error: invalid port offset string " << optarg << "\n"; 202 option_error = 4; 203 break; 204 } 205 if (port_offset < LOW_PORT || port_offset > HIGH_PORT) { 206 llvm::errs() << llvm::formatv("error: port offset {0} is not in the " 207 "valid user port range of {1} - {2}\n", 208 port_offset, LOW_PORT, HIGH_PORT); 209 option_error = 5; 210 } 211 } break; 212 213 case 'P': 214 case 'm': 215 case 'M': { 216 uint16_t portnum; 217 if (!llvm::to_integer(optarg, portnum)) { 218 llvm::errs() << "error: invalid port number string " << optarg << "\n"; 219 option_error = 2; 220 break; 221 } 222 if (portnum < LOW_PORT || portnum > HIGH_PORT) { 223 llvm::errs() << llvm::formatv("error: port number {0} is not in the " 224 "valid user port range of {1} - {2}\n", 225 portnum, LOW_PORT, HIGH_PORT); 226 option_error = 1; 227 break; 228 } 229 if (ch == 'P') 230 gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID; 231 else if (ch == 'm') 232 min_gdbserver_port = portnum; 233 else 234 max_gdbserver_port = portnum; 235 } break; 236 237 case 'h': /* fall-through is intentional */ 238 case '?': 239 show_usage = true; 240 break; 241 } 242 } 243 244 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) 245 return -1; 246 247 // Make a port map for a port range that was specified. 248 if (min_gdbserver_port < max_gdbserver_port) { 249 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) 250 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; 251 } else if (min_gdbserver_port != max_gdbserver_port) { 252 fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than " 253 "--max-gdbserver-port (%u)\n", 254 min_gdbserver_port, max_gdbserver_port); 255 option_error = 3; 256 } 257 258 // Print usage and exit if no listening port is specified. 259 if (listen_host_port.empty()) 260 show_usage = true; 261 262 if (show_usage || option_error) { 263 display_usage(progname, subcommand); 264 exit(option_error); 265 } 266 267 // Skip any options we consumed with getopt_long_only. 268 argc -= optind; 269 argv += optind; 270 lldb_private::Args inferior_arguments; 271 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); 272 273 const bool children_inherit_listen_socket = false; 274 // the test suite makes many connections in parallel, let's not miss any. 275 // The highest this should get reasonably is a function of the number 276 // of target CPUs. For now, let's just use 100. 277 const int backlog = 100; 278 279 std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create( 280 listen_host_port, children_inherit_listen_socket, error)); 281 if (error.Fail()) { 282 fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); 283 exit(socket_error); 284 } 285 286 error = acceptor_up->Listen(backlog); 287 if (error.Fail()) { 288 printf("failed to listen: %s\n", error.AsCString()); 289 exit(socket_error); 290 } 291 if (socket_file) { 292 error = 293 save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); 294 if (error.Fail()) { 295 fprintf(stderr, "failed to write socket id to %s: %s\n", 296 socket_file.GetPath().c_str(), error.AsCString()); 297 return 1; 298 } 299 } 300 301 do { 302 GDBRemoteCommunicationServerPlatform platform( 303 acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); 304 305 if (port_offset > 0) 306 platform.SetPortOffset(port_offset); 307 308 if (!gdbserver_portmap.empty()) { 309 platform.SetPortMap(std::move(gdbserver_portmap)); 310 } 311 312 const bool children_inherit_accept_socket = true; 313 Connection *conn = nullptr; 314 error = acceptor_up->Accept(children_inherit_accept_socket, conn); 315 if (error.Fail()) { 316 printf("error: %s\n", error.AsCString()); 317 exit(socket_error); 318 } 319 printf("Connection established.\n"); 320 if (g_server) { 321 // Collect child zombie processes. 322 while (waitpid(-1, nullptr, WNOHANG) > 0) 323 ; 324 if (fork()) { 325 // Parent doesn't need a connection to the lldb client 326 delete conn; 327 328 // Parent will continue to listen for new connections. 329 continue; 330 } else { 331 // Child process will handle the connection and exit. 332 g_server = 0; 333 // Listening socket is owned by parent process. 334 acceptor_up.release(); 335 } 336 } else { 337 // If not running as a server, this process will not accept 338 // connections while a connection is active. 339 acceptor_up.reset(); 340 } 341 platform.SetConnection(conn); 342 343 if (platform.IsConnected()) { 344 if (inferior_arguments.GetArgumentCount() > 0) { 345 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 346 uint16_t port = 0; 347 std::string socket_name; 348 Status error = platform.LaunchGDBServer(inferior_arguments, 349 "", // hostname 350 pid, port, socket_name); 351 if (error.Success()) 352 platform.SetPendingGdbServer(pid, port, socket_name); 353 else 354 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); 355 } 356 357 // After we connected, we need to get an initial ack from... 358 if (platform.HandshakeWithClient()) { 359 bool interrupt = false; 360 bool done = false; 361 while (!interrupt && !done) { 362 if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt, 363 done) != 364 GDBRemoteCommunication::PacketResult::Success) 365 break; 366 } 367 368 if (error.Fail()) { 369 fprintf(stderr, "error: %s\n", error.AsCString()); 370 } 371 } else { 372 fprintf(stderr, "error: handshake with client failed\n"); 373 } 374 } 375 } while (g_server); 376 377 fprintf(stderr, "lldb-server exiting...\n"); 378 379 return 0; 380 } 381