This revision was automatically updated to reflect the committed changes.
Closed by commit rL280919: gdb-remote: Add jModulesInfo packet (authored by 
labath).

Changed prior to commit:
  https://reviews.llvm.org/D24236?vs=70409&id=70671#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D24236

Files:
  lldb/trunk/docs/lldb-gdb-remote.txt
  lldb/trunk/include/lldb/Target/Process.h
  
lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
  lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
  lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
  lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
  
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
  
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
  lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
  lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
  lldb/trunk/source/Utility/StringExtractorGDBRemote.h
  lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp

Index: lldb/trunk/include/lldb/Target/Process.h
===================================================================
--- lldb/trunk/include/lldb/Target/Process.h
+++ lldb/trunk/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 @@
   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
Index: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
===================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
+++ lldb/trunk/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()
Index: lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
===================================================================
--- lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ lldb/trunk/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 @@
   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;
+  }
+}
Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
@@ -279,6 +279,8 @@
     break;
 
   case 'j':
+    if (PACKET_STARTS_WITH("jModulesInfo:"))
+      return eServerPacketType_jModulesInfo;
     if (PACKET_MATCHES("jSignalsInfo"))
       return eServerPacketType_jSignalsInfo;
     if (PACKET_MATCHES("jThreadsInfo"))
Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.h
===================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.h
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h
@@ -128,6 +128,7 @@
     eServerPacketType_qXfer_auxv_read,
 
     eServerPacketType_jSignalsInfo,
+    eServerPacketType_jModulesInfo,
 
     eServerPacketType_vAttach,
     eServerPacketType_vAttachWait,
Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ lldb/trunk/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 @@
   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 @@
       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
Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ lldb/trunk/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 @@
       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 @@
 
   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 @@
   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 @@
   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 @@
   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;
+}
Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/trunk/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 @@
       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 @@
     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 @@
   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>
Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/trunk/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 @@
   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 @@
   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);
 };
 
Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/trunk/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))
Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -86,6 +86,8 @@
 
   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 @@
 
   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
Index: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
===================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -509,6 +509,13 @@
       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);
Index: lldb/trunk/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt
+++ lldb/trunk/docs/lldb-gdb-remote.txt
@@ -1054,6 +1054,28 @@
 //----------------------------------------------------------------------
 
 //----------------------------------------------------------------------
+// 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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to