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/FileSystem.h" 34 #include "lldb/Host/HostGetOpt.h" 35 #include "lldb/Host/HostInfo.h" 36 #include "lldb/Host/MainLoop.h" 37 #include "lldb/Host/OptionParser.h" 38 #include "lldb/Host/Socket.h" 39 #include "lldb/Host/common/TCPSocket.h" 40 #if LLDB_ENABLE_POSIX 41 #include "lldb/Host/posix/DomainSocket.h" 42 #endif 43 #include "lldb/Utility/FileSpec.h" 44 #include "lldb/Utility/LLDBLog.h" 45 #include "lldb/Utility/Status.h" 46 #include "lldb/Utility/UriParser.h" 47 48 using namespace lldb; 49 using namespace lldb_private; 50 using namespace lldb_private::lldb_server; 51 using namespace lldb_private::process_gdb_remote; 52 using namespace llvm; 53 54 // The test suite makes many connections in parallel, let's not miss any. 55 // The highest this should get reasonably is a function of the number 56 // of target CPUs. For now, let's just use 100. 57 static const int backlog = 100; 58 static const int socket_error = -1; 59 static int g_debug = 0; 60 static int g_verbose = 0; 61 static int g_server = 0; 62 63 // option descriptors for getopt_long_only() 64 static struct option g_long_options[] = { 65 {"debug", no_argument, &g_debug, 1}, 66 {"verbose", no_argument, &g_verbose, 1}, 67 {"log-file", required_argument, nullptr, 'l'}, 68 {"log-channels", required_argument, nullptr, 'c'}, 69 {"listen", required_argument, nullptr, 'L'}, 70 {"gdbserver-port", required_argument, nullptr, 'P'}, 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>(/*should_close=*/true); 185 Status error = gdb_sock->Listen(gdb_address, backlog); 186 if (error.Fail()) 187 return error; 188 189 if (gdbserver_port == 0) 190 gdbserver_port = gdb_sock->GetLocalPortNumber(); 191 192 return Status(); 193 } 194 195 static llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> 196 AcceptGdbConnectionsIfNeeded(const FileSpec &debugserver_path, 197 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, [debugserver_path, 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( 216 debugserver_path, Socket::ProtocolTcp, 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 FileSpec &prog, 261 const Socket *conn_socket, uint16_t gdb_port, 262 const lldb_private::Args &args, 263 const std::string &log_file, 264 const StringRef log_channels, MainLoop &main_loop) { 265 Status error; 266 SharedSocket shared_socket(conn_socket, error); 267 if (error.Fail()) 268 return error; 269 270 ProcessLaunchInfo launch_info; 271 272 launch_info.SetExecutableFile(prog, false); 273 launch_info.SetArg0(progname); 274 Args &self_args = launch_info.GetArguments(); 275 self_args.AppendArgument(progname); 276 self_args.AppendArgument(llvm::StringRef("platform")); 277 self_args.AppendArgument(llvm::StringRef("--child-platform-fd")); 278 self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD())); 279 launch_info.AppendDuplicateFileAction((int64_t)shared_socket.GetSendableFD(), 280 (int64_t)shared_socket.GetSendableFD()); 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 static FileSpec GetDebugserverPath() { 347 if (const char *p = getenv("LLDB_DEBUGSERVER_PATH")) { 348 FileSpec candidate(p); 349 if (FileSystem::Instance().Exists(candidate)) 350 return candidate; 351 } 352 #if defined(__APPLE__) 353 FileSpec candidate = HostInfo::GetSupportExeDir(); 354 candidate.AppendPathComponent("debugserver"); 355 if (FileSystem::Instance().Exists(candidate)) 356 return candidate; 357 return FileSpec(); 358 #else 359 // On non-apple platforms, *we* are the debug server. 360 return HostInfo::GetProgramFileSpec(); 361 #endif 362 } 363 364 // main 365 int main_platform(int argc, char *argv[]) { 366 const char *progname = argv[0]; 367 const char *subcommand = argv[1]; 368 argc--; 369 argv++; 370 #if !defined(_WIN32) 371 signal(SIGPIPE, SIG_IGN); 372 signal(SIGHUP, signal_handler); 373 #endif 374 int long_option_index = 0; 375 Status error; 376 std::string listen_host_port; 377 int ch; 378 379 std::string log_file; 380 StringRef 381 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 382 383 shared_fd_t fd = SharedSocket::kInvalidFD; 384 385 uint16_t gdbserver_port = 0; 386 387 FileSpec socket_file; 388 bool show_usage = false; 389 int option_error = 0; 390 391 std::string short_options(OptionParser::GetShortOptionString(g_long_options)); 392 393 #if __GLIBC__ 394 optind = 0; 395 #else 396 optreset = 1; 397 optind = 1; 398 #endif 399 400 while ((ch = getopt_long_only(argc, argv, short_options.c_str(), 401 g_long_options, &long_option_index)) != -1) { 402 switch (ch) { 403 case 0: // Any optional that auto set themselves will return 0 404 break; 405 406 case 'L': 407 listen_host_port.append(optarg); 408 break; 409 410 case 'l': // Set Log File 411 if (optarg && optarg[0]) 412 log_file.assign(optarg); 413 break; 414 415 case 'c': // Log Channels 416 if (optarg && optarg[0]) 417 log_channels = StringRef(optarg); 418 break; 419 420 case 'f': // Socket file 421 if (optarg && optarg[0]) 422 socket_file.SetFile(optarg, FileSpec::Style::native); 423 break; 424 425 case 'P': 426 case 'm': 427 case 'M': { 428 uint16_t portnum; 429 if (!llvm::to_integer(optarg, portnum)) { 430 WithColor::error() << "invalid port number string " << optarg << "\n"; 431 option_error = 2; 432 break; 433 } 434 // Note the condition gdbserver_port > HIGH_PORT is valid in case of using 435 // --child-platform-fd. Check gdbserver_port later. 436 if (ch == 'P') 437 gdbserver_port = portnum; 438 else if (gdbserver_port == 0) 439 gdbserver_port = portnum; 440 } break; 441 442 case 2: { 443 uint64_t _fd; 444 if (!llvm::to_integer(optarg, _fd)) { 445 WithColor::error() << "invalid fd " << optarg << "\n"; 446 option_error = 6; 447 } else 448 fd = (shared_fd_t)_fd; 449 } break; 450 451 case 'h': /* fall-through is intentional */ 452 case '?': 453 show_usage = true; 454 break; 455 } 456 } 457 458 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) 459 return -1; 460 461 // Print usage and exit if no listening port is specified. 462 if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD) 463 show_usage = true; 464 465 if (show_usage || option_error) { 466 display_usage(progname, subcommand); 467 exit(option_error); 468 } 469 470 // Skip any options we consumed with getopt_long_only. 471 argc -= optind; 472 argv += optind; 473 lldb_private::Args inferior_arguments; 474 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); 475 476 FileSpec debugserver_path = GetDebugserverPath(); 477 if (!debugserver_path) { 478 WithColor::error(errs()) << "Could not find debug server executable."; 479 return EXIT_FAILURE; 480 } 481 482 Log *log = GetLog(LLDBLog::Platform); 483 if (fd != SharedSocket::kInvalidFD) { 484 // Child process will handle the connection and exit. 485 NativeSocket sockfd; 486 error = SharedSocket::GetNativeSocket(fd, sockfd); 487 if (error.Fail()) { 488 LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString()); 489 return socket_error; 490 } 491 492 std::unique_ptr<Socket> socket; 493 if (gdbserver_port) { 494 socket = std::make_unique<TCPSocket>(sockfd, /*should_close=*/true); 495 } else { 496 #if LLDB_ENABLE_POSIX 497 llvm::Expected<std::unique_ptr<DomainSocket>> domain_socket = 498 DomainSocket::FromBoundNativeSocket(sockfd, /*should_close=*/true); 499 if (!domain_socket) { 500 LLDB_LOG_ERROR(log, domain_socket.takeError(), 501 "Failed to create socket: {0}"); 502 return socket_error; 503 } 504 socket = std::move(domain_socket.get()); 505 #else 506 WithColor::error() << "lldb-platform child: Unix domain sockets are not " 507 "supported on this platform."; 508 return socket_error; 509 #endif 510 } 511 512 GDBRemoteCommunicationServerPlatform platform( 513 debugserver_path, socket->GetSocketProtocol(), gdbserver_port); 514 platform.SetConnection( 515 std::make_unique<ConnectionFileDescriptor>(std::move(socket))); 516 client_handle(platform, inferior_arguments); 517 return 0; 518 } 519 520 if (gdbserver_port != 0 && 521 (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) { 522 WithColor::error() << llvm::formatv("Port number {0} is not in the " 523 "valid user port range of {1} - {2}\n", 524 gdbserver_port, LOW_PORT, HIGH_PORT); 525 return 1; 526 } 527 528 Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain; 529 std::string address; 530 std::string gdb_address; 531 uint16_t platform_port = 0; 532 error = parse_listen_host_port(protocol, listen_host_port, address, 533 platform_port, gdb_address, gdbserver_port); 534 if (error.Fail()) { 535 printf("Failed to parse listen address: %s\n", error.AsCString()); 536 return socket_error; 537 } 538 539 std::unique_ptr<Socket> platform_sock = Socket::Create(protocol, error); 540 if (error.Fail()) { 541 printf("Failed to create platform socket: %s\n", error.AsCString()); 542 return socket_error; 543 } 544 error = platform_sock->Listen(address, backlog); 545 if (error.Fail()) { 546 printf("Failed to listen platform: %s\n", error.AsCString()); 547 return socket_error; 548 } 549 if (protocol == Socket::ProtocolTcp && platform_port == 0) 550 platform_port = 551 static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber(); 552 553 if (socket_file) { 554 error = save_socket_id_to_file( 555 protocol == Socket::ProtocolTcp 556 ? (platform_port ? llvm::to_string(platform_port) : "") 557 : address, 558 socket_file); 559 if (error.Fail()) { 560 fprintf(stderr, "failed to write socket id to %s: %s\n", 561 socket_file.GetPath().c_str(), error.AsCString()); 562 return 1; 563 } 564 } 565 566 std::unique_ptr<TCPSocket> gdb_sock; 567 // Update gdbserver_port if it is still 0 and protocol is tcp. 568 error = ListenGdbConnectionsIfNeeded(protocol, gdb_sock, gdb_address, 569 gdbserver_port); 570 if (error.Fail()) { 571 printf("Failed to listen gdb: %s\n", error.AsCString()); 572 return socket_error; 573 } 574 575 MainLoop main_loop; 576 { 577 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles = 578 platform_sock->Accept( 579 main_loop, [progname, gdbserver_port, &inferior_arguments, log_file, 580 log_channels, &main_loop, 581 &platform_handles](std::unique_ptr<Socket> sock_up) { 582 printf("Connection established.\n"); 583 Status error = spawn_process( 584 progname, HostInfo::GetProgramFileSpec(), sock_up.get(), 585 gdbserver_port, inferior_arguments, log_file, log_channels, 586 main_loop); 587 if (error.Fail()) { 588 Log *log = GetLog(LLDBLog::Platform); 589 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString()); 590 WithColor::error() 591 << "spawn_process failed: " << error.AsCString() << "\n"; 592 if (!g_server) 593 main_loop.RequestTermination(); 594 } 595 if (!g_server) 596 platform_handles->clear(); 597 }); 598 if (!platform_handles) { 599 printf("Failed to accept platform: %s\n", 600 llvm::toString(platform_handles.takeError()).c_str()); 601 return socket_error; 602 } 603 604 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles = 605 AcceptGdbConnectionsIfNeeded(debugserver_path, protocol, gdb_sock, 606 main_loop, gdbserver_port, 607 inferior_arguments); 608 if (!gdb_handles) { 609 printf("Failed to accept gdb: %s\n", 610 llvm::toString(gdb_handles.takeError()).c_str()); 611 return socket_error; 612 } 613 614 main_loop.Run(); 615 } 616 617 fprintf(stderr, "lldb-server exiting...\n"); 618 619 return 0; 620 } 621