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 <cerrno> 10 #if defined(__APPLE__) 11 #include <netinet/in.h> 12 #endif 13 #include <csignal> 14 #include <cstdint> 15 #include <cstdio> 16 #include <cstdlib> 17 #include <cstring> 18 #if !defined(_WIN32) 19 #include <sys/wait.h> 20 #endif 21 #include <fstream> 22 #include <optional> 23 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/ScopedPrinter.h" 26 #include "llvm/Support/WithColor.h" 27 #include "llvm/Support/raw_ostream.h" 28 29 #include "LLDBServerUtilities.h" 30 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" 31 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" 32 #include "lldb/Host/ConnectionFileDescriptor.h" 33 #include "lldb/Host/HostGetOpt.h" 34 #include "lldb/Host/MainLoop.h" 35 #include "lldb/Host/OptionParser.h" 36 #include "lldb/Host/Socket.h" 37 #include "lldb/Host/common/TCPSocket.h" 38 #if LLDB_ENABLE_POSIX 39 #include "lldb/Host/posix/DomainSocket.h" 40 #endif 41 #include "lldb/Utility/FileSpec.h" 42 #include "lldb/Utility/LLDBLog.h" 43 #include "lldb/Utility/Status.h" 44 #include "lldb/Utility/UriParser.h" 45 46 using namespace lldb; 47 using namespace lldb_private; 48 using namespace lldb_private::lldb_server; 49 using namespace lldb_private::process_gdb_remote; 50 using namespace llvm; 51 52 // The test suite makes many connections in parallel, let's not miss any. 53 // The highest this should get reasonably is a function of the number 54 // of target CPUs. For now, let's just use 100. 55 static const int backlog = 100; 56 static const int socket_error = -1; 57 static int g_debug = 0; 58 static int g_verbose = 0; 59 static int g_server = 0; 60 61 // option descriptors for getopt_long_only() 62 static struct option g_long_options[] = { 63 {"debug", no_argument, &g_debug, 1}, 64 {"verbose", no_argument, &g_verbose, 1}, 65 {"log-file", required_argument, nullptr, 'l'}, 66 {"log-channels", required_argument, nullptr, 'c'}, 67 {"listen", required_argument, nullptr, 'L'}, 68 {"gdbserver-port", required_argument, nullptr, 'P'}, 69 {"min-gdbserver-port", required_argument, nullptr, 'm'}, 70 {"max-gdbserver-port", required_argument, nullptr, 'M'}, 71 {"socket-file", required_argument, nullptr, 'f'}, 72 {"server", no_argument, &g_server, 1}, 73 {"child-platform-fd", required_argument, nullptr, 2}, 74 {nullptr, 0, nullptr, 0}}; 75 76 #if defined(__APPLE__) 77 #define LOW_PORT (IPPORT_RESERVED) 78 #define HIGH_PORT (IPPORT_HIFIRSTAUTO) 79 #else 80 #define LOW_PORT (1024u) 81 #define HIGH_PORT (49151u) 82 #endif 83 84 #if !defined(_WIN32) 85 // Watch for signals 86 static void signal_handler(int signo) { 87 switch (signo) { 88 case SIGHUP: 89 // Use SIGINT first, if that does not work, use SIGHUP as a last resort. 90 // And we should not call exit() here because it results in the global 91 // destructors to be invoked and wreaking havoc on the threads still 92 // running. 93 llvm::errs() << "SIGHUP received, exiting lldb-server...\n"; 94 abort(); 95 break; 96 } 97 } 98 #endif 99 100 static void display_usage(const char *progname, const char *subcommand) { 101 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels " 102 "log-channel-list] [--port-file port-file-path] --server " 103 "--listen port\n", 104 progname, subcommand); 105 exit(0); 106 } 107 108 static Status parse_listen_host_port(Socket::SocketProtocol &protocol, 109 const std::string &listen_host_port, 110 std::string &address, 111 uint16_t &platform_port, 112 std::string &gdb_address, 113 const uint16_t gdbserver_port) { 114 std::string hostname; 115 // Try to match socket name as URL - e.g., tcp://localhost:5555 116 if (std::optional<URI> uri = URI::Parse(listen_host_port)) { 117 if (!Socket::FindProtocolByScheme(uri->scheme.str().c_str(), protocol)) { 118 return Status::FromErrorStringWithFormat( 119 "Unknown protocol scheme \"%s\".", uri->scheme.str().c_str()); 120 } 121 if (protocol == Socket::ProtocolTcp) { 122 hostname = uri->hostname; 123 if (uri->port) { 124 platform_port = *(uri->port); 125 } 126 } else 127 address = listen_host_port.substr(uri->scheme.size() + strlen("://")); 128 } else { 129 // Try to match socket name as $host:port - e.g., localhost:5555 130 llvm::Expected<Socket::HostAndPort> host_port = 131 Socket::DecodeHostAndPort(listen_host_port); 132 if (!llvm::errorToBool(host_port.takeError())) { 133 protocol = Socket::ProtocolTcp; 134 hostname = host_port->hostname; 135 platform_port = host_port->port; 136 } else 137 address = listen_host_port; 138 } 139 140 if (protocol == Socket::ProtocolTcp) { 141 if (platform_port != 0 && platform_port == gdbserver_port) { 142 return Status::FromErrorStringWithFormat( 143 "The same platform and gdb ports %u.", platform_port); 144 } 145 address = llvm::formatv("[{0}]:{1}", hostname, platform_port).str(); 146 gdb_address = llvm::formatv("[{0}]:{1}", hostname, gdbserver_port).str(); 147 } else { 148 if (gdbserver_port) { 149 return Status::FromErrorStringWithFormat( 150 "--gdbserver-port %u is redundant for non-tcp protocol %s.", 151 gdbserver_port, Socket::FindSchemeByProtocol(protocol)); 152 } 153 } 154 return Status(); 155 } 156 157 static Status save_socket_id_to_file(const std::string &socket_id, 158 const FileSpec &file_spec) { 159 FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef()); 160 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath())); 161 if (error.Fail()) 162 return Status::FromErrorStringWithFormat( 163 "Failed to create directory %s: %s", temp_file_spec.GetPath().c_str(), 164 error.AsCString()); 165 166 Status status; 167 if (auto Err = llvm::writeToOutput(file_spec.GetPath(), 168 [&socket_id](llvm::raw_ostream &OS) { 169 OS << socket_id; 170 return llvm::Error::success(); 171 })) 172 return Status::FromErrorStringWithFormat( 173 "Failed to atomically write file %s: %s", file_spec.GetPath().c_str(), 174 llvm::toString(std::move(Err)).c_str()); 175 return status; 176 } 177 178 static Status ListenGdbConnectionsIfNeeded( 179 const Socket::SocketProtocol protocol, std::unique_ptr<TCPSocket> &gdb_sock, 180 const std::string &gdb_address, uint16_t &gdbserver_port) { 181 if (protocol != Socket::ProtocolTcp) 182 return Status(); 183 184 gdb_sock = std::make_unique<TCPSocket>( 185 /*should_close=*/true, /*child_processes_inherit=*/false); 186 Status error = gdb_sock->Listen(gdb_address, backlog); 187 if (error.Fail()) 188 return error; 189 190 if (gdbserver_port == 0) 191 gdbserver_port = gdb_sock->GetLocalPortNumber(); 192 193 return Status(); 194 } 195 196 static llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> 197 AcceptGdbConnectionsIfNeeded(const Socket::SocketProtocol protocol, 198 std::unique_ptr<TCPSocket> &gdb_sock, 199 MainLoop &main_loop, const uint16_t gdbserver_port, 200 const lldb_private::Args &args) { 201 if (protocol != Socket::ProtocolTcp) 202 return std::vector<MainLoopBase::ReadHandleUP>(); 203 204 return gdb_sock->Accept(main_loop, [gdbserver_port, 205 &args](std::unique_ptr<Socket> sock_up) { 206 Log *log = GetLog(LLDBLog::Platform); 207 Status error; 208 SharedSocket shared_socket(sock_up.get(), error); 209 if (error.Fail()) { 210 LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", error.AsCString()); 211 return; 212 } 213 lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID; 214 std::string socket_name; 215 GDBRemoteCommunicationServerPlatform platform(Socket::ProtocolTcp, 216 gdbserver_port); 217 error = platform.LaunchGDBServer(args, child_pid, socket_name, 218 shared_socket.GetSendableFD()); 219 if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) { 220 error = shared_socket.CompleteSending(child_pid); 221 if (error.Fail()) { 222 Host::Kill(child_pid, SIGTERM); 223 LLDB_LOGF(log, "gdbserver CompleteSending failed: %s", 224 error.AsCString()); 225 return; 226 } 227 } 228 }); 229 } 230 231 static void client_handle(GDBRemoteCommunicationServerPlatform &platform, 232 const lldb_private::Args &args) { 233 if (!platform.IsConnected()) 234 return; 235 236 if (args.GetArgumentCount() > 0) { 237 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 238 std::string socket_name; 239 Status error = platform.LaunchGDBServer(args, pid, socket_name, 240 SharedSocket::kInvalidFD); 241 if (error.Success()) 242 platform.SetPendingGdbServer(socket_name); 243 else 244 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); 245 } 246 247 bool interrupt = false; 248 bool done = false; 249 Status error; 250 while (!interrupt && !done) { 251 if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt, 252 done) != 253 GDBRemoteCommunication::PacketResult::Success) 254 break; 255 } 256 257 printf("Disconnected.\n"); 258 } 259 260 static Status spawn_process(const char *progname, const Socket *conn_socket, 261 uint16_t gdb_port, const lldb_private::Args &args, 262 const std::string &log_file, 263 const StringRef log_channels, MainLoop &main_loop) { 264 Status error; 265 SharedSocket shared_socket(conn_socket, error); 266 if (error.Fail()) 267 return error; 268 269 ProcessLaunchInfo launch_info; 270 271 FileSpec self_spec(progname, FileSpec::Style::native); 272 launch_info.SetExecutableFile(self_spec, true); 273 Args &self_args = launch_info.GetArguments(); 274 self_args.AppendArgument(llvm::StringRef("platform")); 275 self_args.AppendArgument(llvm::StringRef("--child-platform-fd")); 276 self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD())); 277 #ifndef _WIN32 278 launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(), 279 (int)shared_socket.GetSendableFD()); 280 #endif 281 if (gdb_port) { 282 self_args.AppendArgument(llvm::StringRef("--gdbserver-port")); 283 self_args.AppendArgument(llvm::to_string(gdb_port)); 284 } 285 if (!log_file.empty()) { 286 self_args.AppendArgument(llvm::StringRef("--log-file")); 287 self_args.AppendArgument(log_file); 288 } 289 if (!log_channels.empty()) { 290 self_args.AppendArgument(llvm::StringRef("--log-channels")); 291 self_args.AppendArgument(log_channels); 292 } 293 if (args.GetArgumentCount() > 0) { 294 self_args.AppendArgument("--"); 295 self_args.AppendArguments(args); 296 } 297 298 launch_info.SetLaunchInSeparateProcessGroup(false); 299 300 if (g_server) 301 launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {}); 302 else 303 launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) { 304 main_loop.AddPendingCallback( 305 [](MainLoopBase &loop) { loop.RequestTermination(); }); 306 }); 307 308 // Copy the current environment. 309 launch_info.GetEnvironment() = Host::GetEnvironment(); 310 311 launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO); 312 313 // Close STDIN, STDOUT and STDERR. 314 launch_info.AppendCloseFileAction(STDIN_FILENO); 315 launch_info.AppendCloseFileAction(STDOUT_FILENO); 316 launch_info.AppendCloseFileAction(STDERR_FILENO); 317 318 // Redirect STDIN, STDOUT and STDERR to "/dev/null". 319 launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false); 320 launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true); 321 launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true); 322 323 std::string cmd; 324 self_args.GetCommandString(cmd); 325 326 error = Host::LaunchProcess(launch_info); 327 if (error.Fail()) 328 return error; 329 330 lldb::pid_t child_pid = launch_info.GetProcessID(); 331 if (child_pid == LLDB_INVALID_PROCESS_ID) 332 return Status::FromErrorString("invalid pid"); 333 334 LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}", 335 cmd, child_pid); 336 337 error = shared_socket.CompleteSending(child_pid); 338 if (error.Fail()) { 339 Host::Kill(child_pid, SIGTERM); 340 return error; 341 } 342 343 return Status(); 344 } 345 346 // main 347 int main_platform(int argc, char *argv[]) { 348 const char *progname = argv[0]; 349 const char *subcommand = argv[1]; 350 argc--; 351 argv++; 352 #if !defined(_WIN32) 353 signal(SIGPIPE, SIG_IGN); 354 signal(SIGHUP, signal_handler); 355 #endif 356 int long_option_index = 0; 357 Status error; 358 std::string listen_host_port; 359 int ch; 360 361 std::string log_file; 362 StringRef 363 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 364 365 shared_fd_t fd = SharedSocket::kInvalidFD; 366 367 uint16_t gdbserver_port = 0; 368 369 FileSpec socket_file; 370 bool show_usage = false; 371 int option_error = 0; 372 373 std::string short_options(OptionParser::GetShortOptionString(g_long_options)); 374 375 #if __GLIBC__ 376 optind = 0; 377 #else 378 optreset = 1; 379 optind = 1; 380 #endif 381 382 while ((ch = getopt_long_only(argc, argv, short_options.c_str(), 383 g_long_options, &long_option_index)) != -1) { 384 switch (ch) { 385 case 0: // Any optional that auto set themselves will return 0 386 break; 387 388 case 'L': 389 listen_host_port.append(optarg); 390 break; 391 392 case 'l': // Set Log File 393 if (optarg && optarg[0]) 394 log_file.assign(optarg); 395 break; 396 397 case 'c': // Log Channels 398 if (optarg && optarg[0]) 399 log_channels = StringRef(optarg); 400 break; 401 402 case 'f': // Socket file 403 if (optarg && optarg[0]) 404 socket_file.SetFile(optarg, FileSpec::Style::native); 405 break; 406 407 case 'P': 408 case 'm': 409 case 'M': { 410 uint16_t portnum; 411 if (!llvm::to_integer(optarg, portnum)) { 412 WithColor::error() << "invalid port number string " << optarg << "\n"; 413 option_error = 2; 414 break; 415 } 416 // Note the condition gdbserver_port > HIGH_PORT is valid in case of using 417 // --child-platform-fd. Check gdbserver_port later. 418 if (ch == 'P') 419 gdbserver_port = portnum; 420 else if (gdbserver_port == 0) 421 gdbserver_port = portnum; 422 } break; 423 424 case 2: { 425 uint64_t _fd; 426 if (!llvm::to_integer(optarg, _fd)) { 427 WithColor::error() << "invalid fd " << optarg << "\n"; 428 option_error = 6; 429 } else 430 fd = (shared_fd_t)_fd; 431 } break; 432 433 case 'h': /* fall-through is intentional */ 434 case '?': 435 show_usage = true; 436 break; 437 } 438 } 439 440 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) 441 return -1; 442 443 // Print usage and exit if no listening port is specified. 444 if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD) 445 show_usage = true; 446 447 if (show_usage || option_error) { 448 display_usage(progname, subcommand); 449 exit(option_error); 450 } 451 452 // Skip any options we consumed with getopt_long_only. 453 argc -= optind; 454 argv += optind; 455 lldb_private::Args inferior_arguments; 456 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); 457 458 Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain; 459 460 if (fd != SharedSocket::kInvalidFD) { 461 // Child process will handle the connection and exit. 462 if (gdbserver_port) 463 protocol = Socket::ProtocolTcp; 464 465 Log *log = GetLog(LLDBLog::Platform); 466 467 NativeSocket sockfd; 468 error = SharedSocket::GetNativeSocket(fd, sockfd); 469 if (error.Fail()) { 470 LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString()); 471 return socket_error; 472 } 473 474 GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port); 475 Socket *socket; 476 if (protocol == Socket::ProtocolTcp) 477 socket = new TCPSocket(sockfd, /*should_close=*/true, 478 /*child_processes_inherit=*/false); 479 else { 480 #if LLDB_ENABLE_POSIX 481 socket = new DomainSocket(sockfd, /*should_close=*/true, 482 /*child_processes_inherit=*/false); 483 #else 484 WithColor::error() << "lldb-platform child: Unix domain sockets are not " 485 "supported on this platform."; 486 return socket_error; 487 #endif 488 } 489 platform.SetConnection( 490 std::unique_ptr<Connection>(new ConnectionFileDescriptor(socket))); 491 client_handle(platform, inferior_arguments); 492 return 0; 493 } 494 495 if (gdbserver_port != 0 && 496 (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) { 497 WithColor::error() << llvm::formatv("Port number {0} is not in the " 498 "valid user port range of {1} - {2}\n", 499 gdbserver_port, LOW_PORT, HIGH_PORT); 500 return 1; 501 } 502 503 std::string address; 504 std::string gdb_address; 505 uint16_t platform_port = 0; 506 error = parse_listen_host_port(protocol, listen_host_port, address, 507 platform_port, gdb_address, gdbserver_port); 508 if (error.Fail()) { 509 printf("Failed to parse listen address: %s\n", error.AsCString()); 510 return socket_error; 511 } 512 513 std::unique_ptr<Socket> platform_sock = 514 Socket::Create(protocol, /*child_processes_inherit=*/false, error); 515 if (error.Fail()) { 516 printf("Failed to create platform socket: %s\n", error.AsCString()); 517 return socket_error; 518 } 519 error = platform_sock->Listen(address, backlog); 520 if (error.Fail()) { 521 printf("Failed to listen platform: %s\n", error.AsCString()); 522 return socket_error; 523 } 524 if (protocol == Socket::ProtocolTcp && platform_port == 0) 525 platform_port = 526 static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber(); 527 528 if (socket_file) { 529 error = save_socket_id_to_file( 530 protocol == Socket::ProtocolTcp 531 ? (platform_port ? llvm::to_string(platform_port) : "") 532 : address, 533 socket_file); 534 if (error.Fail()) { 535 fprintf(stderr, "failed to write socket id to %s: %s\n", 536 socket_file.GetPath().c_str(), error.AsCString()); 537 return 1; 538 } 539 } 540 541 std::unique_ptr<TCPSocket> gdb_sock; 542 // Update gdbserver_port if it is still 0 and protocol is tcp. 543 error = ListenGdbConnectionsIfNeeded(protocol, gdb_sock, gdb_address, 544 gdbserver_port); 545 if (error.Fail()) { 546 printf("Failed to listen gdb: %s\n", error.AsCString()); 547 return socket_error; 548 } 549 550 MainLoop main_loop; 551 { 552 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles = 553 platform_sock->Accept( 554 main_loop, [progname, gdbserver_port, &inferior_arguments, log_file, 555 log_channels, &main_loop, 556 &platform_handles](std::unique_ptr<Socket> sock_up) { 557 printf("Connection established.\n"); 558 Status error = spawn_process(progname, sock_up.get(), 559 gdbserver_port, inferior_arguments, 560 log_file, log_channels, main_loop); 561 if (error.Fail()) { 562 Log *log = GetLog(LLDBLog::Platform); 563 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString()); 564 WithColor::error() 565 << "spawn_process failed: " << error.AsCString() << "\n"; 566 if (!g_server) 567 main_loop.RequestTermination(); 568 } 569 if (!g_server) 570 platform_handles->clear(); 571 }); 572 if (!platform_handles) { 573 printf("Failed to accept platform: %s\n", 574 llvm::toString(platform_handles.takeError()).c_str()); 575 return socket_error; 576 } 577 578 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles = 579 AcceptGdbConnectionsIfNeeded(protocol, gdb_sock, main_loop, 580 gdbserver_port, inferior_arguments); 581 if (!gdb_handles) { 582 printf("Failed to accept gdb: %s\n", 583 llvm::toString(gdb_handles.takeError()).c_str()); 584 return socket_error; 585 } 586 587 main_loop.Run(); 588 } 589 590 fprintf(stderr, "lldb-server exiting...\n"); 591 592 return 0; 593 } 594