labath updated this revision to Diff 70409.
labath added a comment.

- fix a bug where we would mark all modules as invalid if communicating with a 
stub which does not support this packet
- extend the packet documentation about what to do when modules are not found 
and the server volunteering information


https://reviews.llvm.org/D24236

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

Index: unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
===================================================================
--- unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ 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"
 
@@ -182,3 +183,75 @@
     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");
+
+    // Empty list of module specs should not send any packets
+    ASSERT_TRUE(client.GetModulesInfo({}, triple).empty());
+
+    FileSpec file_specs[] = { FileSpec("/foo/bar.so", false), FileSpec("/foo/baz.so", false) };
+    std::future<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}]])");
+
+    std::vector<ModuleSpec> result = async_result.get();
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ("/foo/bar.so", result[0].GetFileSpec().GetPath());
+    EXPECT_EQ(triple, result[0].GetArchitecture().GetTriple());
+    EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), result[0].GetUUID());
+    EXPECT_EQ(0u, result[0].GetObjectOffset());
+    EXPECT_EQ(1234u, result[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<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_TRUE(async_result.get().empty());
+    }
+}
Index: source/Utility/StringExtractorGDBRemote.h
===================================================================
--- source/Utility/StringExtractorGDBRemote.h
+++ source/Utility/StringExtractorGDBRemote.h
@@ -146,6 +146,7 @@
         eServerPacketType_qXfer_auxv_read,
 
         eServerPacketType_jSignalsInfo,
+        eServerPacketType_jModulesInfo,
 
         eServerPacketType_vAttach,
         eServerPacketType_vAttachWait,
Index: source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- source/Utility/StringExtractorGDBRemote.cpp
+++ source/Utility/StringExtractorGDBRemote.cpp
@@ -223,6 +223,7 @@
         break;
 
     case 'j':
+        if (PACKET_STARTS_WITH("jModulesInfo:"))                return eServerPacketType_jModulesInfo;
         if (PACKET_MATCHES("jSignalsInfo"))                     return eServerPacketType_jSignalsInfo;
         if (PACKET_MATCHES("jThreadsInfo"))                     return eServerPacketType_jThreadsInfo;
         break;
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -28,6 +28,7 @@
 #include "lldb/Core/StringList.h"
 #include "lldb/Core/StructuredData.h"
 #include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/LoadedModuleInfoList.h"
 #include "lldb/Host/HostThread.h"
 #include "lldb/lldb-private-forward.h"
@@ -38,6 +39,8 @@
 #include "GDBRemoteCommunicationClient.h"
 #include "GDBRemoteRegisterContext.h"
 
+#include "llvm/ADT/DenseMap.h"
+
 namespace lldb_private {
 namespace process_gdb_remote {
 
@@ -241,6 +244,9 @@
                   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,
@@ -514,6 +520,42 @@
     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: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4397,6 +4397,14 @@
 {
     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)
@@ -4415,9 +4423,22 @@
                      arch.GetTriple ().getTriple ().c_str (), 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,
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -109,6 +109,9 @@
     Handle_qModuleInfo (StringExtractorGDBRemote &packet);
 
     PacketResult
+    Handle_jModulesInfo(StringExtractorGDBRemote &packet);
+
+    PacketResult
     Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
 
     PacketResult
@@ -192,6 +195,12 @@
 
     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: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -39,6 +39,7 @@
 #include "lldb/Target/FileAction.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/JSON.h"
 
 // Project includes
 #include "ProcessGDBRemoteLog.h"
@@ -94,6 +95,8 @@
                                   &GDBRemoteCommunicationServerCommon::Handle_qEcho);
     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo,
                                   &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo);
+    RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jModulesInfo,
+                                  &GDBRemoteCommunicationServerCommon::Handle_jModulesInfo);
     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod,
                                   &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod);
     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir,
@@ -1125,20 +1128,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("");
@@ -1165,7 +1159,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);
@@ -1177,6 +1171,57 @@
     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)
@@ -1284,3 +1329,23 @@
     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: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ 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 {
 
@@ -535,6 +537,9 @@
                    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,
@@ -641,7 +646,8 @@
         m_supports_qSymbol:1,
         m_qSymbol_requests_done:1,
         m_supports_qModuleInfo:1,
-        m_supports_jThreadsInfo: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 other operations
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -33,6 +33,7 @@
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/UnixSignals.h"
 #include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/JSON.h"
 #include "lldb/Target/Target.h"
 
 // Project includes
@@ -104,6 +105,7 @@
       m_qSymbol_requests_done(false),
       m_supports_qModuleInfo(true),
       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),
@@ -389,6 +391,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
@@ -3662,6 +3665,89 @@
     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: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
===================================================================
--- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -521,6 +521,12 @@
             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: packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py
@@ -0,0 +1,38 @@
+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: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -50,6 +50,8 @@
 #include "lldb/Target/ThreadList.h"
 #include "lldb/Target/InstrumentationRuntime.h"
 
+#include "llvm/ADT/ArrayRef.h"
+
 namespace lldb_private {
 
 template <typename B, typename S>
@@ -3196,6 +3198,11 @@
     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: docs/lldb-gdb-remote.txt
===================================================================
--- docs/lldb-gdb-remote.txt
+++ 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