diff options
Diffstat (limited to 'lldb/tools/lldb-server')
-rw-r--r-- | lldb/tools/lldb-server/Acceptor.cpp | 193 | ||||
-rw-r--r-- | lldb/tools/lldb-server/Acceptor.h | 49 | ||||
-rw-r--r-- | lldb/tools/lldb-server/LLDBServerUtilities.cpp | 74 | ||||
-rw-r--r-- | lldb/tools/lldb-server/LLDBServerUtilities.h | 9 | ||||
-rw-r--r-- | lldb/tools/lldb-server/lldb-gdbserver.cpp | 744 | ||||
-rw-r--r-- | lldb/tools/lldb-server/lldb-platform.cpp | 634 | ||||
-rw-r--r-- | lldb/tools/lldb-server/lldb-server.cpp | 93 |
7 files changed, 846 insertions, 950 deletions
diff --git a/lldb/tools/lldb-server/Acceptor.cpp b/lldb/tools/lldb-server/Acceptor.cpp index 1bf86eb7da6..938d7795e45 100644 --- a/lldb/tools/lldb-server/Acceptor.cpp +++ b/lldb/tools/lldb-server/Acceptor.cpp @@ -25,10 +25,9 @@ using namespace llvm; namespace { -struct SocketScheme -{ - const char* m_scheme; - const Socket::SocketProtocol m_protocol; +struct SocketScheme { + const char *m_scheme; + const Socket::SocketProtocol m_protocol; }; SocketScheme socket_schemes[] = { @@ -38,134 +37,102 @@ SocketScheme socket_schemes[] = { {"unix-abstract", Socket::ProtocolUnixAbstract}, }; -bool -FindProtocolByScheme(const char* scheme, Socket::SocketProtocol& protocol) -{ - for (auto s: socket_schemes) - { - if (!strcmp(s.m_scheme, scheme)) - { - protocol = s.m_protocol; - return true; - } +bool FindProtocolByScheme(const char *scheme, + Socket::SocketProtocol &protocol) { + for (auto s : socket_schemes) { + if (!strcmp(s.m_scheme, scheme)) { + protocol = s.m_protocol; + return true; } - return false; + } + return false; } -const char* -FindSchemeByProtocol(const Socket::SocketProtocol protocol) -{ - for (auto s: socket_schemes) - { - if (s.m_protocol == protocol) - return s.m_scheme; - } - return nullptr; +const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) { + for (auto s : socket_schemes) { + if (s.m_protocol == protocol) + return s.m_scheme; + } + return nullptr; } - } -Error -Acceptor::Listen(int backlog) -{ - return m_listener_socket_up->Listen(StringRef(m_name.c_str()), - backlog); +Error Acceptor::Listen(int backlog) { + return m_listener_socket_up->Listen(StringRef(m_name.c_str()), backlog); } -Error -Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) -{ - Socket* conn_socket = nullptr; - auto error = m_listener_socket_up->Accept(StringRef(m_name.c_str()), - child_processes_inherit, - conn_socket); - if (error.Success()) - conn = new ConnectionFileDescriptor(conn_socket); - - return error; -} +Error Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) { + Socket *conn_socket = nullptr; + auto error = m_listener_socket_up->Accept( + StringRef(m_name.c_str()), child_processes_inherit, conn_socket); + if (error.Success()) + conn = new ConnectionFileDescriptor(conn_socket); -Socket::SocketProtocol -Acceptor::GetSocketProtocol() const -{ - return m_listener_socket_up->GetSocketProtocol(); + return error; } -const char* -Acceptor::GetSocketScheme() const -{ - return FindSchemeByProtocol(GetSocketProtocol()); +Socket::SocketProtocol Acceptor::GetSocketProtocol() const { + return m_listener_socket_up->GetSocketProtocol(); } -std::string -Acceptor::GetLocalSocketId() const -{ - return m_local_socket_id(); +const char *Acceptor::GetSocketScheme() const { + return FindSchemeByProtocol(GetSocketProtocol()); } -std::unique_ptr<Acceptor> -Acceptor::Create(StringRef name, const bool child_processes_inherit, Error &error) -{ - error.Clear(); - - Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain; - int port; - std::string scheme, host, path; - // Try to match socket name as URL - e.g., tcp://localhost:5555 - if (UriParser::Parse(name.str(), scheme, host, port, path)) - { - if (!FindProtocolByScheme(scheme.c_str(), socket_protocol)) - error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"", scheme.c_str()); - else - name = name.drop_front(scheme.size() + strlen("://")); - } +std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); } + +std::unique_ptr<Acceptor> Acceptor::Create(StringRef name, + const bool child_processes_inherit, + Error &error) { + error.Clear(); + + Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain; + int port; + std::string scheme, host, path; + // Try to match socket name as URL - e.g., tcp://localhost:5555 + if (UriParser::Parse(name.str(), scheme, host, port, path)) { + if (!FindProtocolByScheme(scheme.c_str(), socket_protocol)) + error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"", + scheme.c_str()); else - { - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - // Try to match socket name as $host:port - e.g., localhost:5555 - if (Socket::DecodeHostAndPort (name, host_str, port_str, port, nullptr)) - socket_protocol = Socket::ProtocolTcp; - } + name = name.drop_front(scheme.size() + strlen("://")); + } else { + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + // Try to match socket name as $host:port - e.g., localhost:5555 + if (Socket::DecodeHostAndPort(name, host_str, port_str, port, nullptr)) + socket_protocol = Socket::ProtocolTcp; + } + + if (error.Fail()) + return std::unique_ptr<Acceptor>(); - if (error.Fail()) - return std::unique_ptr<Acceptor>(); - - std::unique_ptr<Socket> listener_socket_up = Socket::Create( - socket_protocol, child_processes_inherit, error); - - LocalSocketIdFunc local_socket_id; - if (error.Success()) - { - if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) - { - TCPSocket* tcp_socket = static_cast<TCPSocket*>(listener_socket_up.get()); - local_socket_id = [tcp_socket]() { - auto local_port = tcp_socket->GetLocalPortNumber(); - return (local_port != 0) ? llvm::to_string(local_port) : ""; - }; - } - else - { - const std::string socket_name = name; - local_socket_id = [socket_name](){ - return socket_name; - }; - } - - return std::unique_ptr<Acceptor>( - new Acceptor(std::move(listener_socket_up), name, local_socket_id)); + std::unique_ptr<Socket> listener_socket_up = + Socket::Create(socket_protocol, child_processes_inherit, error); + + LocalSocketIdFunc local_socket_id; + if (error.Success()) { + if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) { + TCPSocket *tcp_socket = + static_cast<TCPSocket *>(listener_socket_up.get()); + local_socket_id = [tcp_socket]() { + auto local_port = tcp_socket->GetLocalPortNumber(); + return (local_port != 0) ? llvm::to_string(local_port) : ""; + }; + } else { + const std::string socket_name = name; + local_socket_id = [socket_name]() { return socket_name; }; } - return std::unique_ptr<Acceptor>(); + return std::unique_ptr<Acceptor>( + new Acceptor(std::move(listener_socket_up), name, local_socket_id)); + } + + return std::unique_ptr<Acceptor>(); } -Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, - StringRef name, +Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, StringRef name, const LocalSocketIdFunc &local_socket_id) - : m_listener_socket_up(std::move(listener_socket)), - m_name(name.str()), - m_local_socket_id(local_socket_id) -{ -} + : m_listener_socket_up(std::move(listener_socket)), m_name(name.str()), + m_local_socket_id(local_socket_id) {} diff --git a/lldb/tools/lldb-server/Acceptor.h b/lldb/tools/lldb-server/Acceptor.h index 37fba26c881..f0638ef1ae6 100644 --- a/lldb/tools/lldb-server/Acceptor.h +++ b/lldb/tools/lldb-server/Acceptor.h @@ -17,52 +17,45 @@ #include <memory> #include <string> -namespace llvm -{ - class StringRef; +namespace llvm { +class StringRef; } namespace lldb_private { namespace lldb_server { -class Acceptor -{ +class Acceptor { public: - virtual ~Acceptor() = default; + virtual ~Acceptor() = default; - Error - Listen(int backlog); + Error Listen(int backlog); - Error - Accept(const bool child_processes_inherit, Connection *&conn); + Error Accept(const bool child_processes_inherit, Connection *&conn); - static std::unique_ptr<Acceptor> - Create(llvm::StringRef name, const bool child_processes_inherit, Error &error); + static std::unique_ptr<Acceptor> Create(llvm::StringRef name, + const bool child_processes_inherit, + Error &error); - Socket::SocketProtocol - GetSocketProtocol() const; + Socket::SocketProtocol GetSocketProtocol() const; - const char* - GetSocketScheme() const; + const char *GetSocketScheme() const; - // Returns either TCP port number as string or domain socket path. - // Empty string is returned in case of error. - std::string - GetLocalSocketId() const; + // Returns either TCP port number as string or domain socket path. + // Empty string is returned in case of error. + std::string GetLocalSocketId() const; private: - typedef std::function<std::string()> LocalSocketIdFunc; + typedef std::function<std::string()> LocalSocketIdFunc; - Acceptor(std::unique_ptr<Socket> &&listener_socket, - llvm::StringRef name, - const LocalSocketIdFunc &local_socket_id); + Acceptor(std::unique_ptr<Socket> &&listener_socket, llvm::StringRef name, + const LocalSocketIdFunc &local_socket_id); - const std::unique_ptr<Socket> m_listener_socket_up; - const std::string m_name; - const LocalSocketIdFunc m_local_socket_id; + const std::unique_ptr<Socket> m_listener_socket_up; + const std::string m_name; + const LocalSocketIdFunc m_local_socket_id; }; } // namespace lldb_server } // namespace lldb_private -#endif // lldb_server_Acceptor_h_ +#endif // lldb_server_Acceptor_h_ diff --git a/lldb/tools/lldb-server/LLDBServerUtilities.cpp b/lldb/tools/lldb-server/LLDBServerUtilities.cpp index 438d9f127d6..86d8469933e 100644 --- a/lldb/tools/lldb-server/LLDBServerUtilities.cpp +++ b/lldb/tools/lldb-server/LLDBServerUtilities.cpp @@ -21,47 +21,37 @@ using namespace lldb; using namespace lldb_private::lldb_server; using namespace llvm; -bool -LLDBServerUtilities::SetupLogging(const std::string& log_file, - const StringRef& log_channels, - uint32_t log_options) -{ - lldb::StreamSP log_stream_sp; - if (log_file.empty()) - { - log_stream_sp.reset(new StreamFile(stdout, false)); +bool LLDBServerUtilities::SetupLogging(const std::string &log_file, + const StringRef &log_channels, + uint32_t log_options) { + lldb::StreamSP log_stream_sp; + if (log_file.empty()) { + log_stream_sp.reset(new StreamFile(stdout, false)); + } else { + uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate | + File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; + if (!(log_options & LLDB_LOG_OPTION_APPEND)) + options |= File::eOpenOptionTruncate; + + log_stream_sp.reset(new StreamFile(log_file.c_str(), options)); + } + + SmallVector<StringRef, 32> channel_array; + log_channels.split(channel_array, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); + for (auto channel_with_categories : channel_array) { + StreamString error_stream; + Args channel_then_categories(channel_with_categories); + std::string channel(channel_then_categories.GetArgumentAtIndex(0)); + channel_then_categories.Shift(); // Shift off the channel + + bool success = Log::EnableLogChannel( + log_stream_sp, log_options, channel.c_str(), + channel_then_categories.GetConstArgumentVector(), error_stream); + if (!success) { + fprintf(stderr, "Unable to open log file '%s' for channel \"%s\"\n", + log_file.c_str(), channel_with_categories.str().c_str()); + return false; } - else - { - uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate | - File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; - if (!(log_options & LLDB_LOG_OPTION_APPEND)) - options |= File::eOpenOptionTruncate; - - log_stream_sp.reset(new StreamFile(log_file.c_str(), options)); - } - - SmallVector<StringRef, 32> channel_array; - log_channels.split(channel_array, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); - for (auto channel_with_categories : channel_array) - { - StreamString error_stream; - Args channel_then_categories(channel_with_categories); - std::string channel(channel_then_categories.GetArgumentAtIndex(0)); - channel_then_categories.Shift (); // Shift off the channel - - bool success = Log::EnableLogChannel(log_stream_sp, - log_options, - channel.c_str(), - channel_then_categories.GetConstArgumentVector(), - error_stream); - if (!success) - { - fprintf(stderr, "Unable to open log file '%s' for channel \"%s\"\n", - log_file.c_str(), - channel_with_categories.str().c_str()); - return false; - } - } - return true; + } + return true; } diff --git a/lldb/tools/lldb-server/LLDBServerUtilities.h b/lldb/tools/lldb-server/LLDBServerUtilities.h index cab892a5edc..36ec70d9ef9 100644 --- a/lldb/tools/lldb-server/LLDBServerUtilities.h +++ b/lldb/tools/lldb-server/LLDBServerUtilities.h @@ -14,12 +14,11 @@ namespace lldb_private { namespace lldb_server { -class LLDBServerUtilities -{ +class LLDBServerUtilities { public: - static bool - SetupLogging(const std::string& log_file, const llvm::StringRef& log_channels, uint32_t log_options); + static bool SetupLogging(const std::string &log_file, + const llvm::StringRef &log_channels, + uint32_t log_options); }; - } } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index b8c59e29eb5..5a388722b3c 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -24,6 +24,10 @@ // Other libraries and framework includes #include "llvm/ADT/StringRef.h" +#include "Acceptor.h" +#include "LLDBServerUtilities.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" +#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" #include "lldb/Core/Error.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/ConnectionFileDescriptor.h" @@ -32,10 +36,6 @@ #include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" -#include "Acceptor.h" -#include "LLDBServerUtilities.h" -#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" -#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" #ifndef LLGS_PROGRAM_NAME #define LLGS_PROGRAM_NAME "lldb-server" @@ -58,21 +58,24 @@ using namespace lldb_private::process_gdb_remote; static int g_debug = 0; static int g_verbose = 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' }, - { "attach", required_argument, NULL, 'a' }, - { "named-pipe", required_argument, NULL, 'N' }, - { "pipe", required_argument, NULL, 'U' }, - { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture. NOTE: this is a do-nothing arg as it's behavior is default now. FIXME remove call from lldb-platform. - { "reverse-connect", no_argument, NULL, 'R' }, // Specifies that llgs attaches to the client address:port rather than llgs listening for a connection from address on port. - { "setsid", no_argument, NULL, 'S' }, // Call setsid() to make llgs run in its own session. - { NULL, 0, NULL, 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'}, + {"attach", required_argument, NULL, 'a'}, + {"named-pipe", required_argument, NULL, 'N'}, + {"pipe", required_argument, NULL, 'U'}, + {"native-regs", no_argument, NULL, + 'r'}, // Specify to use the native registers instead of the gdb defaults + // for the architecture. NOTE: this is a do-nothing arg as it's + // behavior is default now. FIXME remove call from lldb-platform. + {"reverse-connect", no_argument, NULL, + 'R'}, // Specifies that llgs attaches to the client address:port rather + // than llgs listening for a connection from address on port. + {"setsid", no_argument, NULL, + 'S'}, // Call setsid() to make llgs run in its own session. + {NULL, 0, NULL, 0}}; //---------------------------------------------------------------------- // Watch for signals @@ -80,418 +83,401 @@ static struct option g_long_options[] = static int g_sighup_received_count = 0; #ifndef _WIN32 -static void -sighup_handler(MainLoopBase &mainloop) -{ - ++g_sighup_received_count; +static void sighup_handler(MainLoopBase &mainloop) { + ++g_sighup_received_count; - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("lldb-server:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("lldb-server:%s swallowing SIGHUP (receive count=%d)", + __FUNCTION__, g_sighup_received_count); - if (g_sighup_received_count >= 2) - mainloop.RequestTermination(); + if (g_sighup_received_count >= 2) + mainloop.RequestTermination(); } #endif // #ifndef _WIN32 -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] " - "[--setsid] " - "[--named-pipe named-pipe-path] " - "[--native-regs] " - "[--attach pid] " - "[[HOST]:PORT] " - "[-- PROGRAM ARG1 ARG2 ...]\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] " + "[--setsid] " + "[--named-pipe named-pipe-path] " + "[--native-regs] " + "[--attach pid] " + "[[HOST]:PORT] " + "[-- PROGRAM ARG1 ARG2 ...]\n", + progname, subcommand); + exit(0); } -void -handle_attach_to_pid (GDBRemoteCommunicationServerLLGS &gdb_server, lldb::pid_t pid) -{ - Error error = gdb_server.AttachToProcess (pid); - if (error.Fail ()) - { - fprintf (stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, error.AsCString()); - exit(1); - } +void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server, + lldb::pid_t pid) { + Error error = gdb_server.AttachToProcess(pid); + if (error.Fail()) { + fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, + error.AsCString()); + exit(1); + } } -void -handle_attach_to_process_name (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &process_name) -{ - // FIXME implement. +void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server, + const std::string &process_name) { + // FIXME implement. } -void -handle_attach (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &attach_target) -{ - assert (!attach_target.empty () && "attach_target cannot be empty"); - - // First check if the attach_target is convertible to a long. If so, we'll use it as a pid. - char *end_p = nullptr; - const long int pid = strtol (attach_target.c_str (), &end_p, 10); - - // We'll call it a match if the entire argument is consumed. - if (end_p && static_cast<size_t> (end_p - attach_target.c_str ()) == attach_target.size ()) - handle_attach_to_pid (gdb_server, static_cast<lldb::pid_t> (pid)); - else - handle_attach_to_process_name (gdb_server, attach_target); +void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server, + const std::string &attach_target) { + assert(!attach_target.empty() && "attach_target cannot be empty"); + + // First check if the attach_target is convertible to a long. If so, we'll use + // it as a pid. + char *end_p = nullptr; + const long int pid = strtol(attach_target.c_str(), &end_p, 10); + + // We'll call it a match if the entire argument is consumed. + if (end_p && + static_cast<size_t>(end_p - attach_target.c_str()) == + attach_target.size()) + handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid)); + else + handle_attach_to_process_name(gdb_server, attach_target); } -void -handle_launch (GDBRemoteCommunicationServerLLGS &gdb_server, int argc, const char *const argv[]) -{ - Error error; - error = gdb_server.SetLaunchArguments (argv, argc); - if (error.Fail ()) - { - fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString()); - exit(1); - } - - unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug; - - error = gdb_server.SetLaunchFlags (launch_flags); - if (error.Fail ()) - { - fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString()); - exit(1); - } - - error = gdb_server.LaunchProcess (); - if (error.Fail ()) - { - fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString()); - exit(1); - } +void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc, + const char *const argv[]) { + Error error; + error = gdb_server.SetLaunchArguments(argv, argc); + if (error.Fail()) { + fprintf(stderr, "error: failed to set launch args for '%s': %s\n", argv[0], + error.AsCString()); + exit(1); + } + + unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug; + + error = gdb_server.SetLaunchFlags(launch_flags); + if (error.Fail()) { + fprintf(stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], + error.AsCString()); + exit(1); + } + + error = gdb_server.LaunchProcess(); + if (error.Fail()) { + fprintf(stderr, "error: failed to launch '%s': %s\n", argv[0], + error.AsCString()); + exit(1); + } } -Error -writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) -{ - size_t bytes_written = 0; - // Write the port number as a C string with the NULL terminator. - return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1, bytes_written); +Error writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) { + size_t bytes_written = 0; + // Write the port number as a C string with the NULL terminator. + return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1, + bytes_written); } -Error -writeSocketIdToPipe(const char *const named_pipe_path, const std::string &socket_id) -{ - Pipe port_name_pipe; - // Wait for 10 seconds for pipe to be opened. - auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false, - std::chrono::seconds{10}); - if (error.Fail()) - return error; - return writeSocketIdToPipe(port_name_pipe, socket_id); +Error writeSocketIdToPipe(const char *const named_pipe_path, + const std::string &socket_id) { + Pipe port_name_pipe; + // Wait for 10 seconds for pipe to be opened. + auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false, + std::chrono::seconds{10}); + if (error.Fail()) + return error; + return writeSocketIdToPipe(port_name_pipe, socket_id); } -Error -writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) -{ +Error writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) { #if defined(_WIN32) - return Error("Unnamed pipes are not supported on Windows."); + return Error("Unnamed pipes are not supported on Windows."); #else - Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd}; - return writeSocketIdToPipe(port_pipe, socket_id); + Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd}; + return writeSocketIdToPipe(port_pipe, socket_id); #endif } -void -ConnectToRemote(MainLoop &mainloop, GDBRemoteCommunicationServerLLGS &gdb_server, - bool reverse_connect, const char *const host_and_port, - const char *const progname, const char *const subcommand, - const char *const named_pipe_path, int unnamed_pipe_fd) -{ - Error error; - - if (host_and_port && host_and_port[0]) - { - // Parse out host and port. - std::string final_host_and_port; - std::string connection_host; - std::string connection_port; - uint32_t connection_portno = 0; - - // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port. - if (host_and_port[0] == ':') - final_host_and_port.append ("localhost"); - final_host_and_port.append (host_and_port); - - const std::string::size_type colon_pos = final_host_and_port.find (':'); - if (colon_pos != std::string::npos) - { - connection_host = final_host_and_port.substr (0, colon_pos); - connection_port = final_host_and_port.substr (colon_pos + 1); - connection_portno = StringConvert::ToUInt32 (connection_port.c_str (), 0); - } +void ConnectToRemote(MainLoop &mainloop, + GDBRemoteCommunicationServerLLGS &gdb_server, + bool reverse_connect, const char *const host_and_port, + const char *const progname, const char *const subcommand, + const char *const named_pipe_path, int unnamed_pipe_fd) { + Error error; + + if (host_and_port && host_and_port[0]) { + // Parse out host and port. + std::string final_host_and_port; + std::string connection_host; + std::string connection_port; + uint32_t connection_portno = 0; + + // If host_and_port starts with ':', default the host to be "localhost" and + // expect the remainder to be the port. + if (host_and_port[0] == ':') + final_host_and_port.append("localhost"); + final_host_and_port.append(host_and_port); + + const std::string::size_type colon_pos = final_host_and_port.find(':'); + if (colon_pos != std::string::npos) { + connection_host = final_host_and_port.substr(0, colon_pos); + connection_port = final_host_and_port.substr(colon_pos + 1); + connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0); + } - std::unique_ptr<Connection> connection_up; - - if (reverse_connect) - { - // llgs will connect to the gdb-remote client. - - // Ensure we have a port number for the connection. - if (connection_portno == 0) - { - fprintf (stderr, "error: port number must be specified on when using reverse connect"); - exit (1); - } - - // Build the connection string. - char connection_url[512]; - snprintf(connection_url, sizeof(connection_url), "connect://%s", final_host_and_port.c_str ()); - - // Create the connection. - connection_up.reset(new ConnectionFileDescriptor); - auto connection_result = connection_up->Connect (connection_url, &error); - if (connection_result != eConnectionStatusSuccess) - { - fprintf (stderr, "error: failed to connect to client at '%s' (connection status: %d)", connection_url, static_cast<int> (connection_result)); - exit (-1); - } - if (error.Fail ()) - { - fprintf (stderr, "error: failed to connect to client at '%s': %s", connection_url, error.AsCString ()); - exit (-1); - } - } - else - { - std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(final_host_and_port, false, error)); - if (error.Fail()) - { - fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); - exit(1); - } - error = acceptor_up->Listen(1); - if (error.Fail()) - { - fprintf(stderr, "failed to listen: %s\n", error.AsCString()); - exit(1); - } - const std::string socket_id = acceptor_up->GetLocalSocketId(); - if (!socket_id.empty()) - { - // If we have a named pipe to write the socket id back to, do that now. - if (named_pipe_path && named_pipe_path[0]) - { - error = writeSocketIdToPipe (named_pipe_path, socket_id); - if (error.Fail ()) - fprintf (stderr, "failed to write to the named pipe \'%s\': %s", - named_pipe_path, error.AsCString()); - } - // If we have an unnamed pipe to write the socket id back to, do that now. - else if (unnamed_pipe_fd >= 0) - { - error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id); - if (error.Fail()) - fprintf(stderr, "failed to write to the unnamed pipe: %s", - error.AsCString()); - } - } - else - { - fprintf (stderr, "unable to get the socket id for the listening connection\n"); - } - - Connection* conn = nullptr; - error = acceptor_up->Accept(false, conn); - if (error.Fail()) - { - printf ("failed to accept new connection: %s\n", error.AsCString()); - exit(1); - } - connection_up.reset(conn); + std::unique_ptr<Connection> connection_up; + + if (reverse_connect) { + // llgs will connect to the gdb-remote client. + + // Ensure we have a port number for the connection. + if (connection_portno == 0) { + fprintf(stderr, "error: port number must be specified on when using " + "reverse connect"); + exit(1); + } + + // Build the connection string. + char connection_url[512]; + snprintf(connection_url, sizeof(connection_url), "connect://%s", + final_host_and_port.c_str()); + + // Create the connection. + connection_up.reset(new ConnectionFileDescriptor); + auto connection_result = connection_up->Connect(connection_url, &error); + if (connection_result != eConnectionStatusSuccess) { + fprintf(stderr, "error: failed to connect to client at '%s' " + "(connection status: %d)", + connection_url, static_cast<int>(connection_result)); + exit(-1); + } + if (error.Fail()) { + fprintf(stderr, "error: failed to connect to client at '%s': %s", + connection_url, error.AsCString()); + exit(-1); + } + } else { + std::unique_ptr<Acceptor> acceptor_up( + Acceptor::Create(final_host_and_port, false, error)); + if (error.Fail()) { + fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); + exit(1); + } + error = acceptor_up->Listen(1); + if (error.Fail()) { + fprintf(stderr, "failed to listen: %s\n", error.AsCString()); + exit(1); + } + const std::string socket_id = acceptor_up->GetLocalSocketId(); + if (!socket_id.empty()) { + // If we have a named pipe to write the socket id back to, do that now. + if (named_pipe_path && named_pipe_path[0]) { + error = writeSocketIdToPipe(named_pipe_path, socket_id); + if (error.Fail()) + fprintf(stderr, "failed to write to the named pipe \'%s\': %s", + named_pipe_path, error.AsCString()); } - error = gdb_server.InitializeConnection (std::move(connection_up)); - if (error.Fail()) - { - fprintf(stderr, "Failed to initialize connection: %s\n", error.AsCString()); - exit(-1); + // If we have an unnamed pipe to write the socket id back to, do that + // now. + else if (unnamed_pipe_fd >= 0) { + error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id); + if (error.Fail()) + fprintf(stderr, "failed to write to the unnamed pipe: %s", + error.AsCString()); } - printf ("Connection established.\n"); + } else { + fprintf(stderr, + "unable to get the socket id for the listening connection\n"); + } + + Connection *conn = nullptr; + error = acceptor_up->Accept(false, conn); + if (error.Fail()) { + printf("failed to accept new connection: %s\n", error.AsCString()); + exit(1); + } + connection_up.reset(conn); + } + error = gdb_server.InitializeConnection(std::move(connection_up)); + if (error.Fail()) { + fprintf(stderr, "Failed to initialize connection: %s\n", + error.AsCString()); + exit(-1); } + printf("Connection established.\n"); + } } //---------------------------------------------------------------------- // main //---------------------------------------------------------------------- -int -main_gdbserver (int argc, char *argv[]) -{ - Error error; - MainLoop mainloop; +int main_gdbserver(int argc, char *argv[]) { + Error error; + MainLoop mainloop; #ifndef _WIN32 - // Setup signal handlers first thing. - signal(SIGPIPE, SIG_IGN); - MainLoop::SignalHandleUP sighup_handle = mainloop.RegisterSignal(SIGHUP, sighup_handler, error); + // Setup signal handlers first thing. + signal(SIGPIPE, SIG_IGN); + MainLoop::SignalHandleUP sighup_handle = + mainloop.RegisterSignal(SIGHUP, sighup_handler, error); #endif - const char *progname = argv[0]; - const char *subcommand = argv[1]; - argc--; - argv++; - int long_option_index = 0; - int ch; - std::string attach_target; - std::string named_pipe_path; - std::string log_file; - StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" - int unnamed_pipe_fd = -1; - bool reverse_connect = false; - - // ProcessLaunchInfo launch_info; - ProcessAttachInfo attach_info; - - bool show_usage = false; - int option_error = 0; + const char *progname = argv[0]; + const char *subcommand = argv[1]; + argc--; + argv++; + int long_option_index = 0; + int ch; + std::string attach_target; + std::string named_pipe_path; + std::string log_file; + StringRef + log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" + int unnamed_pipe_fd = -1; + bool reverse_connect = false; + + // ProcessLaunchInfo launch_info; + ProcessAttachInfo attach_info; + + bool show_usage = false; + int option_error = 0; #if __GLIBC__ - optind = 0; + optind = 0; #else - optreset = 1; - optind = 1; + optreset = 1; + optind = 1; #endif - std::string short_options(OptionParser::GetShortOptionString(g_long_options)); + std::string short_options(OptionParser::GetShortOptionString(g_long_options)); - 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; + 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': // Set Log File - if (optarg && optarg[0]) - log_file.assign(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 'c': // Log Channels + if (optarg && optarg[0]) + log_channels = StringRef(optarg); + break; - case 'N': // named pipe - if (optarg && optarg[0]) - named_pipe_path = optarg; - break; + case 'N': // named pipe + if (optarg && optarg[0]) + named_pipe_path = optarg; + break; - case 'U': // unnamed pipe - if (optarg && optarg[0]) - unnamed_pipe_fd = StringConvert::ToUInt32(optarg, -1); - break; + case 'U': // unnamed pipe + if (optarg && optarg[0]) + unnamed_pipe_fd = StringConvert::ToUInt32(optarg, -1); + break; - case 'r': - // Do nothing, native regs is the default these days - break; + case 'r': + // Do nothing, native regs is the default these days + break; - case 'R': - reverse_connect = true; - break; + case 'R': + reverse_connect = true; + break; #ifndef _WIN32 - case 'S': - // Put llgs into a new session. Terminals group processes - // into sessions and when a special terminal key sequences - // (like control+c) are typed they can cause signals to go out to - // all processes in a session. Using this --setsid (-S) option - // will cause debugserver to run in its own sessions and be free - // from such issues. - // - // This is useful when llgs is spawned from a command - // line application that uses llgs to do the debugging, - // yet that application doesn't want llgs receiving the - // signals sent to the session (i.e. dying when anyone hits ^C). - { - const ::pid_t new_sid = setsid(); - if (new_sid == -1) - { - const char *errno_str = strerror(errno); - fprintf (stderr, "failed to set new session id for %s (%s)\n", LLGS_PROGRAM_NAME, errno_str ? errno_str : "<no error string>"); - } - } - break; -#endif - - case 'a': // attach {pid|process_name} - if (optarg && optarg[0]) - attach_target = optarg; - break; - - case 'h': /* fall-through is intentional */ - case '?': - show_usage = true; - break; - } - } - - if (show_usage || option_error) - { - display_usage(progname, subcommand); - exit(option_error); - } - - if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) - return -1; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_VERBOSE)); - if (log) - { - log->Printf ("lldb-server launch"); - for (int i = 0; i < argc; i++) - { - log->Printf ("argv[%i] = '%s'", i, argv[i]); + case 'S': + // Put llgs into a new session. Terminals group processes + // into sessions and when a special terminal key sequences + // (like control+c) are typed they can cause signals to go out to + // all processes in a session. Using this --setsid (-S) option + // will cause debugserver to run in its own sessions and be free + // from such issues. + // + // This is useful when llgs is spawned from a command + // line application that uses llgs to do the debugging, + // yet that application doesn't want llgs receiving the + // signals sent to the session (i.e. dying when anyone hits ^C). + { + const ::pid_t new_sid = setsid(); + if (new_sid == -1) { + const char *errno_str = strerror(errno); + fprintf(stderr, "failed to set new session id for %s (%s)\n", + LLGS_PROGRAM_NAME, + errno_str ? errno_str : "<no error string>"); } - } + } + break; +#endif - // Skip any options we consumed with getopt_long_only. - argc -= optind; - argv += optind; + case 'a': // attach {pid|process_name} + if (optarg && optarg[0]) + attach_target = optarg; + break; - if (argc == 0) - { - display_usage(progname, subcommand); - exit(255); + case 'h': /* fall-through is intentional */ + case '?': + show_usage = true; + break; } - - GDBRemoteCommunicationServerLLGS gdb_server(mainloop); - - const char *const host_and_port = argv[0]; - argc -= 1; - argv += 1; - - // Any arguments left over are for the program that we need to launch. If there - // are no arguments, then the GDB server will start up and wait for an 'A' packet - // to launch a program, or a vAttach packet to attach to an existing process, unless - // explicitly asked to attach with the --attach={pid|program_name} form. - if (!attach_target.empty ()) - handle_attach (gdb_server, attach_target); - else if (argc > 0) - handle_launch (gdb_server, argc, argv); - - // Print version info. - printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); - - ConnectToRemote(mainloop, gdb_server, reverse_connect, - host_and_port, progname, subcommand, - named_pipe_path.c_str(), unnamed_pipe_fd); - - - if (! gdb_server.IsConnected()) - { - fprintf (stderr, "no connection information provided, unable to run\n"); - display_usage (progname, subcommand); - return 1; + } + + if (show_usage || option_error) { + display_usage(progname, subcommand); + exit(option_error); + } + + if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, + LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) + return -1; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(GDBR_LOG_VERBOSE)); + if (log) { + log->Printf("lldb-server launch"); + for (int i = 0; i < argc; i++) { + log->Printf("argv[%i] = '%s'", i, argv[i]); } - - mainloop.Run(); - fprintf(stderr, "lldb-server exiting...\n"); - - return 0; + } + + // Skip any options we consumed with getopt_long_only. + argc -= optind; + argv += optind; + + if (argc == 0) { + display_usage(progname, subcommand); + exit(255); + } + + GDBRemoteCommunicationServerLLGS gdb_server(mainloop); + + const char *const host_and_port = argv[0]; + argc -= 1; + argv += 1; + + // Any arguments left over are for the program that we need to launch. If + // there + // are no arguments, then the GDB server will start up and wait for an 'A' + // packet + // to launch a program, or a vAttach packet to attach to an existing process, + // unless + // explicitly asked to attach with the --attach={pid|program_name} form. + if (!attach_target.empty()) + handle_attach(gdb_server, attach_target); + else if (argc > 0) + handle_launch(gdb_server, argc, argv); + + // Print version info. + printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); + + ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port, + progname, subcommand, named_pipe_path.c_str(), + unnamed_pipe_fd); + + if (!gdb_server.IsConnected()) { + fprintf(stderr, "no connection information provided, unable to run\n"); + display_usage(progname, subcommand); + return 1; + } + + mainloop.Run(); + fprintf(stderr, "lldb-server exiting...\n"); + + return 0; } 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; } diff --git a/lldb/tools/lldb-server/lldb-server.cpp b/lldb/tools/lldb-server/lldb-server.cpp index 9ece640b288..06ef0498749 100644 --- a/lldb/tools/lldb-server/lldb-server.cpp +++ b/lldb/tools/lldb-server/lldb-server.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Initialization/SystemInitializerCommon.h" +#include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/lldb-private.h" #include "llvm/ADT/STLExtras.h" @@ -17,66 +17,57 @@ #include <stdio.h> #include <stdlib.h> -static llvm::ManagedStatic<lldb_private::SystemLifetimeManager> g_debugger_lifetime; +static llvm::ManagedStatic<lldb_private::SystemLifetimeManager> + g_debugger_lifetime; -static void -display_usage (const char *progname) -{ - fprintf(stderr, "Usage:\n" - " %s v[ersion]\n" - " %s g[dbserver] [options]\n" - " %s p[latform] [options]\n" - "Invoke subcommand for additional help\n", progname, progname, progname); - exit(0); +static void display_usage(const char *progname) { + fprintf(stderr, "Usage:\n" + " %s v[ersion]\n" + " %s g[dbserver] [options]\n" + " %s p[latform] [options]\n" + "Invoke subcommand for additional help\n", + progname, progname, progname); + exit(0); } // Forward declarations of subcommand main methods. -int main_gdbserver (int argc, char *argv[]); -int main_platform (int argc, char *argv[]); +int main_gdbserver(int argc, char *argv[]); +int main_platform(int argc, char *argv[]); -static void -initialize () -{ - g_debugger_lifetime->Initialize(llvm::make_unique<lldb_private::SystemInitializerCommon>(), nullptr); +static void initialize() { + g_debugger_lifetime->Initialize( + llvm::make_unique<lldb_private::SystemInitializerCommon>(), nullptr); } -static void -terminate () -{ - g_debugger_lifetime->Terminate(); -} +static void terminate() { g_debugger_lifetime->Terminate(); } //---------------------------------------------------------------------- // main //---------------------------------------------------------------------- -int -main (int argc, char *argv[]) -{ - int option_error = 0; - const char *progname = argv[0]; - if (argc < 2) - { - display_usage(progname); - exit(option_error); - } +int main(int argc, char *argv[]) { + int option_error = 0; + const char *progname = argv[0]; + if (argc < 2) { + display_usage(progname); + exit(option_error); + } - switch (argv[1][0]) - { - case 'g': - initialize(); - main_gdbserver(argc, argv); - terminate(); - break; - case 'p': - initialize(); - main_platform(argc, argv); - terminate(); - break; - case 'v': - fprintf(stderr, "%s\n", lldb_private::GetVersion()); - break; - default: - display_usage(progname); - exit(option_error); - } + switch (argv[1][0]) { + case 'g': + initialize(); + main_gdbserver(argc, argv); + terminate(); + break; + case 'p': + initialize(); + main_platform(argc, argv); + terminate(); + break; + case 'v': + fprintf(stderr, "%s\n", lldb_private::GetVersion()); + break; + default: + display_usage(progname); + exit(option_error); + } } |