Keep lldb-platform.cpp and lldb-gdbserver.cpp separate but link and call into
them from lldb-server.cpp. Also merges changes from ToT.
REPOSITORY
rL LLVM
http://reviews.llvm.org/D7545
Files:
source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
test/tools/lldb-gdbserver/lldbgdbserverutils.py
tools/CMakeLists.txt
tools/Makefile
tools/lldb-gdbserver/CMakeLists.txt
tools/lldb-gdbserver/Makefile
tools/lldb-gdbserver/exports
tools/lldb-gdbserver/lldb-gdbserver.cpp
tools/lldb-platform/CMakeLists.txt
tools/lldb-platform/Makefile
tools/lldb-platform/exports
tools/lldb-platform/lldb-platform.cpp
tools/lldb-server/CMakeLists.txt
tools/lldb-server/Makefile
tools/lldb-server/exports
tools/lldb-server/lldb-gdbserver.cpp
tools/lldb-server/lldb-platform.cpp
tools/lldb-server/lldb-server.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -38,7 +38,7 @@
#if defined(__APPLE__)
# define DEBUGSERVER_BASENAME "debugserver"
#else
-# define DEBUGSERVER_BASENAME "lldb-gdbserver"
+# define DEBUGSERVER_BASENAME "lldb-server"
#endif
using namespace lldb;
@@ -739,10 +739,15 @@
Args &debugserver_args = launch_info.GetArguments();
debugserver_args.Clear();
char arg_cstr[PATH_MAX];
-
+
// Start args with "debugserver /file/path -r --"
debugserver_args.AppendArgument(debugserver_path);
+#if !defined(__APPLE__)
+ // First argument to lldb-server must be mode in which to run.
+ debugserver_args.AppendArgument("gdbserver");
+#endif
+
// If a host and port is supplied then use it
char host_and_port[128];
if (hostname)
Index: test/tools/lldb-gdbserver/lldbgdbserverutils.py
===================================================================
--- test/tools/lldb-gdbserver/lldbgdbserverutils.py
+++ test/tools/lldb-gdbserver/lldbgdbserverutils.py
@@ -63,7 +63,7 @@
if not lldb_exe:
return None
else:
- return _get_debug_monitor_from_lldb(lldb_exe, "lldb-gdbserver")
+ return _get_debug_monitor_from_lldb(lldb_exe, "lldb-server")
else:
return None
Index: tools/CMakeLists.txt
===================================================================
--- tools/CMakeLists.txt
+++ tools/CMakeLists.txt
@@ -7,8 +7,5 @@
add_subdirectory(lldb-mi)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "Linux")
- add_subdirectory(lldb-gdbserver)
-endif()
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
- add_subdirectory(lldb-platform)
+ add_subdirectory(lldb-server)
endif()
Index: tools/Makefile
===================================================================
--- tools/Makefile
+++ tools/Makefile
@@ -14,11 +14,7 @@
# enable lldb-gdbserver for supported platforms
ifneq (,$(strip $(filter $(HOST_OS), FreeBSD Linux GNU/kFreeBSD)))
-DIRS += lldb-gdbserver
-endif
-
-ifneq ($(HOST_OS),MingW)
-DIRS += lldb-platform
+DIRS += lldb-server
endif
ifeq ($(HOST_OS),Darwin)
Index: tools/lldb-gdbserver/CMakeLists.txt
===================================================================
--- tools/lldb-gdbserver/CMakeLists.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-set(LLVM_NO_RTTI 1)
-
-if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
-include_directories(
- ../../source/Plugins/Process/Linux
- ../../source/Plugins/Process/POSIX
- )
-endif ()
-
-if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" )
-include_directories(
- ../../source/Plugins/Process/FreeBSD
- ../../source/Plugins/Process/POSIX
- )
-endif ()
-include_directories(../../source)
-
-include(../../cmake/LLDBDependencies.cmake)
-
-if ( BUILD_SHARED_LIBS )
- add_lldb_executable(lldb-gdbserver
- lldb-gdbserver.cpp
- )
-
- target_link_libraries(lldb-gdbserver liblldb)
-else()
- # have to include lldb and lldb-log files since those are not libraries and llgs depends on them
- add_lldb_executable(lldb-gdbserver
- lldb-gdbserver.cpp
- ../../source/lldb-log.cpp
- ../../source/lldb.cpp
- )
-
- # The Darwin linker doesn't understand --start-group/--end-group.
- if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
- target_link_libraries(lldb-gdbserver
- -Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
- else()
- target_link_libraries(lldb-gdbserver ${LLDB_USED_LIBS})
- endif()
- target_link_libraries(lldb-gdbserver ${CLANG_USED_LIBS})
- llvm_config(lldb-gdbserver ${LLVM_LINK_COMPONENTS})
-
- target_link_libraries(lldb-gdbserver ${LLDB_SYSTEM_LIBS})
-endif()
-
-set_target_properties(lldb-gdbserver PROPERTIES VERSION ${LLDB_VERSION})
-install(TARGETS lldb-gdbserver
- RUNTIME DESTINATION bin)
Index: tools/lldb-gdbserver/Makefile
===================================================================
--- tools/lldb-gdbserver/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-##===- tools/lldb-platform/Makefile ------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LLDB_LEVEL := ../..
-
-TOOLNAME = lldb-gdbserver
-
-LLVMLibsOptions += -llldb -llldbUtility
-
-include $(LLDB_LEVEL)/Makefile
-
-ifeq ($(HOST_OS),Darwin)
- LLVMLibsOptions += -Wl,-rpath,@loader_path/../lib/
-endif
-
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD))
- LLVMLibsOptions += -Wl,-rpath,$(LibDir)
-endif
Index: tools/lldb-gdbserver/lldb-gdbserver.cpp
===================================================================
--- tools/lldb-gdbserver/lldb-gdbserver.cpp
+++ /dev/null
@@ -1,694 +0,0 @@
-//===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// C Includes
-#include <errno.h>
-#include <getopt.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <signal.h>
-#include <unistd.h>
-#endif
-
-// C++ Includes
-
-// Other libraries and framework includes
-#include "lldb/lldb-private-log.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/ConnectionMachPort.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/HostThread.h"
-#include "lldb/Host/Pipe.h"
-#include "lldb/Host/OptionParser.h"
-#include "lldb/Host/Socket.h"
-#include "lldb/Host/StringConvert.h"
-#include "lldb/Host/ThreadLauncher.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
-#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
-
-#ifndef LLGS_PROGRAM_NAME
-#define LLGS_PROGRAM_NAME "lldb-gdbserver"
-#endif
-
-#ifndef LLGS_VERSION_STR
-#define LLGS_VERSION_STR "local_build"
-#endif
-
-using namespace lldb;
-using namespace lldb_private;
-
-// lldb-gdbserver state
-
-namespace
-{
-HostThread s_listen_thread;
- std::unique_ptr<ConnectionFileDescriptor> s_listen_connection_up;
- std::string s_listen_url;
-}
-
-//----------------------------------------------------------------------
-// option descriptors for getopt_long_only()
-//----------------------------------------------------------------------
-
-int g_debug = 0;
-int g_verbose = 0;
-
-static struct option g_long_options[] =
-{
- { "debug", no_argument, &g_debug, 1 },
- { "platform", required_argument, NULL, 'p' },
- { "verbose", no_argument, &g_verbose, 1 },
- { "lldb-command", required_argument, NULL, 'c' },
- { "log-file", required_argument, NULL, 'l' },
- { "log-flags", required_argument, NULL, 'f' },
- { "attach", required_argument, NULL, 'a' },
- { "named-pipe", required_argument, NULL, 'P' },
- { "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
-//----------------------------------------------------------------------
-static int g_sigpipe_received = 0;
-static int g_sighup_received_count = 0;
-
-#ifndef _WIN32
-
-void
-signal_handler(int signo)
-{
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- fprintf (stderr, "lldb-gdbserver:%s received signal %d\n", __FUNCTION__, signo);
- if (log)
- log->Printf ("lldb-gdbserver:%s received signal %d", __FUNCTION__, signo);
-
- switch (signo)
- {
- case SIGPIPE:
- g_sigpipe_received = 1;
- break;
- case SIGHUP:
- ++g_sighup_received_count;
-
- // For now, swallow SIGHUP.
- if (log)
- log->Printf ("lldb-gdbserver:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count);
- signal (SIGHUP, signal_handler);
- break;
- }
-}
-#endif // #ifndef _WIN32
-
-static void
-display_usage (const char *progname)
-{
- fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] [--lldb-command command]* [--platform platform_name] [--setsid] [--named-pipe named-pipe-path] [--native-regs] [--attach pid] [[HOST]:PORT] "
- "[-- PROGRAM ARG1 ARG2 ...]\n", progname);
- exit(0);
-}
-
-static void
-dump_available_platforms (FILE *output_file)
-{
- fprintf (output_file, "Available platform plugins:\n");
- for (int i = 0; ; ++i)
- {
- const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (i);
- const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (i);
-
- if (!plugin_name || !plugin_desc)
- break;
-
- fprintf (output_file, "%s\t%s\n", plugin_name, plugin_desc);
- }
-
- if ( Platform::GetHostPlatform () )
- {
- // add this since the default platform doesn't necessarily get registered by
- // the plugin name (e.g. 'host' doesn't show up as a
- // registered platform plugin even though it's the default).
- fprintf (output_file, "%s\tDefault platform for this host.\n", Platform::GetHostPlatform ()->GetPluginName ().AsCString ());
- }
-}
-
-static void
-run_lldb_commands (const lldb::DebuggerSP &debugger_sp, const std::vector<std::string> &lldb_commands)
-{
- for (const auto &lldb_command : lldb_commands)
- {
- printf("(lldb) %s\n", lldb_command.c_str ());
-
- lldb_private::CommandReturnObject result;
- debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
- const char *output = result.GetOutputData ();
- if (output && output[0])
- puts (output);
- }
-}
-
-static lldb::PlatformSP
-setup_platform (const std::string &platform_name)
-{
- lldb::PlatformSP platform_sp;
-
- if (platform_name.empty())
- {
- printf ("using the default platform: ");
- platform_sp = Platform::GetHostPlatform ();
- printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
- return platform_sp;
- }
-
- Error error;
- platform_sp = Platform::Create (lldb_private::ConstString(platform_name), error);
- if (error.Fail ())
- {
- // the host platform isn't registered with that name (at
- // least, not always. Check if the given name matches
- // the default platform name. If so, use it.
- if ( Platform::GetHostPlatform () && ( Platform::GetHostPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
- {
- platform_sp = Platform::GetHostPlatform ();
- }
- else
- {
- fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
- dump_available_platforms (stderr);
- exit (1);
- }
- }
- printf ("using platform: %s\n", platform_name.c_str ());
-
- return platform_sp;
-}
-
-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 (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &attach_target)
-{
- assert (!attach_target.empty () && "attach_target cannot be empty");
-
- // First check if the attach_target is convertable 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);
- }
-}
-
-static lldb::thread_result_t
-ListenThread (lldb::thread_arg_t /* arg */)
-{
- Error error;
-
- if (s_listen_connection_up)
- {
- // Do the listen on another thread so we can continue on...
- if (s_listen_connection_up->Connect(s_listen_url.c_str(), &error) != eConnectionStatusSuccess)
- s_listen_connection_up.reset();
- }
- return nullptr;
-}
-
-static Error
-StartListenThread (const char *hostname, uint16_t port)
-{
- Error error;
- if (s_listen_thread.IsJoinable())
- {
- error.SetErrorString("listen thread already running");
- }
- else
- {
- char listen_url[512];
- if (hostname && hostname[0])
- snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
- else
- snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
-
- s_listen_url = listen_url;
- s_listen_connection_up.reset (new ConnectionFileDescriptor ());
- s_listen_thread = ThreadLauncher::LaunchThread(listen_url, ListenThread, nullptr, &error);
- }
- return error;
-}
-
-static bool
-JoinListenThread ()
-{
- if (s_listen_thread.IsJoinable())
- s_listen_thread.Join(nullptr);
- return true;
-}
-
-Error
-writePortToPipe (const char *const named_pipe_path, const uint16_t port)
-{
- 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::microseconds (10 * 1000000));
- if (error.Fail ())
- return error;
-
- char port_str[64];
- const auto port_str_len = ::snprintf (port_str, sizeof (port_str), "%u", port);
-
- size_t bytes_written = 0;
- // Write the port number as a C string with the NULL terminator.
- return port_name_pipe.Write (port_str, port_str_len + 1, bytes_written);
-}
-
-void
-ConnectToRemote (GDBRemoteCommunicationServerLLGS &gdb_server, bool reverse_connect, const char *const host_and_port, const char *const progname, const char *const named_pipe_path)
-{
- 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);
- }
- else
- {
- fprintf (stderr, "failed to parse host and port from connection string '%s'\n", final_host_and_port.c_str ());
- display_usage (progname);
- exit (1);
- }
-
- 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.
- std::unique_ptr<ConnectionFileDescriptor> connection_up (new ConnectionFileDescriptor ());
- 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);
- }
-
- // We're connected.
- printf ("Connection established.\n");
- gdb_server.SetConnection (connection_up.release());
- }
- else
- {
- // llgs will listen for connections on the given port from the given address.
- // Start the listener on a new thread. We need to do this so we can resolve the
- // bound listener port.
- StartListenThread(connection_host.c_str (), static_cast<uint16_t> (connection_portno));
- printf ("Listening to port %s for a connection from %s...\n", connection_port.c_str (), connection_host.c_str ());
-
- // If we have a named pipe to write the port number back to, do that now.
- if (named_pipe_path && named_pipe_path[0] && connection_portno == 0)
- {
- const uint16_t bound_port = s_listen_connection_up->GetListeningPort (10);
- if (bound_port > 0)
- {
- error = writePortToPipe (named_pipe_path, bound_port);
- if (error.Fail ())
- {
- fprintf (stderr, "failed to write to the named pipe \'%s\': %s", named_pipe_path, error.AsCString());
- }
- }
- else
- {
- fprintf (stderr, "unable to get the bound port for the listening connection\n");
- }
- }
-
- // Join the listener thread.
- if (!JoinListenThread ())
- {
- fprintf (stderr, "failed to join the listener thread\n");
- display_usage (progname);
- exit (1);
- }
-
- // Ensure we connected.
- if (s_listen_connection_up)
- {
- printf ("Connection established '%s'\n", s_listen_connection_up->GetURI().c_str());
- gdb_server.SetConnection (s_listen_connection_up.release());
- }
- else
- {
- fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
- display_usage (progname);
- exit (1);
- }
- }
- }
-
- if (gdb_server.IsConnected())
- {
- // After we connected, we need to get an initial ack from...
- if (gdb_server.HandshakeWithClient(&error))
- {
- // We'll use a half a second timeout interval so that an exit conditions can
- // be checked that often.
- const uint32_t TIMEOUT_USEC = 500000;
-
- bool interrupt = false;
- bool done = false;
- while (!interrupt && !done && (g_sighup_received_count < 2))
- {
- const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done);
- if ((result != GDBRemoteCommunication::PacketResult::Success) &&
- (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout))
- {
- // We're bailing out - we only support successful handling and timeouts.
- fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result);
- break;
- }
- }
-
- if (error.Fail())
- {
- fprintf(stderr, "error: %s\n", error.AsCString());
- }
- }
- else
- {
- fprintf(stderr, "error: handshake with client failed\n");
- }
- }
- else
- {
- fprintf (stderr, "no connection information provided, unable to run\n");
- display_usage (progname);
- exit (1);
- }
-}
-
-//----------------------------------------------------------------------
-// main
-//----------------------------------------------------------------------
-int
-main (int argc, char *argv[])
-{
-#ifndef _WIN32
- // Setup signal handlers first thing.
- signal (SIGPIPE, signal_handler);
- signal (SIGHUP, signal_handler);
-#endif
-
- const char *progname = argv[0];
- int long_option_index = 0;
- StreamSP log_stream_sp;
- Args log_args;
- Error error;
- int ch;
- std::string platform_name;
- std::string attach_target;
- std::string named_pipe_path;
- bool reverse_connect = false;
-
- Debugger::Initialize (NULL);
-
- lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
-
- debugger_sp->SetInputFileHandle(stdin, false);
- debugger_sp->SetOutputFileHandle(stdout, false);
- debugger_sp->SetErrorFileHandle(stderr, false);
-
- // ProcessLaunchInfo launch_info;
- ProcessAttachInfo attach_info;
-
- bool show_usage = false;
- int option_error = 0;
-#if __GLIBC__
- optind = 0;
-#else
- optreset = 1;
- optind = 1;
-#endif
-
- std::string short_options(OptionParser::GetShortOptionString(g_long_options));
-
- std::vector<std::string> lldb_commands;
-
- 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])
- {
- if ((strcasecmp(optarg, "stdout") == 0) || (strcmp(optarg, "/dev/stdout") == 0))
- {
- log_stream_sp.reset (new StreamFile (stdout, false));
- }
- else if ((strcasecmp(optarg, "stderr") == 0) || (strcmp(optarg, "/dev/stderr") == 0))
- {
- log_stream_sp.reset (new StreamFile (stderr, false));
- }
- else
- {
- FILE *log_file = fopen(optarg, "w");
- if (log_file)
- {
- setlinebuf(log_file);
- log_stream_sp.reset (new StreamFile (log_file, true));
- }
- else
- {
- const char *errno_str = strerror(errno);
- fprintf (stderr, "Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
- }
-
- }
- }
- break;
-
- case 'f': // Log Flags
- if (optarg && optarg[0])
- log_args.AppendArgument(optarg);
- break;
-
- case 'c': // lldb commands
- if (optarg && optarg[0])
- lldb_commands.push_back(optarg);
- break;
-
- case 'p': // platform name
- if (optarg && optarg[0])
- platform_name = optarg;
- break;
-
- case 'P': // named pipe
- if (optarg && optarg[0])
- named_pipe_path = optarg;
- break;
-
- case 'r':
- // Do nothing, native regs is the default these days
- 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);
- exit(option_error);
- }
-
- if (log_stream_sp)
- {
- if (log_args.GetArgumentCount() == 0)
- log_args.AppendArgument("default");
- ProcessGDBRemoteLog::EnableLog (log_stream_sp, 0,log_args.GetConstArgumentVector(), log_stream_sp.get());
- }
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_VERBOSE));
- if (log)
- {
- log->Printf ("lldb-gdbserver launch");
- for (int i = 0; i < argc; i++)
- {
- log->Printf ("argv[%i] = '%s'", i, argv[i]);
- }
- }
-
- // Skip any options we consumed with getopt_long_only.
- argc -= optind;
- argv += optind;
-
- if (argc == 0)
- {
- display_usage(progname);
- exit(255);
- }
-
- // Run any commands requested.
- run_lldb_commands (debugger_sp, lldb_commands);
-
- // Setup the platform that GDBRemoteCommunicationServerLLGS will use.
- lldb::PlatformSP platform_sp = setup_platform (platform_name);
-
- GDBRemoteCommunicationServerLLGS gdb_server (platform_sp, debugger_sp);
-
- const char *const host_and_port = argv[0];
- argc -= 1;
- argv += 1;
-
- // Any arguments left over are for the 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 (gdb_server, reverse_connect, host_and_port, progname, named_pipe_path.c_str ());
-
- Debugger::Terminate ();
-
- fprintf(stderr, "lldb-gdbserver exiting...\n");
-
- return 0;
-}
Index: tools/lldb-platform/CMakeLists.txt
===================================================================
--- tools/lldb-platform/CMakeLists.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-set(LLVM_NO_RTTI 1)
-
-if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
-include_directories(
- ../../source/Plugins/Process/Linux
- ../../source/Plugins/Process/POSIX
- )
-endif ()
-
-if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" )
-include_directories(
- ../../source/Plugins/Process/FreeBSD
- ../../source/Plugins/Process/POSIX
- )
-endif ()
-
-include_directories(../../source)
-
-include(../../cmake/LLDBDependencies.cmake)
-
-add_lldb_executable(lldb-platform
- lldb-platform.cpp
- ../../source/lldb-log.cpp
- ../../source/lldb.cpp
- ${LLDB_WRAP_PYTHON}
- ${LLDB_VERS_GENERATED_FILE}
- )
-
-if (LLDB_WRAP_PYTHON OR LLDB_VERS_GENERATED_FILE)
- add_dependencies(lldb-platform swig_wrapper)
-endif()
-
-# The Darwin linker doesn't understand --start-group/--end-group.
-if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
- target_link_libraries(lldb-platform
- -Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
-else()
- target_link_libraries(lldb-platform ${LLDB_USED_LIBS})
-endif()
-target_link_libraries(lldb-platform ${CLANG_USED_LIBS})
-llvm_config(lldb-platform ${LLVM_LINK_COMPONENTS})
-
-target_link_libraries(lldb-platform ${LLDB_SYSTEM_LIBS})
-
-set_target_properties(lldb-platform PROPERTIES VERSION ${LLDB_VERSION})
-
-install(TARGETS lldb-platform
- RUNTIME DESTINATION bin)
Index: tools/lldb-platform/Makefile
===================================================================
--- tools/lldb-platform/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-##===- tools/lldb-platform/Makefile ------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LLDB_LEVEL := ../..
-
-TOOLNAME = lldb-platform
-
-LLVMLibsOptions += -llldb -llldbUtility
-
-include $(LLDB_LEVEL)/Makefile
-
-ifeq ($(HOST_OS),Darwin)
- LLVMLibsOptions += -Wl,-rpath,@loader_path/../lib/
-endif
-
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD))
- LLVMLibsOptions += -Wl,-rpath,$(LibDir)
-endif
Index: tools/lldb-platform/lldb-platform.cpp
===================================================================
--- tools/lldb-platform/lldb-platform.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-//===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/lldb-python.h"
-
-// C Includes
-#include <errno.h>
-#if defined(__APPLE__)
-#include <netinet/in.h>
-#endif
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// C++ Includes
-
-// Other libraries and framework includes
-#include "lldb/lldb-private-log.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/ConnectionMachPort.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/HostGetOpt.h"
-#include "lldb/Host/OptionParser.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
-#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-//----------------------------------------------------------------------
-// option descriptors for getopt_long_only()
-//----------------------------------------------------------------------
-
-int g_debug = 0;
-int g_verbose = 0;
-int g_stay_alive = 0;
-
-static struct option g_long_options[] =
-{
- { "debug", no_argument, &g_debug, 1 },
- { "verbose", no_argument, &g_verbose, 1 },
- { "stay-alive", no_argument, &g_stay_alive, 1 },
- { "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' },
- { "lldb-command", required_argument, NULL, 'c' },
- { 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)
-#endif
-
-
-//----------------------------------------------------------------------
-// Watch for signals
-//----------------------------------------------------------------------
-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-platform...\n");
- abort();
- break;
- }
-}
-
-static void
-display_usage (const char *progname)
-{
- fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname);
- exit(0);
-}
-
-//----------------------------------------------------------------------
-// main
-//----------------------------------------------------------------------
-int
-main (int argc, char *argv[])
-{
- const char *progname = argv[0];
- signal (SIGPIPE, SIG_IGN);
- signal (SIGHUP, signal_handler);
- int long_option_index = 0;
- Error error;
- std::string listen_host_port;
- int ch;
- Debugger::Initialize(NULL);
-
- lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
-
- debugger_sp->SetInputFileHandle(stdin, false);
- debugger_sp->SetOutputFileHandle(stdout, false);
- debugger_sp->SetErrorFileHandle(stderr, false);
-
- GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
- int min_gdbserver_port = 0;
- int max_gdbserver_port = 0;
- uint16_t port_offset = 0;
-
- std::vector<std::string> lldb_commands;
- bool show_usage = false;
- int option_error = 0;
-
- std::string short_options(OptionParser::GetShortOptionString(g_long_options));
-
-#if __GLIBC__
- optind = 0;
-#else
- 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 '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 'c':
- lldb_commands.push_back(optarg);
- break;
-
- case 'h': /* fall-through is intentional */
- case '?':
- show_usage = true;
- break;
- }
- }
-
- // 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);
- exit(option_error);
- }
-
- // Execute any LLDB commands that we were asked to evaluate.
- for (const auto &lldb_command : lldb_commands)
- {
- lldb_private::CommandReturnObject result;
- printf("(lldb) %s\n", lldb_command.c_str());
- debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result);
- const char *output = result.GetOutputData();
- if (output && output[0])
- puts(output);
- }
-
-
- do {
- GDBRemoteCommunicationServerPlatform platform;
-
- if (port_offset > 0)
- platform.SetPortOffset(port_offset);
-
- if (!gdbserver_portmap.empty())
- {
- platform.SetPortMap(std::move(gdbserver_portmap));
- }
-
- if (!listen_host_port.empty())
- {
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
- if (conn_ap.get())
- {
- std::string connect_url ("listen://");
- connect_url.append(listen_host_port.c_str());
-
- printf ("Listening for a connection from %s...\n", listen_host_port.c_str());
- if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
- {
- printf ("Connection established.\n");
- platform.SetConnection (conn_ap.release());
- }
- else
- {
- printf ("error: %s\n", error.AsCString());
- }
- }
-
- if (platform.IsConnected())
- {
- // After we connected, we need to get an initial ack from...
- if (platform.HandshakeWithClient(&error))
- {
- 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");
- }
- }
- }
- } while (g_stay_alive);
-
- Debugger::Terminate();
-
- fprintf(stderr, "lldb-platform exiting...\n");
-
- return 0;
-}
Index: tools/lldb-server/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/lldb-server/CMakeLists.txt
@@ -0,0 +1,54 @@
+set(LLVM_NO_RTTI 1)
+
+if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
+include_directories(
+ ../../source/Plugins/Process/Linux
+ ../../source/Plugins/Process/POSIX
+ )
+endif ()
+
+if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" )
+include_directories(
+ ../../source/Plugins/Process/FreeBSD
+ ../../source/Plugins/Process/POSIX
+ )
+endif ()
+
+include_directories(../../source)
+
+include(../../cmake/LLDBDependencies.cmake)
+
+if (BUILD_SHARED_LIBS )
+ add_lldb_executable(lldb-server
+ lldb-server.cpp
+ lldb-gdbserver.cpp
+ lldb-platform.cpp
+ )
+
+ target_link_libraries(lldb-server liblldb)
+else()
+ add_lldb_executable(lldb-server
+ lldb-server.cpp
+ lldb-gdbserver.cpp
+ lldb-platform.cpp
+ ../../source/lldb-log.cpp
+ ../../source/lldb.cpp
+ )
+
+ # The Darwin linker doesn't understand --start-group/--end-group.
+ if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
+ target_link_libraries(lldb-server
+ -Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
+ else()
+ target_link_libraries(lldb-server ${LLDB_USED_LIBS})
+ endif()
+ target_link_libraries(lldb-server ${CLANG_USED_LIBS})
+ llvm_config(lldb-server ${LLVM_LINK_COMPONENTS})
+
+ target_link_libraries(lldb-server ${LLDB_SYSTEM_LIBS})
+endif()
+
+set_target_properties(lldb-server PROPERTIES VERSION ${LLDB_VERSION})
+
+install(TARGETS lldb-server
+ RUNTIME DESTINATION bin)
Index: tools/lldb-server/Makefile
===================================================================
--- /dev/null
+++ tools/lldb-server/Makefile
@@ -0,0 +1,23 @@
+##===- tools/lldb-server/Makefile ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LLDB_LEVEL := ../..
+
+TOOLNAME = lldb-server
+
+LLVMLibsOptions += -llldb -llldbUtility
+
+include $(LLDB_LEVEL)/Makefile
+
+ifeq ($(HOST_OS),Darwin)
+ LLVMLibsOptions += -Wl,-rpath,@loader_path/../lib/
+endif
+
+ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD))
+ LLVMLibsOptions += -Wl,-rpath,$(LibDir)
+endif
Index: tools/lldb-server/lldb-gdbserver.cpp
===================================================================
--- /dev/null
+++ tools/lldb-server/lldb-gdbserver.cpp
@@ -0,0 +1,699 @@
+//===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <signal.h>
+#include <unistd.h>
+#endif
+
+// C++ Includes
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ConnectionMachPort.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+
+#ifndef LLGS_PROGRAM_NAME
+#define LLGS_PROGRAM_NAME "lldb-gdbserver"
+#endif
+
+#ifndef LLGS_VERSION_STR
+#define LLGS_VERSION_STR "local_build"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+// lldb-gdbserver state
+
+namespace
+{
+
+HostThread s_listen_thread;
+ std::unique_ptr<ConnectionFileDescriptor> s_listen_connection_up;
+ std::string s_listen_url;
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long_only()
+//----------------------------------------------------------------------
+
+int g_debug = 0;
+int g_verbose = 0;
+
+static struct option g_long_options[] =
+{
+ { "debug", no_argument, &g_debug, 1 },
+ { "platform", required_argument, NULL, 'p' },
+ { "verbose", no_argument, &g_verbose, 1 },
+ { "lldb-command", required_argument, NULL, 'c' },
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-flags", required_argument, NULL, 'f' },
+ { "attach", required_argument, NULL, 'a' },
+ { "named-pipe", required_argument, NULL, 'P' },
+ { "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
+//----------------------------------------------------------------------
+static int g_sigpipe_received = 0;
+static int g_sighup_received_count = 0;
+
+#ifndef _WIN32
+
+void
+signal_handler(int signo)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ fprintf (stderr, "lldb-gdbserver:%s received signal %d\n", __FUNCTION__, signo);
+ if (log)
+ log->Printf ("lldb-gdbserver:%s received signal %d", __FUNCTION__, signo);
+
+ switch (signo)
+ {
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ case SIGHUP:
+ ++g_sighup_received_count;
+
+ // For now, swallow SIGHUP.
+ if (log)
+ log->Printf ("lldb-gdbserver:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count);
+ signal (SIGHUP, signal_handler);
+ break;
+ }
+}
+#endif // #ifndef _WIN32
+
+static void
+display_usage (const char *progname, const char* subcommand)
+{
+ fprintf(stderr, "Usage:\n %s %s [--log-file log-file-path] [--log-flags flags] [--lldb-command command]* [--platform platform_name] [--setsid] [--named-pipe named-pipe-path] [--native-regs] [--attach pid] [[HOST]:PORT] "
+ "[-- PROGRAM ARG1 ARG2 ...]\n", progname, subcommand);
+ exit(0);
+}
+
+static void
+dump_available_platforms (FILE *output_file)
+{
+ fprintf (output_file, "Available platform plugins:\n");
+ for (int i = 0; ; ++i)
+ {
+ const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (i);
+ const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (i);
+
+ if (!plugin_name || !plugin_desc)
+ break;
+
+ fprintf (output_file, "%s\t%s\n", plugin_name, plugin_desc);
+ }
+
+ if ( Platform::GetHostPlatform () )
+ {
+ // add this since the default platform doesn't necessarily get registered by
+ // the plugin name (e.g. 'host' doesn't show up as a
+ // registered platform plugin even though it's the default).
+ fprintf (output_file, "%s\tDefault platform for this host.\n", Platform::GetHostPlatform ()->GetPluginName ().AsCString ());
+ }
+}
+
+static void
+run_lldb_commands (const lldb::DebuggerSP &debugger_sp, const std::vector<std::string> &lldb_commands)
+{
+ for (const auto &lldb_command : lldb_commands)
+ {
+ printf("(lldb) %s\n", lldb_command.c_str ());
+
+ lldb_private::CommandReturnObject result;
+ debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
+ const char *output = result.GetOutputData ();
+ if (output && output[0])
+ puts (output);
+ }
+}
+
+static lldb::PlatformSP
+setup_platform (const std::string &platform_name)
+{
+ lldb::PlatformSP platform_sp;
+
+ if (platform_name.empty())
+ {
+ printf ("using the default platform: ");
+ platform_sp = Platform::GetHostPlatform ();
+ printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
+ return platform_sp;
+ }
+
+ Error error;
+ platform_sp = Platform::Create (lldb_private::ConstString(platform_name), error);
+ if (error.Fail ())
+ {
+ // the host platform isn't registered with that name (at
+ // least, not always. Check if the given name matches
+ // the default platform name. If so, use it.
+ if ( Platform::GetHostPlatform () && ( Platform::GetHostPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
+ {
+ platform_sp = Platform::GetHostPlatform ();
+ }
+ else
+ {
+ fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
+ dump_available_platforms (stderr);
+ exit (1);
+ }
+ }
+ printf ("using platform: %s\n", platform_name.c_str ());
+
+ return platform_sp;
+}
+
+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 (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &attach_target)
+{
+ assert (!attach_target.empty () && "attach_target cannot be empty");
+
+ // First check if the attach_target is convertable 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);
+ }
+}
+
+static lldb::thread_result_t
+ListenThread (lldb::thread_arg_t /* arg */)
+{
+ Error error;
+
+ if (s_listen_connection_up)
+ {
+ // Do the listen on another thread so we can continue on...
+ if (s_listen_connection_up->Connect(s_listen_url.c_str(), &error) != eConnectionStatusSuccess)
+ s_listen_connection_up.reset();
+ }
+ return nullptr;
+}
+
+static Error
+StartListenThread (const char *hostname, uint16_t port)
+{
+ Error error;
+ if (s_listen_thread.IsJoinable())
+ {
+ error.SetErrorString("listen thread already running");
+ }
+ else
+ {
+ char listen_url[512];
+ if (hostname && hostname[0])
+ snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
+ else
+ snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+
+ s_listen_url = listen_url;
+ s_listen_connection_up.reset (new ConnectionFileDescriptor ());
+ s_listen_thread = ThreadLauncher::LaunchThread(listen_url, ListenThread, nullptr, &error);
+ }
+ return error;
+}
+
+static bool
+JoinListenThread ()
+{
+ if (s_listen_thread.IsJoinable())
+ s_listen_thread.Join(nullptr);
+ return true;
+}
+
+Error
+writePortToPipe (const char *const named_pipe_path, const uint16_t port)
+{
+ 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::microseconds (10 * 1000000));
+ if (error.Fail ())
+ return error;
+
+ char port_str[64];
+ const auto port_str_len = ::snprintf (port_str, sizeof (port_str), "%u", port);
+
+ size_t bytes_written = 0;
+ // Write the port number as a C string with the NULL terminator.
+ return port_name_pipe.Write (port_str, port_str_len + 1, bytes_written);
+}
+
+void
+ConnectToRemote (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)
+{
+ 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);
+ }
+ else
+ {
+ fprintf (stderr, "failed to parse host and port from connection string '%s'\n", final_host_and_port.c_str ());
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+
+ 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.
+ std::unique_ptr<ConnectionFileDescriptor> connection_up (new ConnectionFileDescriptor ());
+ 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);
+ }
+
+ // We're connected.
+ printf ("Connection established.\n");
+ gdb_server.SetConnection (connection_up.release());
+ }
+ else
+ {
+ // llgs will listen for connections on the given port from the given address.
+ // Start the listener on a new thread. We need to do this so we can resolve the
+ // bound listener port.
+ StartListenThread(connection_host.c_str (), static_cast<uint16_t> (connection_portno));
+ printf ("Listening to port %s for a connection from %s...\n", connection_port.c_str (), connection_host.c_str ());
+
+ // If we have a named pipe to write the port number back to, do that now.
+ if (named_pipe_path && named_pipe_path[0] && connection_portno == 0)
+ {
+ const uint16_t bound_port = s_listen_connection_up->GetListeningPort (10);
+ if (bound_port > 0)
+ {
+ error = writePortToPipe (named_pipe_path, bound_port);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "failed to write to the named pipe \'%s\': %s", named_pipe_path, error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf (stderr, "unable to get the bound port for the listening connection\n");
+ }
+ }
+
+ // Join the listener thread.
+ if (!JoinListenThread ())
+ {
+ fprintf (stderr, "failed to join the listener thread\n");
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+
+ // Ensure we connected.
+ if (s_listen_connection_up)
+ {
+ printf ("Connection established '%s'\n", s_listen_connection_up->GetURI().c_str());
+ gdb_server.SetConnection (s_listen_connection_up.release());
+ }
+ else
+ {
+ fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+ }
+ }
+
+ if (gdb_server.IsConnected())
+ {
+ // After we connected, we need to get an initial ack from...
+ if (gdb_server.HandshakeWithClient(&error))
+ {
+ // We'll use a half a second timeout interval so that an exit conditions can
+ // be checked that often.
+ const uint32_t TIMEOUT_USEC = 500000;
+
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done && (g_sighup_received_count < 2))
+ {
+ const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done);
+ if ((result != GDBRemoteCommunication::PacketResult::Success) &&
+ (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout))
+ {
+ // We're bailing out - we only support successful handling and timeouts.
+ fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result);
+ break;
+ }
+ }
+
+ if (error.Fail())
+ {
+ fprintf(stderr, "error: %s\n", error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: handshake with client failed\n");
+ }
+ }
+ else
+ {
+ fprintf (stderr, "no connection information provided, unable to run\n");
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+}
+
+}
+
+//----------------------------------------------------------------------
+// main
+//----------------------------------------------------------------------
+int
+main_gdbserver (int argc, char *argv[])
+{
+#ifndef _WIN32
+ // Setup signal handlers first thing.
+ signal (SIGPIPE, signal_handler);
+ signal (SIGHUP, signal_handler);
+#endif
+
+ const char *progname = argv[0];
+ const char *subcommand = argv[1];
+ argc--;
+ argv++;
+ int long_option_index = 0;
+ StreamSP log_stream_sp;
+ Args log_args;
+ Error error;
+ int ch;
+ std::string platform_name;
+ std::string attach_target;
+ std::string named_pipe_path;
+ bool reverse_connect = false;
+
+ Debugger::Initialize (NULL);
+
+ lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
+
+ debugger_sp->SetInputFileHandle(stdin, false);
+ debugger_sp->SetOutputFileHandle(stdout, false);
+ debugger_sp->SetErrorFileHandle(stderr, false);
+
+ // ProcessLaunchInfo launch_info;
+ ProcessAttachInfo attach_info;
+
+ bool show_usage = false;
+ int option_error = 0;
+#if __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+
+ std::string short_options(OptionParser::GetShortOptionString(g_long_options));
+
+ std::vector<std::string> lldb_commands;
+
+ 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])
+ {
+ if ((strcasecmp(optarg, "stdout") == 0) || (strcmp(optarg, "/dev/stdout") == 0))
+ {
+ log_stream_sp.reset (new StreamFile (stdout, false));
+ }
+ else if ((strcasecmp(optarg, "stderr") == 0) || (strcmp(optarg, "/dev/stderr") == 0))
+ {
+ log_stream_sp.reset (new StreamFile (stderr, false));
+ }
+ else
+ {
+ FILE *log_file = fopen(optarg, "w");
+ if (log_file)
+ {
+ setlinebuf(log_file);
+ log_stream_sp.reset (new StreamFile (log_file, true));
+ }
+ else
+ {
+ const char *errno_str = strerror(errno);
+ fprintf (stderr, "Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
+ }
+
+ }
+ }
+ break;
+
+ case 'f': // Log Flags
+ if (optarg && optarg[0])
+ log_args.AppendArgument(optarg);
+ break;
+
+ case 'c': // lldb commands
+ if (optarg && optarg[0])
+ lldb_commands.push_back(optarg);
+ break;
+
+ case 'p': // platform name
+ if (optarg && optarg[0])
+ platform_name = optarg;
+ break;
+
+ case 'P': // named pipe
+ if (optarg && optarg[0])
+ named_pipe_path = optarg;
+ break;
+
+ case 'r':
+ // Do nothing, native regs is the default these days
+ 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 (log_stream_sp)
+ {
+ if (log_args.GetArgumentCount() == 0)
+ log_args.AppendArgument("default");
+ ProcessGDBRemoteLog::EnableLog (log_stream_sp, 0,log_args.GetConstArgumentVector(), log_stream_sp.get());
+ }
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_VERBOSE));
+ if (log)
+ {
+ log->Printf ("lldb-gdbserver launch");
+ for (int i = 0; i < argc; i++)
+ {
+ log->Printf ("argv[%i] = '%s'", i, argv[i]);
+ }
+ }
+
+ // Skip any options we consumed with getopt_long_only.
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ display_usage(progname, subcommand);
+ exit(255);
+ }
+
+ // Run any commands requested.
+ run_lldb_commands (debugger_sp, lldb_commands);
+
+ // Setup the platform that GDBRemoteCommunicationServerLLGS will use.
+ lldb::PlatformSP platform_sp = setup_platform (platform_name);
+
+ GDBRemoteCommunicationServerLLGS gdb_server (platform_sp, debugger_sp);
+
+ const char *const host_and_port = argv[0];
+ argc -= 1;
+ argv += 1;
+
+ // Any arguments left over are for the 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 (gdb_server, reverse_connect, host_and_port, progname, subcommand, named_pipe_path.c_str ());
+
+ Debugger::Terminate ();
+
+ fprintf(stderr, "lldb-gdbserver exiting...\n");
+
+ return 0;
+}
Index: tools/lldb-server/lldb-platform.cpp
===================================================================
--- /dev/null
+++ tools/lldb-server/lldb-platform.cpp
@@ -0,0 +1,319 @@
+//===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+#if defined(__APPLE__)
+#include <netinet/in.h>
+#endif
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// C++ Includes
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ConnectionMachPort.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/HostGetOpt.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long_only()
+//----------------------------------------------------------------------
+
+int g_debug = 0;
+int g_verbose = 0;
+int g_stay_alive = 0;
+
+static struct option g_long_options[] =
+{
+ { "debug", no_argument, &g_debug, 1 },
+ { "verbose", no_argument, &g_verbose, 1 },
+ { "stay-alive", no_argument, &g_stay_alive, 1 },
+ { "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' },
+ { "lldb-command", required_argument, NULL, 'c' },
+ { 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)
+#endif
+
+
+//----------------------------------------------------------------------
+// Watch for signals
+//----------------------------------------------------------------------
+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-platform...\n");
+ abort();
+ break;
+ }
+}
+
+static void
+display_usage (const char *progname, const char *subcommand)
+{
+ fprintf(stderr, "Usage:\n %s %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname, subcommand);
+ exit(0);
+}
+
+}
+
+//----------------------------------------------------------------------
+// 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;
+ Debugger::Initialize(NULL);
+
+ lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
+
+ debugger_sp->SetInputFileHandle(stdin, false);
+ debugger_sp->SetOutputFileHandle(stdout, false);
+ debugger_sp->SetErrorFileHandle(stderr, false);
+
+ GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
+ int min_gdbserver_port = 0;
+ int max_gdbserver_port = 0;
+ uint16_t port_offset = 0;
+
+ std::vector<std::string> lldb_commands;
+ bool show_usage = false;
+ int option_error = 0;
+
+ std::string short_options(OptionParser::GetShortOptionString(g_long_options));
+
+#if __GLIBC__
+ optind = 0;
+#else
+ 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 '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 'c':
+ lldb_commands.push_back(optarg);
+ break;
+
+ case 'h': /* fall-through is intentional */
+ case '?':
+ show_usage = true;
+ break;
+ }
+ }
+
+ // 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);
+ }
+
+ // Execute any LLDB commands that we were asked to evaluate.
+ for (const auto &lldb_command : lldb_commands)
+ {
+ lldb_private::CommandReturnObject result;
+ printf("(lldb) %s\n", lldb_command.c_str());
+ debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result);
+ const char *output = result.GetOutputData();
+ if (output && output[0])
+ puts(output);
+ }
+
+
+ do {
+ GDBRemoteCommunicationServerPlatform platform;
+
+ if (port_offset > 0)
+ platform.SetPortOffset(port_offset);
+
+ if (!gdbserver_portmap.empty())
+ {
+ platform.SetPortMap(std::move(gdbserver_portmap));
+ }
+
+ if (!listen_host_port.empty())
+ {
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ std::string connect_url ("listen://");
+ connect_url.append(listen_host_port.c_str());
+
+ printf ("Listening for a connection from %s...\n", listen_host_port.c_str());
+ if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ {
+ printf ("Connection established.\n");
+ platform.SetConnection (conn_ap.release());
+ }
+ else
+ {
+ printf ("error: %s\n", error.AsCString());
+ }
+ }
+
+ if (platform.IsConnected())
+ {
+ // After we connected, we need to get an initial ack from...
+ if (platform.HandshakeWithClient(&error))
+ {
+ 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");
+ }
+ }
+ }
+ } while (g_stay_alive);
+
+ Debugger::Terminate();
+
+ fprintf(stderr, "lldb-platform exiting...\n");
+
+ return 0;
+}
Index: tools/lldb-server/lldb-server.cpp
===================================================================
--- /dev/null
+++ tools/lldb-server/lldb-server.cpp
@@ -0,0 +1,52 @@
+//===-- lldb-server.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <stdlib.h>
+
+ static void
+display_usage (const char *progname)
+{
+ fprintf(stderr, "Usage:\n"
+ " %s g[dbserver] [options]\n"
+ " %s p[latform] [options]\n"
+ "Invoke subcommand for additional help", progname, progname);
+ exit(0);
+}
+
+// Forward declarations of subcommand main methods.
+int main_gdbserver (int argc, char *argv[]);
+int main_platform (int argc, char *argv[]);
+
+//----------------------------------------------------------------------
+// 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);
+ }
+ else if (argv[1][0] == 'g')
+ {
+ main_gdbserver(argc, argv);
+ }
+ else if (argv[1][0] == 'p')
+ {
+ main_platform(argc, argv);
+ }
+ else {
+ display_usage(progname);
+ exit(option_error);
+ }
+}
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits