diff options
author | Tamas Berghammer <tberghammer@google.com> | 2015-12-08 14:08:19 +0000 |
---|---|---|
committer | Tamas Berghammer <tberghammer@google.com> | 2015-12-08 14:08:19 +0000 |
commit | ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5 (patch) | |
tree | 47ae8040ff8d1ce1485f2789a848bd181403c605 /lldb/source/Plugins/Process/gdb-remote | |
parent | 59d092f883a44c35822f3038128a11452801c7a4 (diff) | |
download | bcm5719-llvm-ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5.tar.gz bcm5719-llvm-ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5.zip |
Modify "platform connect" to connect to processes as well
The standard remote debugging workflow with gdb is to start the
application on the remote host under gdbserver (e.g.: gdbserver :5039
a.out) and then connect to it with gdb.
The same workflow is supported by debugserver/lldb-gdbserver with a very
similar syntax but to access all features of lldb we need to be
connected also to an lldb-platform instance running on the target.
Before this change this had to be done manually with starting a separate
lldb-platform on the target machine and then connecting to it with lldb
before connecting to the process.
This change modifies the behavior of "platform connect" with
automatically connecting to the process instance if it was started by
the remote platform. With this command replacing gdbserver in a gdb
based worflow is usually as simple as replacing the command to execute
gdbserver with executing lldb-platform.
Differential revision: http://reviews.llvm.org/D14952
llvm-svn: 255016
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
6 files changed, 183 insertions, 66 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index ea95298dd5c..2ea1f206008 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1115,7 +1115,8 @@ Error GDBRemoteCommunication::StartDebugserverProcess (const char *url, Platform *platform, ProcessLaunchInfo &launch_info, - uint16_t *port) + uint16_t *port, + const Args& inferior_args) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -1328,6 +1329,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, } } while (has_env_var); + if (inferior_args.GetArgumentCount() > 0) + { + debugserver_args.AppendArgument ("--"); + debugserver_args.AppendArguments (inferior_args); + } + + // Copy the current environment to the gdbserver/debugserver instance + StringList env; + if (Host::GetEnvironment(env)) + { + for (size_t i = 0; i < env.GetSize(); ++i) + launch_info.GetEnvironmentEntries().AppendArgument(env[i].c_str()); + } + // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index ccc8ef1b247..2a01bcec260 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -25,6 +25,7 @@ #include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" #include "Utility/StringExtractorGDBRemote.h" @@ -168,7 +169,8 @@ public: StartDebugserverProcess(const char *url, Platform *platform, // If non nullptr, then check with the platform for the GDB server binary if it can't be located ProcessLaunchInfo &launch_info, - uint16_t *port); + uint16_t *port, + const Args& inferior_args = Args()); void DumpHistory(Stream &strm); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 7b193f0bffb..5c7f6caca51 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3383,6 +3383,43 @@ GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostnam return false; } +size_t +GDBRemoteCommunicationClient::QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls) +{ + connection_urls.clear(); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) + return 0; + + StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); + if (!data) + return 0; + + StructuredData::Array* array = data->GetAsArray(); + if (!array) + return 0; + + for (size_t i = 0, count = array->GetSize(); i < count; ++i) + { + StructuredData::Dictionary* element = nullptr; + if (!array->GetItemAtIndexAsDictionary(i, element)) + continue; + + uint16_t port = 0; + if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) + port = port_osp->GetIntegerValue(0); + + std::string socket_name; + if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) + socket_name = socket_name_osp->GetStringValue(); + + if (port != 0 || !socket_name.empty()) + connection_urls.emplace_back(port, socket_name); + } + return connection_urls.size(); +} + bool GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 2c41d199ca5..d2df214d0db 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -119,7 +119,10 @@ public: lldb::pid_t &pid, uint16_t &port, std::string &socket_name); - + + size_t + QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls); + bool KillSpawnedProcess (lldb::pid_t pid); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 19a29b4654a..022c558352b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -34,6 +34,7 @@ #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/JSON.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -54,7 +55,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_platform_sp (Platform::GetHostPlatform ()), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_pending_gdb_server{ LLDB_INVALID_PROCESS_ID, 0, "" } { RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, &GDBRemoteCommunicationServerPlatform::Handle_qC); @@ -62,6 +64,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, @@ -90,38 +94,16 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() { } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +Error +GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args, + std::string hostname, + lldb::pid_t& pid, + uint16_t& port, + std::string& socket_name) { -#ifdef _WIN32 - return SendErrorResponse(9); -#else - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); - - // Sleep and wait a bit for debugserver to start to listen... - ConnectionFileDescriptor file_conn; - std::string hostname; - // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environment variable - packet.SetFilePos(::strlen ("qLaunchGDBServer;")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - } if (port == UINT16_MAX) port = GetNextAvailablePort(); - + // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). @@ -132,6 +114,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD ProcessLaunchInfo debugserver_launch_info; if (hostname.empty()) hostname = "127.0.0.1"; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); @@ -148,11 +132,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD UNUSED_IF_ASSERT_DISABLED(ok); assert(ok); - std::string socket_name; std::ostringstream url; - uint16_t* port_ptr = &port; - url << m_socket_scheme << "://"; if (m_socket_protocol == Socket::ProtocolTcp) url << platform_ip << ":" << port; else @@ -165,56 +146,108 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD Error error = StartDebugserverProcess (url.str().c_str(), nullptr, debugserver_launch_info, - port_ptr); - - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - + port_ptr, + args); - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + pid = debugserver_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); + m_spawned_pids.insert(pid); if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); + AssociatePortWithProcess(port, pid); } else { if (port > 0) - FreePort (port); + FreePort(port); } + return error; +} - if (error.Success()) +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +{ +#ifdef _WIN32 + return SendErrorResponse(9); +#else + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); + + ConnectionFileDescriptor file_conn; + std::string hostname; + packet.SetFilePos(::strlen ("qLaunchGDBServer;")); + std::string name; + std::string value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) + { + if (name.compare ("host") == 0) + hostname.swap(value); + else if (name.compare ("port") == 0) + port = StringConvert::ToUInt32(value.c_str(), 0, 0); + } + + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + std::string socket_name; + Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + return SendErrorResponse(9); + } - StreamGDBRemote response; - response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - if (!socket_name.empty()) - { - response.PutCString("socket_name:"); - response.PutCStringAsRawHex8(socket_name.c_str()); - response.PutChar(';'); - } + if (log) + log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + StreamGDBRemote response; + response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + if (!socket_name.empty()) + { + response.PutCString("socket_name:"); + response.PutCStringAsRawHex8(socket_name.c_str()); + response.PutChar(';'); } - else + + PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); + if (packet_result != PacketResult::Success) { - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } - return SendErrorResponse (9); + return packet_result; #endif } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer (StringExtractorGDBRemote &packet) +{ + if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(4); + + JSONObject::SP server_sp = std::make_shared<JSONObject>(); + server_sp->SetObject("port", std::make_shared<JSONNumber>(m_pending_gdb_server.port)); + if (!m_pending_gdb_server.socket_name.empty()) + server_sp->SetObject("socket_name", + std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); + + JSONArray server_list; + server_list.AppendObject(server_sp); + + StreamGDBRemote response; + server_list.Write(response); + + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); + return SendPacketNoLock(escaped_response.GetData(), escaped_response.GetSize()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); @@ -553,7 +586,17 @@ GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix) } void -GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset) +GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { m_port_offset = port_offset; } + +void +GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(lldb::pid_t pid, + uint16_t port, + const std::string& socket_name) +{ + m_pending_gdb_server.pid = pid; + m_pending_gdb_server.port = port; + m_pending_gdb_server.socket_name = socket_name; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 6e8f5b06e16..1fe7207d2bc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -66,6 +66,19 @@ public: void SetPortOffset (uint16_t port_offset); + void + SetInferiorArguments (const lldb_private::Args& args); + + Error + LaunchGDBServer(const lldb_private::Args& args, + std::string hostname, + lldb::pid_t& pid, + uint16_t& port, + std::string& socket_name); + + void + SetPendingGdbServer(lldb::pid_t pid, uint16_t port, const std::string& socket_name); + protected: const Socket::SocketProtocol m_socket_protocol; const std::string m_socket_scheme; @@ -75,11 +88,15 @@ protected: PortMap m_port_map; uint16_t m_port_offset; + struct { lldb::pid_t pid; uint16_t port; std::string socket_name; } m_pending_gdb_server; PacketResult Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); PacketResult + Handle_qQueryGDBServer (StringExtractorGDBRemote &packet); + + PacketResult Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); PacketResult |