diff options
Diffstat (limited to 'lldb/source/Plugins/Process')
6 files changed, 261 insertions, 2 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 786d80176c6..fde38037d9a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/StringExtras.h" +#include "lldb/Target/Process.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/LLDBAssert.h" @@ -100,6 +101,41 @@ GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(ContinueDelegate &dele case 'A': delegate.HandleAsyncMisc(llvm::StringRef(response.GetStringRef()).substr(1)); break; + + case 'J': + // Asynchronous JSON packet, destined for a + // StructuredDataPlugin. + { + // Parse the content into a StructuredData instance. + auto payload_index = strlen("JSON-async:"); + StructuredData::ObjectSP json_sp = + StructuredData::ParseJSON(response.GetStringRef() + .substr(payload_index)); + if (log) + { + if (json_sp) + log->Printf( + "GDBRemoteCommmunicationClientBase::%s() " + "received Async StructuredData packet: %s", + __FUNCTION__, + response.GetStringRef(). + substr(payload_index).c_str()); + else + log->Printf("GDBRemoteCommmunicationClientBase::%s" + "() received StructuredData packet:" + " parse failure", __FUNCTION__); + } + + // Pass the data to the process to route to the + // appropriate plugin. The plugin controls what happens + // to it from there. + bool routed = delegate.HandleAsyncStructuredData(json_sp); + if (log) + log->Printf("GDBRemoteCommmunicationClientBase::%s()" + " packet %s", __FUNCTION__, + routed ? "handled" : "not handled"); + break; + } case 'T': case 'S': // Do this with the continue lock held. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h index 9cfba4b8394..684ef3e80d1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -31,6 +31,16 @@ public: HandleAsyncMisc(llvm::StringRef data) = 0; virtual void HandleStopReply() = 0; + + // + /// Processes async structured data. + /// + /// @return + /// true if the data was handled; otherwise, false. + // + virtual bool + HandleAsyncStructuredData(const StructuredData::ObjectSP + &object_sp) = 0; }; GDBRemoteClientBase(const char *comm_name, const char *listener_name); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 00357dd54e3..d893b868e75 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -30,6 +30,8 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Target/Target.h" // Project includes @@ -114,7 +116,10 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), m_default_packet_timeout(0), - m_max_packet_size(0) + m_max_packet_size(0), + m_qSupported_response(), + m_supported_async_json_packets_is_valid(false), + m_supported_async_json_packets_sp() { } @@ -378,6 +383,9 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) m_gdb_server_version = UINT32_MAX; m_default_packet_timeout = 0; m_max_packet_size = 0; + m_qSupported_response.clear(); + m_supported_async_json_packets_is_valid = false; + m_supported_async_json_packets_sp.reset(); } // These flags should be reset when we first connect to a GDB server @@ -413,6 +421,12 @@ GDBRemoteCommunicationClient::GetRemoteQSupported () /*send_async=*/false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); + + // Hang on to the qSupported packet, so that platforms can do custom + // configuration of the transport before attaching/launching the + // process. + m_qSupported_response = response_cstr; + if (::strstr (response_cstr, "qXfer:auxv:read+")) m_supports_qXfer_auxv_read = eLazyBoolYes; if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) @@ -3906,6 +3920,126 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) } } +StructuredData::Array* +GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() +{ + if (!m_supported_async_json_packets_is_valid) + { + // Query the server for the array of supported asynchronous JSON + // packets. + m_supported_async_json_packets_is_valid = true; + + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet( + GDBR_LOG_PROCESS)); + + // Poll it now. + StringExtractorGDBRemote response; + const bool send_async = false; + if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, + send_async) == PacketResult::Success) + { + m_supported_async_json_packets_sp = StructuredData::ParseJSON( + response.GetStringRef()); + if (m_supported_async_json_packets_sp && + !m_supported_async_json_packets_sp->GetAsArray()) + { + // We were returned something other than a JSON array. This + // is invalid. Clear it out. + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets returned invalid " + "result: %s", __FUNCTION__, + response.GetStringRef().c_str()); + m_supported_async_json_packets_sp.reset(); + } + } + else + { + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets unsupported", + __FUNCTION__); + } + + if (log && m_supported_async_json_packets_is_valid) + { + StreamString stream; + m_supported_async_json_packets_sp->Dump(stream); + log->Printf("GDBRemoteCommunicationClient::%s(): supported async " + "JSON packets: %s", __FUNCTION__, + stream.GetString().c_str()); + } + } + + return m_supported_async_json_packets_sp + ? m_supported_async_json_packets_sp->GetAsArray() + : nullptr; +} + +Error +GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( + const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) +{ + Error error; + + if (type_name.GetLength() == 0) + { + error.SetErrorString("invalid type_name argument"); + return error; + } + + // Build command: Configure{type_name}: serialized config + // data. + StreamGDBRemote stream; + stream.PutCString("QConfigure"); + stream.PutCString(type_name.AsCString()); + stream.PutChar(':'); + if (config_sp) + { + // Gather the plain-text version of the configuration data. + StreamString unescaped_stream; + config_sp->Dump(unescaped_stream); + unescaped_stream.Flush(); + + // Add it to the stream in escaped fashion. + stream.PutEscapedBytes(unescaped_stream.GetData(), + unescaped_stream.GetSize()); + } + stream.Flush(); + + // Send the packet. + const bool send_async = false; + StringExtractorGDBRemote response; + auto result = SendPacketAndWaitForResponse(stream.GetString().c_str(), + response, send_async); + if (result == PacketResult::Success) + { + // We failed if the config result comes back other than OK. + if (strcmp(response.GetStringRef().c_str(), "OK") == 0) + { + // Okay! + error.Clear(); + } + else + { + error.SetErrorStringWithFormat("configuring StructuredData feature " + "%s failed with error %s", + type_name.AsCString(), + response.GetStringRef().c_str()); + } + } + else + { + // Can we get more data here on the failure? + error.SetErrorStringWithFormat("configuring StructuredData feature %s " + "failed when sending packet: " + "PacketResult=%d", type_name.AsCString(), + result); + } + return error; +} + void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index b041ecbf3da..54e70792175 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -547,6 +547,53 @@ public: void ServeSymbolLookups(lldb_private::Process *process); + //------------------------------------------------------------------ + /// Return the feature set supported by the gdb-remote server. + /// + /// This method returns the remote side's response to the qSupported + /// packet. The response is the complete string payload returned + /// to the client. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + const std::string& + GetServerSupportedFeatures() const + { + return m_qSupported_response; + } + + //------------------------------------------------------------------ + /// Return the array of async JSON packet types supported by the remote. + /// + /// This method returns the remote side's array of supported JSON + /// packet types as a list of type names. Each of the results are + /// expected to have an Enable{type_name} command to enable and configure + /// the related feature. Each type_name for an enabled feature will + /// possibly send async-style packets that contain a payload of a + /// binhex-encoded JSON dictionary. The dictionary will have a + /// string field named 'type', that contains the type_name of the + /// supported packet type. + /// + /// There is a Plugin category called structured-data plugins. + /// A plugin indicates whether it knows how to handle a type_name. + /// If so, it can be used to process the async JSON packet. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + lldb_private::StructuredData::Array* + GetSupportedStructuredDataPlugins(); + + //------------------------------------------------------------------ + /// Configure a StructuredData feature on the remote end. + /// + /// @see \b Process::ConfigureStructuredData(...) for details. + //------------------------------------------------------------------ + Error + ConfigureRemoteStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp); + protected: LazyBool m_supports_not_sending_acks; LazyBool m_supports_thread_suffix; @@ -617,6 +664,10 @@ protected: uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported + std::string m_qSupported_response; // the complete response to qSupported + + bool m_supported_async_json_packets_is_valid; + lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp; bool GetCurrentProcessInfo (bool allow_lazy_pid = true); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1fa78fe155f..be5c3b552c8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1175,7 +1175,7 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) - log->Printf ("ProcessGDBRemote::DidLaunch()"); + log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__); if (GetID() != LLDB_INVALID_PROCESS_ID) { BuildDynamicRegisterInfo (false); @@ -1271,6 +1271,13 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) GetTarget().SetArchitecture (process_arch); } } + + // Find out which StructuredDataPlugins are supported by the + // debug monitor. These plugins transmit data over async $J packets. + auto supported_packets_array = + m_gdb_comm.GetSupportedStructuredDataPlugins(); + if (supported_packets_array) + MapSupportedStructuredDataPlugins(*supported_packets_array); } } @@ -4342,6 +4349,13 @@ ProcessGDBRemote::GetSharedCacheInfo () return object_sp; } +Error +ProcessGDBRemote::ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP + &config_sp) +{ + return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp); +} // Establish the largest memory read/write payloads we should use. // If the remote stub has a max packet size, stay under that size. @@ -5235,6 +5249,13 @@ ProcessGDBRemote::HandleStopReply() BuildDynamicRegisterInfo(true); } +bool +ProcessGDBRemote::HandleAsyncStructuredData(const StructuredData::ObjectSP + &object_sp) +{ + return RouteAsyncStructuredData(object_sp); +} + class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed { public: diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 0f41a2149ea..3a0dd2f7235 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -261,6 +261,10 @@ public: StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override; + Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) override; + StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos () override; @@ -506,6 +510,9 @@ private: HandleAsyncMisc(llvm::StringRef data) override; void HandleStopReply() override; + bool + HandleAsyncStructuredData(const StructuredData::ObjectSP + &object_sp) override; DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote); }; |