diff options
Diffstat (limited to 'lldb/tools/lldb-server/lldb-platform.cpp')
-rw-r--r-- | lldb/tools/lldb-server/lldb-platform.cpp | 634 |
1 files changed, 302 insertions, 332 deletions
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp index 3292080da63..d6bfaa24ee7 100644 --- a/lldb/tools/lldb-server/lldb-platform.cpp +++ b/lldb/tools/lldb-server/lldb-platform.cpp @@ -26,6 +26,10 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" +#include "Acceptor.h" +#include "LLDBServerUtilities.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" +#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" #include "lldb/Core/Error.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" @@ -33,10 +37,6 @@ #include "lldb/Host/HostGetOpt.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/common/TCPSocket.h" -#include "Acceptor.h" -#include "LLDBServerUtilities.h" -#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" -#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" using namespace lldb; using namespace lldb_private; @@ -52,365 +52,335 @@ static int g_debug = 0; static int g_verbose = 0; static int g_server = 0; -static struct option g_long_options[] = -{ - { "debug", no_argument, &g_debug, 1 }, - { "verbose", no_argument, &g_verbose, 1 }, - { "log-file", required_argument, NULL, 'l' }, - { "log-channels", required_argument, NULL, 'c' }, - { "listen", required_argument, NULL, 'L' }, - { "port-offset", required_argument, NULL, 'p' }, - { "gdbserver-port", required_argument, NULL, 'P' }, - { "min-gdbserver-port", required_argument, NULL, 'm' }, - { "max-gdbserver-port", required_argument, NULL, 'M' }, - { "socket-file", required_argument, NULL, 'f' }, - { "server", no_argument, &g_server, 1 }, - { NULL, 0, NULL, 0 } -}; - -#if defined (__APPLE__) -#define LOW_PORT (IPPORT_RESERVED) -#define HIGH_PORT (IPPORT_HIFIRSTAUTO) +static struct option g_long_options[] = { + {"debug", no_argument, &g_debug, 1}, + {"verbose", no_argument, &g_verbose, 1}, + {"log-file", required_argument, NULL, 'l'}, + {"log-channels", required_argument, NULL, 'c'}, + {"listen", required_argument, NULL, 'L'}, + {"port-offset", required_argument, NULL, 'p'}, + {"gdbserver-port", required_argument, NULL, 'P'}, + {"min-gdbserver-port", required_argument, NULL, 'm'}, + {"max-gdbserver-port", required_argument, NULL, 'M'}, + {"socket-file", required_argument, NULL, 'f'}, + {"server", no_argument, &g_server, 1}, + {NULL, 0, NULL, 0}}; + +#if defined(__APPLE__) +#define LOW_PORT (IPPORT_RESERVED) +#define HIGH_PORT (IPPORT_HIFIRSTAUTO) #else -#define LOW_PORT (1024u) -#define HIGH_PORT (49151u) +#define LOW_PORT (1024u) +#define HIGH_PORT (49151u) #endif //---------------------------------------------------------------------- // Watch for signals //---------------------------------------------------------------------- -static void -signal_handler(int signo) -{ - switch (signo) - { - case SIGHUP: - // Use SIGINT first, if that does not work, use SIGHUP as a last resort. - // And we should not call exit() here because it results in the global destructors - // to be invoked and wreaking havoc on the threads still running. - Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-server...\n"); - abort(); - break; - } +static void signal_handler(int signo) { + switch (signo) { + case SIGHUP: + // Use SIGINT first, if that does not work, use SIGHUP as a last resort. + // And we should not call exit() here because it results in the global + // destructors + // to be invoked and wreaking havoc on the threads still running. + Host::SystemLog(Host::eSystemLogWarning, + "SIGHUP received, exiting lldb-server...\n"); + abort(); + break; + } } -static void -display_usage (const char *progname, const char *subcommand) -{ - fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port\n", progname, subcommand); - exit(0); +static void display_usage(const char *progname, const char *subcommand) { + fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels " + "log-channel-list] [--port-file port-file-path] --server " + "--listen port\n", + progname, subcommand); + exit(0); } -static Error -save_socket_id_to_file(const std::string &socket_id, const FileSpec &file_spec) -{ - FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false); - auto error = FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault); - if (error.Fail()) - return Error("Failed to create directory %s: %s", temp_file_spec.GetCString(), error.AsCString()); - - llvm::SmallString<PATH_MAX> temp_file_path; - temp_file_spec.AppendPathComponent("port-file.%%%%%%"); - auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetCString(), temp_file_path); - if (err_code) - return Error("Failed to create temp file: %s", err_code.message().c_str()); - - llvm::FileRemover tmp_file_remover(temp_file_path.c_str()); - - { - std::ofstream temp_file(temp_file_path.c_str(), std::ios::out); - if (!temp_file.is_open()) - return Error("Failed to open temp file %s", temp_file_path.c_str()); - temp_file << socket_id; - } - - err_code = llvm::sys::fs::rename(temp_file_path.c_str(), file_spec.GetPath().c_str()); - if (err_code) - return Error("Failed to rename file %s to %s: %s", - temp_file_path.c_str(), file_spec.GetPath().c_str(), err_code.message().c_str()); - - tmp_file_remover.releaseFile(); - return Error(); +static Error save_socket_id_to_file(const std::string &socket_id, + const FileSpec &file_spec) { + FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false); + auto error = FileSystem::MakeDirectory(temp_file_spec, + eFilePermissionsDirectoryDefault); + if (error.Fail()) + return Error("Failed to create directory %s: %s", + temp_file_spec.GetCString(), error.AsCString()); + + llvm::SmallString<PATH_MAX> temp_file_path; + temp_file_spec.AppendPathComponent("port-file.%%%%%%"); + auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetCString(), + temp_file_path); + if (err_code) + return Error("Failed to create temp file: %s", err_code.message().c_str()); + + llvm::FileRemover tmp_file_remover(temp_file_path.c_str()); + + { + std::ofstream temp_file(temp_file_path.c_str(), std::ios::out); + if (!temp_file.is_open()) + return Error("Failed to open temp file %s", temp_file_path.c_str()); + temp_file << socket_id; + } + + err_code = llvm::sys::fs::rename(temp_file_path.c_str(), + file_spec.GetPath().c_str()); + if (err_code) + return Error("Failed to rename file %s to %s: %s", temp_file_path.c_str(), + file_spec.GetPath().c_str(), err_code.message().c_str()); + + tmp_file_remover.releaseFile(); + return Error(); } //---------------------------------------------------------------------- // main //---------------------------------------------------------------------- -int -main_platform (int argc, char *argv[]) -{ - const char *progname = argv[0]; - const char *subcommand = argv[1]; - argc--; - argv++; - signal (SIGPIPE, SIG_IGN); - signal (SIGHUP, signal_handler); - int long_option_index = 0; - Error error; - std::string listen_host_port; - int ch; - - std::string log_file; - StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" - - GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap; - int min_gdbserver_port = 0; - int max_gdbserver_port = 0; - uint16_t port_offset = 0; - - FileSpec socket_file; - bool show_usage = false; - int option_error = 0; - int socket_error = -1; - - std::string short_options(OptionParser::GetShortOptionString(g_long_options)); - +int main_platform(int argc, char *argv[]) { + const char *progname = argv[0]; + const char *subcommand = argv[1]; + argc--; + argv++; + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, signal_handler); + int long_option_index = 0; + Error error; + std::string listen_host_port; + int ch; + + std::string log_file; + StringRef + log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" + + GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap; + int min_gdbserver_port = 0; + int max_gdbserver_port = 0; + uint16_t port_offset = 0; + + FileSpec socket_file; + bool show_usage = false; + int option_error = 0; + int socket_error = -1; + + std::string short_options(OptionParser::GetShortOptionString(g_long_options)); + #if __GLIBC__ - optind = 0; + optind = 0; #else - optreset = 1; - optind = 1; + optreset = 1; + optind = 1; #endif - while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1) - { - switch (ch) - { - case 0: // Any optional that auto set themselves will return 0 - break; - - case 'L': - listen_host_port.append (optarg); - break; - - case 'l': // Set Log File - if (optarg && optarg[0]) - log_file.assign(optarg); - break; - - case 'c': // Log Channels - if (optarg && optarg[0]) - log_channels = StringRef(optarg); - break; - - case 'f': // Socket file - if (optarg && optarg[0]) - socket_file.SetFile(optarg, false); - break; - - case 'p': - { - char *end = NULL; - long tmp_port_offset = strtoul(optarg, &end, 0); - if (end && *end == '\0') - { - if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) - { - port_offset = (uint16_t)tmp_port_offset; - } - else - { - fprintf (stderr, "error: port offset %li is not in the valid user port range of %u - %u\n", tmp_port_offset, LOW_PORT, HIGH_PORT); - option_error = 5; - } - } - else - { - fprintf (stderr, "error: invalid port offset string %s\n", optarg); - option_error = 4; - } - } - break; - - case 'P': - case 'm': - case 'M': - { - char *end = NULL; - long portnum = strtoul(optarg, &end, 0); - if (end && *end == '\0') - { - if (LOW_PORT <= portnum && portnum <= HIGH_PORT) - { - if (ch == 'P') - gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID; - else if (ch == 'm') - min_gdbserver_port = portnum; - else - max_gdbserver_port = portnum; - } - else - { - fprintf (stderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT); - option_error = 1; - } - } - else - { - fprintf (stderr, "error: invalid port number string %s\n", optarg); - option_error = 2; - } - } - break; - - case 'h': /* fall-through is intentional */ - case '?': - show_usage = true; - break; + while ((ch = getopt_long_only(argc, argv, short_options.c_str(), + g_long_options, &long_option_index)) != -1) { + switch (ch) { + case 0: // Any optional that auto set themselves will return 0 + break; + + case 'L': + listen_host_port.append(optarg); + break; + + case 'l': // Set Log File + if (optarg && optarg[0]) + log_file.assign(optarg); + break; + + case 'c': // Log Channels + if (optarg && optarg[0]) + log_channels = StringRef(optarg); + break; + + case 'f': // Socket file + if (optarg && optarg[0]) + socket_file.SetFile(optarg, false); + break; + + case 'p': { + char *end = NULL; + long tmp_port_offset = strtoul(optarg, &end, 0); + if (end && *end == '\0') { + if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) { + port_offset = (uint16_t)tmp_port_offset; + } else { + fprintf(stderr, "error: port offset %li is not in the valid user " + "port range of %u - %u\n", + tmp_port_offset, LOW_PORT, HIGH_PORT); + option_error = 5; } + } else { + fprintf(stderr, "error: invalid port offset string %s\n", optarg); + option_error = 4; + } + } break; + + case 'P': + case 'm': + case 'M': { + char *end = NULL; + long portnum = strtoul(optarg, &end, 0); + if (end && *end == '\0') { + if (LOW_PORT <= portnum && portnum <= HIGH_PORT) { + if (ch == 'P') + gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID; + else if (ch == 'm') + min_gdbserver_port = portnum; + else + max_gdbserver_port = portnum; + } else { + fprintf(stderr, "error: port number %li is not in the valid user " + "port range of %u - %u\n", + portnum, LOW_PORT, HIGH_PORT); + option_error = 1; + } + } else { + fprintf(stderr, "error: invalid port number string %s\n", optarg); + option_error = 2; + } + } break; + + case 'h': /* fall-through is intentional */ + case '?': + show_usage = true; + break; + } + } + + if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) + return -1; + + // Make a port map for a port range that was specified. + if (min_gdbserver_port < max_gdbserver_port) { + for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) + gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; + } else if (min_gdbserver_port != max_gdbserver_port) { + fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than " + "--max-gdbserver-port (%u)\n", + min_gdbserver_port, max_gdbserver_port); + option_error = 3; + } + + // Print usage and exit if no listening port is specified. + if (listen_host_port.empty()) + show_usage = true; + + if (show_usage || option_error) { + display_usage(progname, subcommand); + exit(option_error); + } + + // Skip any options we consumed with getopt_long_only. + argc -= optind; + argv += optind; + lldb_private::Args inferior_arguments; + inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); + + const bool children_inherit_listen_socket = false; + // the test suite makes many connections in parallel, let's not miss any. + // The highest this should get reasonably is a function of the number + // of target CPUs. For now, let's just use 100. + const int backlog = 100; + + std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create( + listen_host_port, children_inherit_listen_socket, error)); + if (error.Fail()) { + fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); + exit(socket_error); + } + + error = acceptor_up->Listen(backlog); + if (error.Fail()) { + printf("failed to listen: %s\n", error.AsCString()); + exit(socket_error); + } + if (socket_file) { + error = + save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); + if (error.Fail()) { + fprintf(stderr, "failed to write socket id to %s: %s\n", + socket_file.GetPath().c_str(), error.AsCString()); + return 1; } + } - if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) - return -1; + do { + GDBRemoteCommunicationServerPlatform platform( + acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); - // Make a port map for a port range that was specified. - if (min_gdbserver_port < max_gdbserver_port) - { - for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) - gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; - } - else if (min_gdbserver_port != max_gdbserver_port) - { - fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port); - option_error = 3; - } + if (port_offset > 0) + platform.SetPortOffset(port_offset); - // Print usage and exit if no listening port is specified. - if (listen_host_port.empty()) - show_usage = true; - - if (show_usage || option_error) - { - display_usage(progname, subcommand); - exit(option_error); + if (!gdbserver_portmap.empty()) { + platform.SetPortMap(std::move(gdbserver_portmap)); } - // Skip any options we consumed with getopt_long_only. - argc -= optind; - argv += optind; - lldb_private::Args inferior_arguments; - inferior_arguments.SetArguments(argc, const_cast<const char**>(argv)); - - const bool children_inherit_listen_socket = false; - // the test suite makes many connections in parallel, let's not miss any. - // The highest this should get reasonably is a function of the number - // of target CPUs. For now, let's just use 100. - const int backlog = 100; - - std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(listen_host_port, children_inherit_listen_socket, error)); - if (error.Fail()) - { - fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); - exit(socket_error); + const bool children_inherit_accept_socket = true; + Connection *conn = nullptr; + error = acceptor_up->Accept(children_inherit_accept_socket, conn); + if (error.Fail()) { + printf("error: %s\n", error.AsCString()); + exit(socket_error); } - - error = acceptor_up->Listen(backlog); - if (error.Fail()) - { - printf("failed to listen: %s\n", error.AsCString()); - exit(socket_error); + printf("Connection established.\n"); + if (g_server) { + // Collect child zombie processes. + while (waitpid(-1, nullptr, WNOHANG) > 0) + ; + if (fork()) { + // Parent doesn't need a connection to the lldb client + delete conn; + + // Parent will continue to listen for new connections. + continue; + } else { + // Child process will handle the connection and exit. + g_server = 0; + // Listening socket is owned by parent process. + acceptor_up.release(); + } + } else { + // If not running as a server, this process will not accept + // connections while a connection is active. + acceptor_up.reset(); } - if (socket_file) - { - error = save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); - if (error.Fail()) - { - fprintf(stderr, "failed to write socket id to %s: %s\n", socket_file.GetPath().c_str(), error.AsCString()); - return 1; - } - } - - do { - GDBRemoteCommunicationServerPlatform platform(acceptor_up->GetSocketProtocol(), - acceptor_up->GetSocketScheme()); - - if (port_offset > 0) - platform.SetPortOffset(port_offset); - - if (!gdbserver_portmap.empty()) - { - platform.SetPortMap(std::move(gdbserver_portmap)); - } - - const bool children_inherit_accept_socket = true; - Connection* conn = nullptr; - error = acceptor_up->Accept(children_inherit_accept_socket, conn); - if (error.Fail()) - { - printf ("error: %s\n", error.AsCString()); - exit(socket_error); - } - printf ("Connection established.\n"); - if (g_server) - { - // Collect child zombie processes. - while (waitpid(-1, nullptr, WNOHANG) > 0); - if (fork()) - { - // Parent doesn't need a connection to the lldb client - delete conn; - - // Parent will continue to listen for new connections. - continue; - } - else - { - // Child process will handle the connection and exit. - g_server = 0; - // Listening socket is owned by parent process. - acceptor_up.release(); - } - } + platform.SetConnection(conn); + + if (platform.IsConnected()) { + if (inferior_arguments.GetArgumentCount() > 0) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + uint16_t port = 0; + std::string socket_name; + Error error = platform.LaunchGDBServer(inferior_arguments, + "", // hostname + pid, port, socket_name); + if (error.Success()) + platform.SetPendingGdbServer(pid, port, socket_name); else - { - // If not running as a server, this process will not accept - // connections while a connection is active. - acceptor_up.reset(); + fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); + } + + // After we connected, we need to get an initial ack from... + if (platform.HandshakeWithClient()) { + bool interrupt = false; + bool done = false; + while (!interrupt && !done) { + if (platform.GetPacketAndSendResponse(UINT32_MAX, error, interrupt, + done) != + GDBRemoteCommunication::PacketResult::Success) + break; } - platform.SetConnection (conn); - - if (platform.IsConnected()) - { - if (inferior_arguments.GetArgumentCount() > 0) - { - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = 0; - std::string socket_name; - Error error = platform.LaunchGDBServer(inferior_arguments, - "", // hostname - pid, - port, - socket_name); - if (error.Success()) - platform.SetPendingGdbServer(pid, port, socket_name); - else - fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); - } - - // After we connected, we need to get an initial ack from... - if (platform.HandshakeWithClient()) - { - bool interrupt = false; - bool done = false; - while (!interrupt && !done) - { - if (platform.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success) - break; - } - - if (error.Fail()) - { - fprintf(stderr, "error: %s\n", error.AsCString()); - } - } - else - { - fprintf(stderr, "error: handshake with client failed\n"); - } + + if (error.Fail()) { + fprintf(stderr, "error: %s\n", error.AsCString()); } - } while (g_server); + } else { + fprintf(stderr, "error: handshake with client failed\n"); + } + } + } while (g_server); - fprintf(stderr, "lldb-server exiting...\n"); + fprintf(stderr, "lldb-server exiting...\n"); - return 0; + return 0; } |