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
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 9e21e82..cf220f3 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4020,6 +4020,14 @@
                                      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 @@
                 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))