diff options
author | Greg Clayton <gclayton@apple.com> | 2013-11-21 18:39:32 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2013-11-21 18:39:32 +0000 |
commit | be94a0405587069c0b6d33c4803db0451e008ff0 (patch) | |
tree | 16940eb858ec0cf60bd23730ef4149d09ac01b61 /lldb/tools/lldb-gdbserver | |
parent | d9aef7883dae29c1b1ac2d5ad00372d72ece65ae (diff) | |
download | bcm5719-llvm-be94a0405587069c0b6d33c4803db0451e008ff0.tar.gz bcm5719-llvm-be94a0405587069c0b6d33c4803db0451e008ff0.zip |
Start the correct host abstraction of process and thread.
Added a new "Host/Debug.h" which contains the pure virtual class definitions for NativeProcessProtocol and NativeThreadProtocol. These classes are host layer classes that, over time, every host that supports debugging will implement once.
Then the new "lldb-gdbserver" binary in the tools directory will be able to make a remote debugging binary from these native classes, and we will also be able to have a new lldb_private::Process class that implements native debugging using these classes.
So as soon as linux and MacOSX switch over to using this layer, everyone will get native and remote debugging.
This check-in is primarily to get the needed code in so that poeple can start trying to implement the NativeProcessProtocol and NativeThreadProtocol and use it in the GDBRemoteCommunicationServer class to implement a GDB server for remote debugging.
llvm-svn: 195369
Diffstat (limited to 'lldb/tools/lldb-gdbserver')
-rw-r--r-- | lldb/tools/lldb-gdbserver/CMakeLists.txt | 14 | ||||
-rw-r--r-- | lldb/tools/lldb-gdbserver/Makefile | 23 | ||||
-rw-r--r-- | lldb/tools/lldb-gdbserver/lldb-gdbserver.cpp | 240 |
3 files changed, 277 insertions, 0 deletions
diff --git a/lldb/tools/lldb-gdbserver/CMakeLists.txt b/lldb/tools/lldb-gdbserver/CMakeLists.txt new file mode 100644 index 00000000000..9c1599a1e7f --- /dev/null +++ b/lldb/tools/lldb-gdbserver/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_NO_RTTI 1) + +include_directories(../../source) + +add_lldb_executable(lldb-gdbserver + lldb-gdbserver.cpp + ) + +target_link_libraries(lldb-gdbserver liblldb) + +set_target_properties(lldb-gdbserver PROPERTIES VERSION ${LLDB_VERSION}) + +install(TARGETS lldb-gdbserver + RUNTIME DESTINATION bin) diff --git a/lldb/tools/lldb-gdbserver/Makefile b/lldb/tools/lldb-gdbserver/Makefile new file mode 100644 index 00000000000..41425a139a8 --- /dev/null +++ b/lldb/tools/lldb-gdbserver/Makefile @@ -0,0 +1,23 @@ +##===- 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 diff --git a/lldb/tools/lldb-gdbserver/lldb-gdbserver.cpp b/lldb/tools/lldb-gdbserver/lldb-gdbserver.cpp new file mode 100644 index 00000000000..26b9b2d19eb --- /dev/null +++ b/lldb/tools/lldb-gdbserver/lldb-gdbserver.cpp @@ -0,0 +1,240 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-python.h" + +// C Includes +#include <errno.h> +#include <getopt.h> +#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/ConnectionFileDescriptor.h" +#include "lldb/Core/ConnectionMachPort.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/StreamFile.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.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; + +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-flags", required_argument, NULL, 'f' }, + { NULL, 0, NULL, 0 } +}; + + +//---------------------------------------------------------------------- +// Watch for signals +//---------------------------------------------------------------------- +int g_sigpipe_received = 0; +void +signal_handler(int signo) +{ + switch (signo) + { + case SIGPIPE: + g_sigpipe_received = 1; + break; + 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-gdbserver...\n"); + abort(); + break; + } +} + +static void +display_usage (const char *progname) +{ + fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] HOST:PORT [-- PROGRAM ARG1 ARG2 ...]\n", progname); + exit(0); +} + +//---------------------------------------------------------------------- +// main +//---------------------------------------------------------------------- +int +main (int argc, char *argv[]) +{ + const char *progname = argv[0]; + signal (SIGPIPE, signal_handler); + signal (SIGHUP, signal_handler); + int long_option_index = 0; + StreamSP log_stream_sp; + Args log_args; + Error error; + int ch; + Debugger::Initialize(); + + bool show_usage = false; + int option_error = 0; +// StreamSP stream_sp (new StreamFile(stdout, false)); +// const char *log_channels[] = { "host", "process", NULL }; +// EnableLog (stream_sp, 0, log_channels, NULL); + + while ((ch = getopt_long_only(argc, argv, "l:f:h", g_long_options, &long_option_index)) != -1) + { +// DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", +// ch, (uint8_t)ch, +// g_long_options[long_option_index].name, +// g_long_options[long_option_index].has_arg ? '=' : ' ', +// optarg ? optarg : ""); + 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 '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()); + } + + // Skip any options we consumed with getopt_long_only + argc -= optind; + argv += optind; + + if (argc == 0) + { + display_usage(progname); + exit(255); + } + + const char *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. + + const bool is_platform = false; + GDBRemoteCommunicationServer gdb_server (is_platform); + + if (host_and_port && host_and_port[0]) + { + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); + if (conn_ap.get()) + { + std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); + if (conn_ap.get()) + { + std::string connect_url ("listen://"); + connect_url.append(host_and_port); + + printf ("Listening for a connection on %s...\n", host_and_port); + if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess) + { + printf ("Connection established.\n"); + gdb_server.SetConnection (conn_ap.release()); + } + } + } + + if (gdb_server.IsConnected()) + { + // After we connected, we need to get an initial ack from... + if (gdb_server.HandshakeWithClient(&error)) + { + bool interrupt = false; + bool done = false; + while (!interrupt && !done) + { + if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done)) + break; + } + + if (error.Fail()) + { + fprintf(stderr, "error: %s\n", error.AsCString()); + } + } + else + { + fprintf(stderr, "error: handshake with client failed\n"); + } + } + } + + Debugger::Terminate(); + + fprintf(stderr, "lldb-gdbserver exiting...\n"); + + return 0; +} |