brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.6 KiB · 59b1eb4 Raw
668 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include <cerrno>10#if defined(__APPLE__)11#include <netinet/in.h>12#endif13#include <csignal>14#include <cstdint>15#include <cstdio>16#include <cstdlib>17#include <cstring>18#if !defined(_WIN32)19#include <sys/wait.h>20#endif21#include <fstream>22#include <optional>23 24#include "llvm/Option/ArgList.h"25#include "llvm/Option/OptTable.h"26#include "llvm/Option/Option.h"27#include "llvm/Support/FileSystem.h"28#include "llvm/Support/ScopedPrinter.h"29#include "llvm/Support/WithColor.h"30#include "llvm/Support/raw_ostream.h"31 32#include "LLDBServerUtilities.h"33#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"34#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"35#include "lldb/Host/ConnectionFileDescriptor.h"36#include "lldb/Host/FileSystem.h"37#include "lldb/Host/HostGetOpt.h"38#include "lldb/Host/HostInfo.h"39#include "lldb/Host/MainLoop.h"40#include "lldb/Host/OptionParser.h"41#include "lldb/Host/Socket.h"42#include "lldb/Host/common/TCPSocket.h"43#if LLDB_ENABLE_POSIX44#include "lldb/Host/posix/DomainSocket.h"45#endif46#include "lldb/Utility/FileSpec.h"47#include "lldb/Utility/LLDBLog.h"48#include "lldb/Utility/Status.h"49#include "lldb/Utility/UriParser.h"50 51using namespace lldb;52using namespace lldb_private;53using namespace lldb_private::lldb_server;54using namespace lldb_private::process_gdb_remote;55using namespace llvm;56 57// The test suite makes many connections in parallel, let's not miss any.58// The highest this should get reasonably is a function of the number59// of target CPUs. For now, let's just use 100.60static const int backlog = 100;61static const int socket_error = -1;62 63namespace {64using namespace llvm::opt;65 66enum ID {67  OPT_INVALID = 0, // This is not an option ID.68#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),69#include "PlatformOptions.inc"70#undef OPTION71};72 73#define OPTTABLE_STR_TABLE_CODE74#include "PlatformOptions.inc"75#undef OPTTABLE_STR_TABLE_CODE76 77#define OPTTABLE_PREFIXES_TABLE_CODE78#include "PlatformOptions.inc"79#undef OPTTABLE_PREFIXES_TABLE_CODE80 81static constexpr opt::OptTable::Info InfoTable[] = {82#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),83#include "PlatformOptions.inc"84#undef OPTION85};86 87class PlatformOptTable : public opt::GenericOptTable {88public:89  PlatformOptTable()90      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}91 92  void PrintHelp(llvm::StringRef Name) {93    std::string Usage =94        (Name + " [options] --listen <[host]:port> [[--] program args...]")95            .str();96 97    std::string Title = "lldb-server platform";98 99    OptTable::printHelp(llvm::outs(), Usage.c_str(), Title.c_str());100 101    llvm::outs() << R"(102DESCRIPTION103  Acts as a platform server for remote debugging. When LLDB clients connect,104  the platform server handles platform operations (file transfers, process105  launching) and spawns debug server instances (lldb-server gdbserver) to106  handle actual debugging sessions.107 108  By default, the server exits after handling one connection. Use --server109  to keep running and accept multiple connections sequentially.110 111EXAMPLES112  # Listen on port 1234, exit after first connection113  lldb-server platform --listen tcp://0.0.0.0:1234114 115  # Listen on port 5555, accept multiple connections116  lldb-server platform --server --listen tcp://localhost:5555117 118  # Listen on Unix domain socket119  lldb-server platform --listen unix:///tmp/lldb-server.sock120 121)";122  }123};124} // namespace125 126#if defined(__APPLE__)127#define LOW_PORT (IPPORT_RESERVED)128#define HIGH_PORT (IPPORT_HIFIRSTAUTO)129#else130#define LOW_PORT (1024u)131#define HIGH_PORT (49151u)132#endif133 134#if !defined(_WIN32)135// Watch for signals136static void signal_handler(int signo) {137  switch (signo) {138  case SIGHUP:139    // Use SIGINT first, if that does not work, use SIGHUP as a last resort.140    // And we should not call exit() here because it results in the global141    // destructors to be invoked and wreaking havoc on the threads still142    // running.143    llvm::errs() << "SIGHUP received, exiting lldb-server...\n";144    abort();145    break;146  }147}148#endif149 150static void display_usage(PlatformOptTable &Opts, const char *progname,151                          const char *subcommand) {152  std::string Name =153      (llvm::sys::path::filename(progname) + " " + subcommand).str();154  Opts.PrintHelp(Name);155}156 157static Status parse_listen_host_port(Socket::SocketProtocol &protocol,158                                     const std::string &listen_host_port,159                                     std::string &address,160                                     uint16_t &platform_port,161                                     std::string &gdb_address,162                                     const uint16_t gdbserver_port) {163  std::string hostname;164  // Try to match socket name as URL - e.g., tcp://localhost:5555165  if (std::optional<URI> uri = URI::Parse(listen_host_port)) {166    if (!Socket::FindProtocolByScheme(uri->scheme.str().c_str(), protocol)) {167      return Status::FromErrorStringWithFormat(168          "Unknown protocol scheme \"%s\".", uri->scheme.str().c_str());169    }170    if (protocol == Socket::ProtocolTcp) {171      hostname = uri->hostname;172      if (uri->port) {173        platform_port = *(uri->port);174      }175    } else176      address = listen_host_port.substr(uri->scheme.size() + strlen("://"));177  } else {178    // Try to match socket name as $host:port - e.g., localhost:5555179    llvm::Expected<Socket::HostAndPort> host_port =180        Socket::DecodeHostAndPort(listen_host_port);181    if (!llvm::errorToBool(host_port.takeError())) {182      protocol = Socket::ProtocolTcp;183      hostname = host_port->hostname;184      platform_port = host_port->port;185    } else186      address = listen_host_port;187  }188 189  if (protocol == Socket::ProtocolTcp) {190    if (platform_port != 0 && platform_port == gdbserver_port) {191      return Status::FromErrorStringWithFormat(192          "The same platform and gdb ports %u.", platform_port);193    }194    address = llvm::formatv("[{0}]:{1}", hostname, platform_port).str();195    gdb_address = llvm::formatv("[{0}]:{1}", hostname, gdbserver_port).str();196  } else {197    if (gdbserver_port) {198      return Status::FromErrorStringWithFormat(199          "--gdbserver-port %u is redundant for non-tcp protocol %s.",200          gdbserver_port, Socket::FindSchemeByProtocol(protocol));201    }202  }203  return Status();204}205 206static Status save_socket_id_to_file(const std::string &socket_id,207                                     const FileSpec &file_spec) {208  FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef());209  Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));210  if (error.Fail())211    return Status::FromErrorStringWithFormat(212        "Failed to create directory %s: %s", temp_file_spec.GetPath().c_str(),213        error.AsCString());214 215  Status status;216  if (auto Err = llvm::writeToOutput(file_spec.GetPath(),217                                     [&socket_id](llvm::raw_ostream &OS) {218                                       OS << socket_id;219                                       return llvm::Error::success();220                                     }))221    return Status::FromErrorStringWithFormat(222        "Failed to atomically write file %s: %s", file_spec.GetPath().c_str(),223        llvm::toString(std::move(Err)).c_str());224  return status;225}226 227static Status ListenGdbConnectionsIfNeeded(228    const Socket::SocketProtocol protocol, std::unique_ptr<TCPSocket> &gdb_sock,229    const std::string &gdb_address, uint16_t &gdbserver_port) {230  if (protocol != Socket::ProtocolTcp)231    return Status();232 233  gdb_sock = std::make_unique<TCPSocket>(/*should_close=*/true);234  Status error = gdb_sock->Listen(gdb_address, backlog);235  if (error.Fail())236    return error;237 238  if (gdbserver_port == 0)239    gdbserver_port = gdb_sock->GetLocalPortNumber();240 241  return Status();242}243 244static llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>245AcceptGdbConnectionsIfNeeded(const FileSpec &debugserver_path,246                             const Socket::SocketProtocol protocol,247                             std::unique_ptr<TCPSocket> &gdb_sock,248                             MainLoop &main_loop, const uint16_t gdbserver_port,249                             const lldb_private::Args &args) {250  if (protocol != Socket::ProtocolTcp)251    return std::vector<MainLoopBase::ReadHandleUP>();252 253  return gdb_sock->Accept(main_loop, [debugserver_path, gdbserver_port,254                                      &args](std::unique_ptr<Socket> sock_up) {255    Log *log = GetLog(LLDBLog::Platform);256    Status error;257    SharedSocket shared_socket(sock_up.get(), error);258    if (error.Fail()) {259      LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", error.AsCString());260      return;261    }262    lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID;263    std::string socket_name;264    GDBRemoteCommunicationServerPlatform platform(265        debugserver_path, Socket::ProtocolTcp, gdbserver_port);266    error = platform.LaunchGDBServer(args, child_pid, socket_name,267                                     shared_socket.GetSendableFD());268    if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) {269      error = shared_socket.CompleteSending(child_pid);270      if (error.Fail()) {271        Host::Kill(child_pid, SIGTERM);272        LLDB_LOGF(log, "gdbserver CompleteSending failed: %s",273                  error.AsCString());274        return;275      }276    }277  });278}279 280static void client_handle(GDBRemoteCommunicationServerPlatform &platform,281                          const lldb_private::Args &args) {282  if (!platform.IsConnected())283    return;284 285  if (args.GetArgumentCount() > 0) {286    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;287    std::string socket_name;288    Status error = platform.LaunchGDBServer(args, pid, socket_name,289                                            SharedSocket::kInvalidFD);290    if (error.Success())291      platform.SetPendingGdbServer(socket_name);292    else293      fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());294  }295 296  bool interrupt = false;297  bool done = false;298  Status error;299  while (!interrupt && !done) {300    if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,301                                          done) !=302        GDBRemoteCommunication::PacketResult::Success)303      break;304  }305 306  printf("Disconnected.\n");307}308 309static Status spawn_process(const char *progname, const FileSpec &prog,310                            const Socket *conn_socket, uint16_t gdb_port,311                            const lldb_private::Args &args,312                            const std::string &log_file,313                            const StringRef log_channels, MainLoop &main_loop,314                            bool multi_client) {315  Status error;316  SharedSocket shared_socket(conn_socket, error);317  if (error.Fail())318    return error;319 320  ProcessLaunchInfo launch_info;321 322  launch_info.SetExecutableFile(prog, false);323  launch_info.SetArg0(progname);324  Args &self_args = launch_info.GetArguments();325  self_args.AppendArgument(progname);326  self_args.AppendArgument(llvm::StringRef("platform"));327  self_args.AppendArgument(llvm::StringRef("--child-platform-fd"));328  self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD()));329  launch_info.AppendDuplicateFileAction((int64_t)shared_socket.GetSendableFD(),330                                        (int64_t)shared_socket.GetSendableFD());331  if (gdb_port) {332    self_args.AppendArgument(llvm::StringRef("--gdbserver-port"));333    self_args.AppendArgument(llvm::to_string(gdb_port));334  }335  if (!log_file.empty()) {336    self_args.AppendArgument(llvm::StringRef("--log-file"));337    self_args.AppendArgument(log_file);338  }339  if (!log_channels.empty()) {340    self_args.AppendArgument(llvm::StringRef("--log-channels"));341    self_args.AppendArgument(log_channels);342  }343  if (args.GetArgumentCount() > 0) {344    self_args.AppendArgument("--");345    self_args.AppendArguments(args);346  }347 348  launch_info.SetLaunchInSeparateProcessGroup(false);349 350  // Set up process monitor callback based on whether we're in server mode.351  if (multi_client)352    // In server mode: empty callback (don't terminate when child exits).353    launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});354  else355    // In single-client mode: terminate main loop when child exits.356    launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {357      main_loop.AddPendingCallback(358          [](MainLoopBase &loop) { loop.RequestTermination(); });359    });360 361  // Copy the current environment.362  launch_info.GetEnvironment() = Host::GetEnvironment();363 364  launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);365 366  // Close STDIN, STDOUT and STDERR.367  launch_info.AppendCloseFileAction(STDIN_FILENO);368  launch_info.AppendCloseFileAction(STDOUT_FILENO);369  launch_info.AppendCloseFileAction(STDERR_FILENO);370 371  // Redirect STDIN, STDOUT and STDERR to "/dev/null".372  launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);373  launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);374  launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);375 376  std::string cmd;377  self_args.GetCommandString(cmd);378 379  error = Host::LaunchProcess(launch_info);380  if (error.Fail())381    return error;382 383  lldb::pid_t child_pid = launch_info.GetProcessID();384  if (child_pid == LLDB_INVALID_PROCESS_ID)385    return Status::FromErrorString("invalid pid");386 387  LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}",388           cmd, child_pid);389 390  error = shared_socket.CompleteSending(child_pid);391  if (error.Fail()) {392    Host::Kill(child_pid, SIGTERM);393    return error;394  }395 396  return Status();397}398 399static FileSpec GetDebugserverPath() {400  if (const char *p = getenv("LLDB_DEBUGSERVER_PATH")) {401    FileSpec candidate(p);402    if (FileSystem::Instance().Exists(candidate))403      return candidate;404  }405#if defined(__APPLE__)406  FileSpec candidate = HostInfo::GetSupportExeDir();407  candidate.AppendPathComponent("debugserver");408  if (FileSystem::Instance().Exists(candidate))409    return candidate;410  return FileSpec();411#else412  // On non-apple platforms, *we* are the debug server.413  return HostInfo::GetProgramFileSpec();414#endif415}416 417// main418int main_platform(int argc, char *argv[]) {419  const char *progname = argv[0];420  const char *subcommand = argv[1];421  argc--;422  argv++;423#if !defined(_WIN32)424  signal(SIGPIPE, SIG_IGN);425  signal(SIGHUP, signal_handler);426#endif427 428  // Special handling for 'help' as first argument.429  if (argc > 0 && strcmp(argv[0], "help") == 0) {430    PlatformOptTable Opts;431    display_usage(Opts, progname, subcommand);432    return EXIT_SUCCESS;433  }434 435  Status error;436  shared_fd_t fd = SharedSocket::kInvalidFD;437  uint16_t gdbserver_port = 0;438  FileSpec socket_file;439 440  PlatformOptTable Opts;441  BumpPtrAllocator Alloc;442  StringSaver Saver(Alloc);443  bool HasError = false;444 445  opt::InputArgList Args =446      Opts.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](llvm::StringRef Msg) {447        WithColor::error() << Msg << "\n";448        HasError = true;449      });450 451  std::string Name =452      (llvm::sys::path::filename(progname) + " " + subcommand).str();453  std::string HelpText =454      "Use '" + Name + " --help' for a complete list of options.\n";455 456  if (HasError) {457    llvm::errs() << HelpText;458    return EXIT_FAILURE;459  }460 461  if (Args.hasArg(OPT_help)) {462    display_usage(Opts, progname, subcommand);463    return EXIT_SUCCESS;464  }465 466  // Parse arguments.467  std::string listen_host_port = Args.getLastArgValue(OPT_listen).str();468  std::string log_file = Args.getLastArgValue(OPT_log_file).str();469  StringRef log_channels = Args.getLastArgValue(OPT_log_channels);470  bool multi_client = Args.hasArg(OPT_server);471  [[maybe_unused]] bool debug = Args.hasArg(OPT_debug);472  [[maybe_unused]] bool verbose = Args.hasArg(OPT_verbose);473 474  if (Args.hasArg(OPT_socket_file)) {475    socket_file.SetFile(Args.getLastArgValue(OPT_socket_file),476                        FileSpec::Style::native);477  }478 479  if (Args.hasArg(OPT_gdbserver_port)) {480    if (!llvm::to_integer(Args.getLastArgValue(OPT_gdbserver_port),481                          gdbserver_port)) {482      WithColor::error() << "invalid --gdbserver-port value\n";483      return EXIT_FAILURE;484    }485  }486 487  if (Args.hasArg(OPT_child_platform_fd)) {488    uint64_t _fd;489    if (!llvm::to_integer(Args.getLastArgValue(OPT_child_platform_fd), _fd)) {490      WithColor::error() << "invalid --child-platform-fd value\n";491      return EXIT_FAILURE;492    }493    fd = (shared_fd_t)_fd;494  }495 496  if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))497    return -1;498 499  // Print usage and exit if no listening port is specified.500  if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD) {501    WithColor::error() << "either --listen or --child-platform-fd is required\n"502                       << HelpText;503    return EXIT_FAILURE;504  }505 506  // Get remaining arguments for inferior.507  std::vector<llvm::StringRef> Inputs;508  for (opt::Arg *Arg : Args.filtered(OPT_INPUT))509    Inputs.push_back(Arg->getValue());510  if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {511    for (const char *Val : Arg->getValues())512      Inputs.push_back(Val);513  }514 515  lldb_private::Args inferior_arguments;516  if (!Inputs.empty()) {517    std::vector<const char *> args_ptrs;518    for (const auto &Input : Inputs)519      args_ptrs.push_back(Input.data());520    inferior_arguments.SetArguments(args_ptrs.size(), args_ptrs.data());521  }522 523  FileSpec debugserver_path = GetDebugserverPath();524  if (!debugserver_path) {525    WithColor::error(errs()) << "Could not find debug server executable.";526    return EXIT_FAILURE;527  }528 529  Log *log = GetLog(LLDBLog::Platform);530  if (fd != SharedSocket::kInvalidFD) {531    // Child process will handle the connection and exit.532    NativeSocket sockfd;533    error = SharedSocket::GetNativeSocket(fd, sockfd);534    if (error.Fail()) {535      LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString());536      return socket_error;537    }538 539    std::unique_ptr<Socket> socket;540    if (gdbserver_port) {541      socket = std::make_unique<TCPSocket>(sockfd, /*should_close=*/true);542    } else {543#if LLDB_ENABLE_POSIX544      llvm::Expected<std::unique_ptr<DomainSocket>> domain_socket =545          DomainSocket::FromBoundNativeSocket(sockfd, /*should_close=*/true);546      if (!domain_socket) {547        LLDB_LOG_ERROR(log, domain_socket.takeError(),548                       "Failed to create socket: {0}");549        return socket_error;550      }551      socket = std::move(domain_socket.get());552#else553      WithColor::error() << "lldb-platform child: Unix domain sockets are not "554                            "supported on this platform.";555      return socket_error;556#endif557    }558 559    GDBRemoteCommunicationServerPlatform platform(560        debugserver_path, socket->GetSocketProtocol(), gdbserver_port);561    platform.SetConnection(562        std::make_unique<ConnectionFileDescriptor>(std::move(socket)));563    client_handle(platform, inferior_arguments);564    return EXIT_SUCCESS;565  }566 567  if (gdbserver_port != 0 &&568      (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) {569    WithColor::error() << llvm::formatv("Port number {0} is not in the "570                                        "valid user port range of {1} - {2}\n",571                                        gdbserver_port, LOW_PORT, HIGH_PORT);572    return EXIT_FAILURE;573  }574 575  Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain;576  std::string address;577  std::string gdb_address;578  uint16_t platform_port = 0;579  error = parse_listen_host_port(protocol, listen_host_port, address,580                                 platform_port, gdb_address, gdbserver_port);581  if (error.Fail()) {582    printf("Failed to parse listen address: %s\n", error.AsCString());583    return socket_error;584  }585 586  std::unique_ptr<Socket> platform_sock = Socket::Create(protocol, error);587  if (error.Fail()) {588    printf("Failed to create platform socket: %s\n", error.AsCString());589    return socket_error;590  }591  error = platform_sock->Listen(address, backlog);592  if (error.Fail()) {593    printf("Failed to listen platform: %s\n", error.AsCString());594    return socket_error;595  }596  if (protocol == Socket::ProtocolTcp && platform_port == 0)597    platform_port =598        static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber();599 600  if (socket_file) {601    error = save_socket_id_to_file(602        protocol == Socket::ProtocolTcp603            ? (platform_port ? llvm::to_string(platform_port) : "")604            : address,605        socket_file);606    if (error.Fail()) {607      fprintf(stderr, "failed to write socket id to %s: %s\n",608              socket_file.GetPath().c_str(), error.AsCString());609      return EXIT_FAILURE;610    }611  }612 613  std::unique_ptr<TCPSocket> gdb_sock;614  // Update gdbserver_port if it is still 0 and protocol is tcp.615  error = ListenGdbConnectionsIfNeeded(protocol, gdb_sock, gdb_address,616                                       gdbserver_port);617  if (error.Fail()) {618    printf("Failed to listen gdb: %s\n", error.AsCString());619    return socket_error;620  }621 622  MainLoop main_loop;623  {624    llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =625        platform_sock->Accept(626            main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,627                        log_channels, &main_loop, multi_client,628                        &platform_handles](std::unique_ptr<Socket> sock_up) {629              printf("Connection established.\n");630              Status error = spawn_process(631                  progname, HostInfo::GetProgramFileSpec(), sock_up.get(),632                  gdbserver_port, inferior_arguments, log_file, log_channels,633                  main_loop, multi_client);634              if (error.Fail()) {635                Log *log = GetLog(LLDBLog::Platform);636                LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());637                WithColor::error()638                    << "spawn_process failed: " << error.AsCString() << "\n";639                if (!multi_client)640                  main_loop.RequestTermination();641              }642              if (!multi_client)643                platform_handles->clear();644            });645    if (!platform_handles) {646      printf("Failed to accept platform: %s\n",647             llvm::toString(platform_handles.takeError()).c_str());648      return socket_error;649    }650 651    llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles =652        AcceptGdbConnectionsIfNeeded(debugserver_path, protocol, gdb_sock,653                                     main_loop, gdbserver_port,654                                     inferior_arguments);655    if (!gdb_handles) {656      printf("Failed to accept gdb: %s\n",657             llvm::toString(gdb_handles.takeError()).c_str());658      return socket_error;659    }660 661    main_loop.Run();662  }663 664  fprintf(stderr, "lldb-server exiting...\n");665 666  return EXIT_SUCCESS;667}668