summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2016-09-08 10:07:04 +0000
committerPavel Labath <labath@google.com>2016-09-08 10:07:04 +0000
commit2f1fbaebe25a4637cf75ec9ab1877c64584ede24 (patch)
treecca4e3ae0fd9afec5fbeeccd59b2b964262b3b88
parent2b7ed1339cea63180bc3203ac57b4c5b12219589 (diff)
downloadbcm5719-llvm-2f1fbaebe25a4637cf75ec9ab1877c64584ede24.tar.gz
bcm5719-llvm-2f1fbaebe25a4637cf75ec9ab1877c64584ede24.zip
gdb-remote: Add jModulesInfo packet
Summary: This adds the jModulesInfo packet, which is the equivalent of qModulesInfo, but it enables us to query multiple modules at once. This makes a significant speed improvement in case the application has many (over a hundred) modules, and the communication link has a non-negligible latency. This functionality is accessed by ProcessGdbRemote::PrefetchModuleSpecs(), which does the caching. GetModuleSpecs() is modified to first consult the cache before asking the remote stub. PrefetchModuleSpecs is currently only called from POSIX-DYLD dynamic loader plugin, after it reads the list of modules from the inferior memory, but other uses are possible. This decreases the attach time to an android application by about 40%. Reviewers: clayborg Subscribers: tberghammer, lldb-commits, danalbert Differential Revision: https://reviews.llvm.org/D24236 llvm-svn: 280919
-rw-r--r--lldb/docs/lldb-gdb-remote.txt22
-rw-r--r--lldb/include/lldb/Target/Process.h5
-rw-r--r--lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py39
-rw-r--r--lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp7
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp90
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h9
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp99
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h6
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp22
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h31
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp2
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.h1
-rw-r--r--lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp74
13 files changed, 390 insertions, 17 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 2fec87bdaf5..45098189418 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -1054,6 +1054,28 @@ for this region.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
+// jModulesInfo:[{"file":"...",triple:"..."}, ...]
+//
+// BRIEF
+// Get information for a list of modules by given module path and
+// architecture.
+//
+// RESPONSE
+// A JSON array of dictionaries containing the following keys: uuid,
+// triple, file_path, file_offset, file_size. The meaning of the fields
+// is the same as in the qModuleInfo packet. The server signals the
+// failure to retrieve the module info for a file by ommiting the
+// corresponding array entry from the response. The server may also
+// include entries the client did not ask for, if it has reason to
+// the modules will be interesting to the client.
+//
+// PRIORITY TO IMPLEMENT
+// Optional. If not implemented, qModuleInfo packet will be used, which
+// may be slower if the target contains a large number of modules and
+// the communication link has a non-negligible latency.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
// Stop reply packet extensions
//
// BRIEF
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 00c4dfed502..b112249743f 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -50,6 +50,8 @@
#include "lldb/Target/ThreadList.h"
#include "lldb/lldb-private.h"
+#include "llvm/ADT/ArrayRef.h"
+
namespace lldb_private {
template <typename B, typename S> struct Range;
@@ -2646,6 +2648,9 @@ public:
virtual bool GetModuleSpec(const FileSpec &module_file_spec,
const ArchSpec &arch, ModuleSpec &module_spec);
+ virtual void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs,
+ const llvm::Triple &triple) {}
+
//------------------------------------------------------------------
/// Try to find the load address of a file.
/// The load address is defined as the address of the first memory
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
new file mode 100644
index 00000000000..3441075836f
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
@@ -0,0 +1,39 @@
+from __future__ import print_function
+
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestGdbRemoteModuleInfo(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def module_info(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines([
+ 'read packet: $jModulesInfo:[{"file":"%s","triple":"%s"}]]#00' % (
+ lldbutil.append_to_process_working_directory("a.out"),
+ self.dbg.GetSelectedPlatform().GetTriple()),
+ {"direction": "send",
+ "regex": r'^\$\[{(.*)}\]\]#[0-9A-Fa-f]{2}',
+ "capture": {1: "spec"}},
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ spec = context.get("spec")
+ self.assertRegexpMatches(spec, '"file_path":".*"')
+ self.assertRegexpMatches(spec, '"file_offset":\d+')
+ self.assertRegexpMatches(spec, '"file_size":\d+')
+ self.assertRegexpMatches(spec, '"triple":"\w*-\w*-.*"')
+ self.assertRegexpMatches(spec, '"uuid":"[A-Fa-f0-9]+"')
+
+ @llgs_test
+ def test_module_info(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.module_info()
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index cb27190cf33..8678f616eac 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -509,6 +509,13 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
module_list.Append(module_sp);
}
}
+
+ std::vector<FileSpec> module_names;
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ module_names.push_back(I->file_spec);
+ m_process->PrefetchModuleSpecs(
+ module_names, m_process->GetTarget().GetArchitecture().GetTriple());
+
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
ModuleSP module_sp =
LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 6e09196ed21..68baba2494b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -32,6 +32,7 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/JSON.h"
#include "lldb/Utility/LLDBAssert.h"
// Project includes
@@ -93,8 +94,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
m_supports_z4(true), m_supports_QEnvironment(true),
m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true),
m_qSymbol_requests_done(false), m_supports_qModuleInfo(true),
- m_supports_jThreadsInfo(true), m_curr_pid(LLDB_INVALID_PROCESS_ID),
- m_curr_tid(LLDB_INVALID_THREAD_ID),
+ m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true),
+ m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID),
m_curr_tid_run(LLDB_INVALID_THREAD_ID),
m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(),
m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX),
@@ -323,6 +324,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_qSupported_response.clear();
m_supported_async_json_packets_is_valid = false;
m_supported_async_json_packets_sp.reset();
+ m_supports_jModulesInfo = true;
}
// These flags should be reset when we first connect to a GDB server
@@ -3232,6 +3234,90 @@ bool GDBRemoteCommunicationClient::GetModuleInfo(
return true;
}
+static llvm::Optional<ModuleSpec>
+ParseModuleSpec(StructuredData::Dictionary *dict) {
+ ModuleSpec result;
+ if (!dict)
+ return llvm::None;
+
+ std::string string;
+ uint64_t integer;
+
+ if (!dict->GetValueForKeyAsString("uuid", string))
+ return llvm::None;
+ result.GetUUID().SetFromCString(string.c_str(), string.size());
+
+ if (!dict->GetValueForKeyAsInteger("file_offset", integer))
+ return llvm::None;
+ result.SetObjectOffset(integer);
+
+ if (!dict->GetValueForKeyAsInteger("file_size", integer))
+ return llvm::None;
+ result.SetObjectSize(integer);
+
+ if (!dict->GetValueForKeyAsString("triple", string))
+ return llvm::None;
+ result.GetArchitecture().SetTriple(string.c_str());
+
+ if (!dict->GetValueForKeyAsString("file_path", string))
+ return llvm::None;
+ result.GetFileSpec() = FileSpec(string, false, result.GetArchitecture());
+
+ return result;
+}
+
+llvm::Optional<std::vector<ModuleSpec>>
+GDBRemoteCommunicationClient::GetModulesInfo(
+ llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) {
+ if (!m_supports_jModulesInfo)
+ return llvm::None;
+
+ JSONArray::SP module_array_sp = std::make_shared<JSONArray>();
+ for (const FileSpec &module_file_spec : module_file_specs) {
+ JSONObject::SP module_sp = std::make_shared<JSONObject>();
+ module_array_sp->AppendObject(module_sp);
+ module_sp->SetObject(
+ "file", std::make_shared<JSONString>(module_file_spec.GetPath()));
+ module_sp->SetObject("triple",
+ std::make_shared<JSONString>(triple.getTriple()));
+ }
+ StreamString unescaped_payload;
+ unescaped_payload.PutCString("jModulesInfo:");
+ module_array_sp->Write(unescaped_payload);
+ StreamGDBRemote payload;
+ payload.PutEscapedBytes(unescaped_payload.GetData(),
+ unescaped_payload.GetSize());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(payload.GetString(), response, false) !=
+ PacketResult::Success ||
+ response.IsErrorResponse())
+ return llvm::None;
+
+ if (response.IsUnsupportedResponse()) {
+ m_supports_jModulesInfo = false;
+ return llvm::None;
+ }
+
+ StructuredData::ObjectSP response_object_sp =
+ StructuredData::ParseJSON(response.GetStringRef());
+ if (!response_object_sp)
+ return llvm::None;
+
+ StructuredData::Array *response_array = response_object_sp->GetAsArray();
+ if (!response_array)
+ return llvm::None;
+
+ std::vector<ModuleSpec> result;
+ for (size_t i = 0; i < response_array->GetSize(); ++i) {
+ if (llvm::Optional<ModuleSpec> module_spec = ParseModuleSpec(
+ response_array->GetItemAtIndex(i)->GetAsDictionary()))
+ result.push_back(*module_spec);
+ }
+
+ return result;
+}
+
// query the target remote for extended information using the qXfer packet
//
// example: object='features', annex='target.xml', out=<xml output>
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index e40c08cc681..cfdcc881d76 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -26,6 +26,8 @@
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
+#include "llvm/ADT/Optional.h"
+
namespace lldb_private {
namespace process_gdb_remote {
@@ -437,6 +439,10 @@ public:
bool GetModuleInfo(const FileSpec &module_file_spec,
const ArchSpec &arch_spec, ModuleSpec &module_spec);
+ llvm::Optional<std::vector<ModuleSpec>>
+ GetModulesInfo(llvm::ArrayRef<FileSpec> module_file_specs,
+ const llvm::Triple &triple);
+
bool ReadExtFeature(const lldb_private::ConstString object,
const lldb_private::ConstString annex, std::string &out,
lldb_private::Error &err);
@@ -527,7 +533,8 @@ protected:
m_supports_z2 : 1, m_supports_z3 : 1, m_supports_z4 : 1,
m_supports_QEnvironment : 1, m_supports_QEnvironmentHexEncoded : 1,
m_supports_qSymbol : 1, m_qSymbol_requests_done : 1,
- m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1;
+ m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1,
+ m_supports_jModulesInfo : 1;
lldb::pid_t m_curr_pid;
lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index f7ef2fe2176..0d7ca3c53e4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -38,6 +38,7 @@
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/JSON.h"
#include "llvm/ADT/Triple.h"
// Project includes
@@ -102,6 +103,9 @@ GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(
StringExtractorGDBRemote::eServerPacketType_qModuleInfo,
&GDBRemoteCommunicationServerCommon::Handle_qModuleInfo);
RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jModulesInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_jModulesInfo);
+ RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod,
&GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod);
RegisterMemberFunctionHandler(
@@ -1078,22 +1082,11 @@ GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
std::string triple;
packet.GetHexByteString(triple);
- ArchSpec arch(triple.c_str());
- const FileSpec req_module_path_spec(module_path.c_str(), true);
- const FileSpec module_path_spec =
- FindModuleFile(req_module_path_spec.GetPath(), arch);
- const ModuleSpec module_spec(module_path_spec, arch);
-
- ModuleSpecList module_specs;
- if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0,
- module_specs))
+ ModuleSpec matched_module_spec = GetModuleInfo(module_path, triple);
+ if (!matched_module_spec.GetFileSpec())
return SendErrorResponse(3);
- ModuleSpec matched_module_spec;
- if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
- return SendErrorResponse(4);
-
const auto file_offset = matched_module_spec.GetObjectOffset();
const auto file_size = matched_module_spec.GetObjectSize();
const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
@@ -1119,7 +1112,7 @@ GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
response.PutChar(';');
response.PutCString("file_path:");
- response.PutCStringAsRawHex8(module_path_spec.GetCString());
+ response.PutCStringAsRawHex8(matched_module_spec.GetFileSpec().GetCString());
response.PutChar(';');
response.PutCString("file_offset:");
response.PutHex64(file_offset);
@@ -1131,6 +1124,63 @@ GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
return SendPacketNoLock(response.GetString());
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_jModulesInfo(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("jModulesInfo:"));
+
+ StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(packet.Peek());
+ if (!object_sp)
+ return SendErrorResponse(1);
+
+ StructuredData::Array *packet_array = object_sp->GetAsArray();
+ if (!packet_array)
+ return SendErrorResponse(2);
+
+ JSONArray::SP response_array_sp = std::make_shared<JSONArray>();
+ for (size_t i = 0; i < packet_array->GetSize(); ++i) {
+ StructuredData::Dictionary *query =
+ packet_array->GetItemAtIndex(i)->GetAsDictionary();
+ if (!query)
+ continue;
+ std::string file, triple;
+ if (!query->GetValueForKeyAsString("file", file) ||
+ !query->GetValueForKeyAsString("triple", triple))
+ continue;
+
+ ModuleSpec matched_module_spec = GetModuleInfo(file, triple);
+ if (!matched_module_spec.GetFileSpec())
+ continue;
+
+ const auto file_offset = matched_module_spec.GetObjectOffset();
+ const auto file_size = matched_module_spec.GetObjectSize();
+ const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
+
+ if (uuid_str.empty())
+ continue;
+
+ JSONObject::SP response = std::make_shared<JSONObject>();
+ response_array_sp->AppendObject(response);
+ response->SetObject("uuid", std::make_shared<JSONString>(uuid_str));
+ response->SetObject(
+ "triple",
+ std::make_shared<JSONString>(
+ matched_module_spec.GetArchitecture().GetTriple().getTriple()));
+ response->SetObject("file_path",
+ std::make_shared<JSONString>(
+ matched_module_spec.GetFileSpec().GetPath()));
+ response->SetObject("file_offset",
+ std::make_shared<JSONNumber>(file_offset));
+ response->SetObject("file_size", std::make_shared<JSONNumber>(file_size));
+ }
+
+ StreamString response;
+ response_array_sp->Write(response);
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse(
const ProcessInstanceInfo &proc_info, StreamString &response) {
response.Printf(
@@ -1230,3 +1280,24 @@ FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile(
return FileSpec(module_path.c_str(), true);
#endif
}
+
+ModuleSpec GDBRemoteCommunicationServerCommon::GetModuleInfo(
+ const std::string &module_path, const std::string &triple) {
+ ArchSpec arch(triple.c_str());
+
+ const FileSpec req_module_path_spec(module_path.c_str(), true);
+ const FileSpec module_path_spec =
+ FindModuleFile(req_module_path_spec.GetPath(), arch);
+ const ModuleSpec module_spec(module_path_spec, arch);
+
+ ModuleSpecList module_specs;
+ if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0,
+ module_specs))
+ return ModuleSpec();
+
+ ModuleSpec matched_module_spec;
+ if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ return ModuleSpec();
+
+ return matched_module_spec;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
index d6be24a0e4b..321a92266bd 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -86,6 +86,8 @@ protected:
PacketResult Handle_qModuleInfo(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jModulesInfo(StringExtractorGDBRemote &packet);
+
PacketResult Handle_qPlatform_shell(StringExtractorGDBRemote &packet);
PacketResult Handle_qPlatform_mkdir(StringExtractorGDBRemote &packet);
@@ -149,6 +151,10 @@ protected:
virtual FileSpec FindModuleFile(const std::string &module_path,
const ArchSpec &arch);
+
+private:
+ ModuleSpec GetModuleInfo(const std::string &module_path,
+ const std::string &triple);
};
} // namespace process_gdb_remote
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 9e21e820dc7..cf220f3150b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4020,6 +4020,14 @@ bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec,
ModuleSpec &module_spec) {
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
+ const ModuleCacheKey key(module_file_spec.GetPath(),
+ arch.GetTriple().getTriple());
+ auto cached = m_cached_module_specs.find(key);
+ if (cached != m_cached_module_specs.end()) {
+ module_spec = cached->second;
+ return bool(module_spec);
+ }
+
if (!m_gdb_comm.GetModuleInfo(module_file_spec, arch, module_spec)) {
if (log)
log->Printf("ProcessGDBRemote::%s - failed to get module info for %s:%s",
@@ -4037,9 +4045,23 @@ bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec,
stream.GetString().c_str());
}
+ m_cached_module_specs[key] = module_spec;
return true;
}
+void ProcessGDBRemote::PrefetchModuleSpecs(
+ llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) {
+ auto module_specs = m_gdb_comm.GetModulesInfo(module_file_specs, triple);
+ if (module_specs) {
+ for (const FileSpec &spec : module_file_specs)
+ m_cached_module_specs[{spec.GetPath(), triple.getTriple()}] =
+ ModuleSpec();
+ for (const ModuleSpec &spec : *module_specs)
+ m_cached_module_specs[{spec.GetFileSpec().GetPath(),
+ triple.getTriple()}] = spec;
+ }
+}
+
bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor,
uint32_t &update) {
if (m_gdb_comm.GetOSVersion(major, minor, update))
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index f2a58dbccaa..493176d72c2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -25,6 +25,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/LoadedModuleInfoList.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/StringList.h"
#include "lldb/Core/StructuredData.h"
@@ -38,6 +39,8 @@
#include "GDBRemoteCommunicationClient.h"
#include "GDBRemoteRegisterContext.h"
+#include "llvm/ADT/DenseMap.h"
+
namespace lldb_private {
namespace process_gdb_remote {
@@ -194,6 +197,9 @@ public:
bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
ModuleSpec &module_spec) override;
+ void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs,
+ const llvm::Triple &triple) override;
+
bool GetHostOSVersion(uint32_t &major, uint32_t &minor,
uint32_t &update) override;
@@ -412,6 +418,31 @@ private:
bool
HandleAsyncStructuredData(const StructuredData::ObjectSP &object_sp) override;
+ using ModuleCacheKey = std::pair<std::string, std::string>;
+ // KeyInfo for the cached module spec DenseMap.
+ // The invariant is that all real keys will have the file and architecture
+ // set.
+ // The empty key has an empty file and an empty arch.
+ // The tombstone key has an invalid arch and an empty file.
+ // The comparison and hash functions take the file name and architecture
+ // triple into account.
+ struct ModuleCacheInfo {
+ static ModuleCacheKey getEmptyKey() { return ModuleCacheKey(); }
+
+ static ModuleCacheKey getTombstoneKey() { return ModuleCacheKey("", "T"); }
+
+ static unsigned getHashValue(const ModuleCacheKey &key) {
+ return llvm::hash_combine(key.first, key.second);
+ }
+
+ static bool isEqual(const ModuleCacheKey &LHS, const ModuleCacheKey &RHS) {
+ return LHS == RHS;
+ }
+ };
+
+ llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo>
+ m_cached_module_specs;
+
DISALLOW_COPY_AND_ASSIGN(ProcessGDBRemote);
};
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index c2f8f5a4a8c..dd13be9a763 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -279,6 +279,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
break;
case 'j':
+ if (PACKET_STARTS_WITH("jModulesInfo:"))
+ return eServerPacketType_jModulesInfo;
if (PACKET_MATCHES("jSignalsInfo"))
return eServerPacketType_jSignalsInfo;
if (PACKET_MATCHES("jThreadsInfo"))
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h
index f63e72f68c4..ce12660f0d3 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.h
+++ b/lldb/source/Utility/StringExtractorGDBRemote.h
@@ -128,6 +128,7 @@ public:
eServerPacketType_qXfer_auxv_read,
eServerPacketType_jSignalsInfo,
+ eServerPacketType_jModulesInfo,
eServerPacketType_vAttach,
eServerPacketType_vAttachWait,
diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index c5d41ae81f4..1fa24c98bb9 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -19,6 +19,7 @@
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/ModuleSpec.h"
#include "llvm/ADT/ArrayRef.h"
@@ -185,3 +186,76 @@ TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
HandlePacket(server, "QSyncThreadState:0047;", "OK");
ASSERT_TRUE(async_result.get());
}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ llvm::Triple triple("i386-pc-linux");
+
+ FileSpec file_specs[] = {FileSpec("/foo/bar.so", false),
+ FileSpec("/foo/baz.so", false)};
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_specs, triple); });
+ HandlePacket(
+ server, "jModulesInfo:["
+ R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
+ R"({"file":"/foo/baz.so","triple":"i386-pc-linux"}])",
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
+
+ auto result = async_result.get();
+ ASSERT_TRUE(result.hasValue());
+ ASSERT_EQ(1u, result->size());
+ EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
+ EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
+ EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), result.getValue()[0].GetUUID());
+ EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
+ EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ llvm::Triple triple("i386-pc-linux");
+ FileSpec file_spec("/foo/bar.so", false);
+
+ const char *invalid_responses[] = {
+ "OK", "E47", "[]",
+ // no UUID
+ R"([{"triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
+ // no triple
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
+ // no file_path
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_offset":0,"file_size":1234}])",
+ // no file_offset
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_size":1234}])",
+ // no file_size
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0}])",
+ };
+
+ for (const char *response : invalid_responses) {
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_spec, triple); });
+ HandlePacket(
+ server,
+ R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
+ response);
+
+ ASSERT_FALSE(async_result.get().hasValue()) << "response was: " << response;
+ }
+}
OpenPOWER on IntegriCloud