friss created this revision.
friss added reviewers: jasonmolenda, labath.
Herald added projects: LLDB, LLVM.
Herald added a subscriber: llvm-commits.

On macOS 11, the libraries that have been integrated in the system
shared cache are not present on the filesystem anymore. LLDB was
using those files to get access to the symbols of those libraries.
LLDB can get the images from the target process memory though.

This has 2 consequences:

- LLDB cannot load the images before the process starts, reporting an error if 
someone tries to break on a system symbol.
- Loading the symbols by downloading the data from the inferior is super slow. 
It takes tens of seconds at the start of the debug session to populate the 
Module list.

To fix this, we can use the library images LLDB has in its own
mapping of the shared cache. To do this patch extends ModuleSpec
to be able to store a DataBuffer for the Module that the MacOS
platform will provide by querying a new HostInfo utility which
describes the contents of the shared cache.

This patch fixes a number of test failures on macOS 11 due to the
first problem described above.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D83023

Files:
  lldb/include/lldb/Core/Module.h
  lldb/include/lldb/Core/ModuleSpec.h
  lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
  lldb/include/lldb/Symbol/ObjectFile.h
  lldb/include/lldb/Utility/DataBuffer.h
  lldb/source/Core/Module.cpp
  lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
  lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
  lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
  lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
  lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
  lldb/source/Symbol/ObjectFile.cpp
  lldb/unittests/Host/HostInfoTest.cpp
  llvm/include/llvm/BinaryFormat/MachO.h

Index: llvm/include/llvm/BinaryFormat/MachO.h
===================================================================
--- llvm/include/llvm/BinaryFormat/MachO.h
+++ llvm/include/llvm/BinaryFormat/MachO.h
@@ -82,7 +82,8 @@
   MH_HAS_TLV_DESCRIPTORS = 0x00800000u,
   MH_NO_HEAP_EXECUTION = 0x01000000u,
   MH_APP_EXTENSION_SAFE = 0x02000000u,
-  MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000u
+  MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000u,
+  MH_DYLIB_IN_CACHE = 0x80000000u,
 };
 
 enum : uint32_t {
Index: lldb/unittests/Host/HostInfoTest.cpp
===================================================================
--- lldb/unittests/Host/HostInfoTest.cpp
+++ lldb/unittests/Host/HostInfoTest.cpp
@@ -60,3 +60,18 @@
   EXPECT_TRUE(HostInfo::GetXcodeSDKPath(XcodeSDK("CeciNestPasUnOS.sdk")).empty());
 }
 #endif
+
+#if defined(__APPLE__)
+TEST_F(HostInfoTest, GetSharedCacheInfo) {
+  const SharedCacheInfo &shared_cache_info = HostInfo::GetSharedCacheInfo();
+  EXPECT_TRUE(shared_cache_info.GetUUID().IsValid());
+  EXPECT_TRUE(shared_cache_info.GetData());
+  SharedCacheImageInfo image_info =
+      shared_cache_info.GetImages().lookup("/usr/lib/libobjc.A.dylib");
+  EXPECT_TRUE(image_info.unslidTextOffset);
+
+  for (const auto& image : shared_cache_info.GetImages()) {
+    EXPECT_TRUE(image.getValue().unslidTextOffset < shared_cache_info.GetData()->GetByteSize());
+  }
+}
+#endif
Index: lldb/source/Symbol/ObjectFile.cpp
===================================================================
--- lldb/source/Symbol/ObjectFile.cpp
+++ lldb/source/Symbol/ObjectFile.cpp
@@ -207,9 +207,15 @@
 size_t ObjectFile::GetModuleSpecifications(const FileSpec &file,
                                            lldb::offset_t file_offset,
                                            lldb::offset_t file_size,
-                                           ModuleSpecList &specs) {
-  DataBufferSP data_sp =
-      FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, file_offset);
+                                           ModuleSpecList &specs,
+                                           DataBufferSP data_sp) {
+  lldb::offset_t data_offset = 0;
+  if (!data_sp)
+    data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512,
+                                                      file_offset);
+  else
+    data_offset = file_offset;
+
   if (data_sp) {
     if (file_size == 0) {
       const lldb::offset_t actual_file_size =
@@ -219,7 +225,7 @@
     }
     return ObjectFile::GetModuleSpecifications(file,        // file spec
                                                data_sp,     // data bytes
-                                               0,           // data offset
+                                               data_offset, // data offset
                                                file_offset, // file offset
                                                file_size,   // file length
                                                specs);
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -39,6 +39,9 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/VersionTuple.h"
+#include <Plugins/ObjectFile/Mach-O/ObjectFileMachO.h>
+
+#include <mach/mach.h>
 
 #if defined(__APPLE__)
 #include <TargetConditionals.h>
@@ -237,6 +240,35 @@
 
   Status err;
 
+#if __APPLE__
+  if (IsHost()) {
+    // When debugging on the host, we are most likely using the same shared
+    // cache as our inferior. The dylibs from the shared cache might not
+    // exist on the filesystem, so let's use the images in our own memory
+    // to create the modules.
+
+    const auto &shared_cache_info = HostInfo::GetSharedCacheInfo();
+    const auto &shared_cache_images = shared_cache_info.GetImages();
+    // Check if the requested image is in our shared cache.
+    SharedCacheImageInfo image_info =
+        shared_cache_images.lookup(module_spec.GetFileSpec().GetPath());
+
+    // If we found it and it has the correct UUID, let's proceed with
+    // creating a module from the memory contents.
+    if (image_info.unslidTextOffset &&
+        (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
+      ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
+                                   shared_cache_info.GetData());
+      shared_cache_spec.SetObjectOffset(image_info.unslidTextOffset);
+      err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
+                                        module_search_paths_ptr,
+                                        old_module_sp_ptr, did_create_ptr);
+      if (module_sp)
+        return err;
+    }
+  }
+#endif
+
   err = ModuleList::GetSharedModule(module_spec, module_sp,
                                     module_search_paths_ptr, old_module_sp_ptr,
                                     did_create_ptr);
Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
===================================================================
--- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -129,6 +129,13 @@
 
   bool GetIsDynamicLinkEditor() override;
 
+  size_t ReadSectionData(lldb_private::Section *section,
+                         lldb::offset_t section_offset, void *dst,
+                         size_t dst_len) override;
+
+  size_t ReadSectionData(lldb_private::Section *section,
+                         lldb_private::DataExtractor &section_data) override;
+
   static bool ParseHeader(lldb_private::DataExtractor &data,
                           lldb::offset_t *data_offset_ptr,
                           llvm::MachO::mach_header &header);
Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -47,8 +47,8 @@
 
 #include "ObjectFileMachO.h"
 
-#if defined(__APPLE__) &&                                                      \
-    (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
 // GetLLDBSharedCacheUUID() needs to call dlsym()
 #include <dlfcn.h>
 #endif
@@ -823,7 +823,8 @@
     lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
   const size_t initial_count = specs.GetSize();
 
-  if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
+  if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset,
+                                       data_sp->GetByteSize())) {
     DataExtractor data;
     data.SetData(data_sp);
     llvm::MachO::mach_header header;
@@ -923,6 +924,57 @@
   ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
 }
 
+size_t ObjectFileMachO::ReadSectionData(Section *section,
+                                        lldb::offset_t section_offset,
+                                        void *dst, size_t dst_len) {
+  if (!(m_header.flags & MH_DYLIB_IN_CACHE) || IsInMemory())
+    return ObjectFile::ReadSectionData(section, section_offset, dst, dst_len);
+
+  // We get here only for modules from LLDB's own shared cache.
+  assert(!IsInMemory());
+  // In the shared cache, the load command file offsets are relative to the
+  // base of the shared cache, not the dylib image.
+  Section *segment = section->GetParent().get();
+  if (!segment)
+    segment = section;
+
+  // We know __TEXT is at offset 0 of the image. Compute the offset of the
+  // segment we are looking for.
+  SectionSP text_segment_sp =
+      GetSectionList()->FindSectionByName(GetSegmentNameTEXT());
+  lldb::offset_t segment_offset =
+      segment->GetFileAddress() - text_segment_sp->GetFileAddress();
+  uint64_t offset_in_segment =
+      section->GetFileOffset() - segment->GetFileOffset();
+  return CopyData(segment_offset + offset_in_segment + section_offset, dst_len,
+                  dst);
+}
+
+size_t ObjectFileMachO::ReadSectionData(Section *section,
+                                        DataExtractor &section_data) {
+  if (!(m_header.flags & MH_DYLIB_IN_CACHE) || IsInMemory())
+    return ObjectFile::ReadSectionData(section, section_data);
+
+  // We get here only for modules from LLDB's own shared cache.
+  assert(!IsInMemory());
+  // In the shared cache, the load command file offsets are relative to the
+  // base of the shared cache, not the dylib image.
+  Section *segment = section->GetParent().get();
+  if (!segment)
+    segment = section;
+
+  // We know __TEXT is at offset 0 of the image. Compute the offset of the
+  // segment we are looking for.
+  SectionSP text_segment_sp =
+      GetSectionList()->FindSectionByName(GetSegmentNameTEXT());
+  lldb::offset_t segment_offset =
+      segment->GetFileAddress() - text_segment_sp->GetFileAddress();
+  uint64_t offset_in_segment =
+      section->GetFileOffset() - segment->GetFileOffset();
+  return GetData(segment_offset + offset_in_segment, section->GetFileSize(),
+                 section_data);
+}
+
 bool ObjectFileMachO::ParseHeader(DataExtractor &data,
                                   lldb::offset_t *data_offset_ptr,
                                   llvm::MachO::mach_header &header) {
@@ -2264,19 +2316,30 @@
   Process *process = process_sp.get();
 
   uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
+  bool is_shared_cache_image = m_header.flags & MH_DYLIB_IN_CACHE;
 
-  if (process && m_header.filetype != llvm::MachO::MH_OBJECT) {
-    Target &target = process->GetTarget();
-
-    memory_module_load_level = target.GetMemoryModuleLoadLevel();
+  if (m_header.filetype != llvm::MachO::MH_OBJECT &&
+      (process_sp || is_shared_cache_image)) {
+    Target *target = process ? &process->GetTarget() : nullptr;
 
     SectionSP linkedit_section_sp(
         section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
+    SectionSP text_segment_sp =
+        section_list->FindSectionByName(GetSegmentNameTEXT());
+
+    if (target)
+      memory_module_load_level = target->GetMemoryModuleLoadLevel();
     // Reading mach file from memory in a process or core file...
 
     if (linkedit_section_sp) {
-      addr_t linkedit_load_addr =
-          linkedit_section_sp->GetLoadBaseAddress(&target);
+      addr_t linkedit_load_addr = LLDB_INVALID_ADDRESS;
+      if (target)
+        linkedit_load_addr = linkedit_section_sp->GetLoadBaseAddress(target);
+      else if (is_shared_cache_image && !IsInMemory())
+        linkedit_load_addr = linkedit_section_sp->GetFileAddress() +
+                             (ptrdiff_t)(&m_data.GetData()[0] -
+                                         text_segment_sp->GetFileAddress());
+
       if (linkedit_load_addr == LLDB_INVALID_ADDRESS) {
         // We might be trying to access the symbol table before the
         // __LINKEDIT's load address has been set in the target. We can't
@@ -2295,10 +2358,9 @@
 
       bool data_was_read = false;
 
-#if defined(__APPLE__) &&                                                      \
-    (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
-      if (m_header.flags & 0x80000000u &&
-          process->GetAddressByteSize() == sizeof(void *)) {
+#if defined(__APPLE__)
+      if (is_shared_cache_image &&
+          (!process || process->GetAddressByteSize() == sizeof(void *))) {
         // This mach-o memory file is in the dyld shared cache. If this
         // program is not remote and this is iOS, then this process will
         // share the same shared cache as the process we are debugging and we
@@ -2318,19 +2380,26 @@
         UUID lldb_shared_cache;
         addr_t lldb_shared_cache_addr;
         GetLLDBSharedCacheUUID(lldb_shared_cache_addr, lldb_shared_cache);
-        UUID process_shared_cache;
-        addr_t process_shared_cache_addr;
-        GetProcessSharedCacheUUID(process, process_shared_cache_addr,
-                                  process_shared_cache);
         bool use_lldb_cache = true;
-        if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() &&
-            (lldb_shared_cache != process_shared_cache ||
-             process_shared_cache_addr != lldb_shared_cache_addr)) {
-          use_lldb_cache = false;
+
+        if (process) {
+          UUID process_shared_cache;
+          addr_t process_shared_cache_addr;
+          GetProcessSharedCacheUUID(process, process_shared_cache_addr,
+                                    process_shared_cache);
+          if (!lldb_shared_cache.IsValid() || !process_shared_cache.IsValid() ||
+              lldb_shared_cache != process_shared_cache ||
+              process_shared_cache_addr != lldb_shared_cache_addr) {
+            use_lldb_cache = false;
+          }
         }
 
-        PlatformSP platform_sp(target.GetPlatform());
-        if (platform_sp && platform_sp->IsHost() && use_lldb_cache) {
+        if (target && use_lldb_cache) {
+          PlatformSP platform_sp(target->GetPlatform());
+          use_lldb_cache = platform_sp && platform_sp->IsHost();
+        }
+
+        if (use_lldb_cache) {
           data_was_read = true;
           nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size,
                              eByteOrderLittle);
@@ -2344,6 +2413,23 @@
                                          function_starts_load_command.datasize,
                                          eByteOrderLittle);
           }
+
+          if (m_dysymtab.nindirectsyms != 0) {
+            const addr_t dysymtab_start_addr = linkedit_load_addr +
+                                               m_dysymtab.indirectsymoff -
+                                               linkedit_file_offset;
+            indirect_symbol_index_data.SetData((void *)dysymtab_start_addr,
+                                               m_dysymtab.nindirectsyms * 4,
+                                               eByteOrderLittle);
+          }
+
+          if (dyld_info.export_size > 0) {
+            const addr_t dyld_trie_start_addr = linkedit_load_addr +
+                                                dyld_info.export_off -
+                                                linkedit_file_offset;
+            dyld_trie_data.SetData((void *)dyld_trie_start_addr,
+                                   dyld_info.export_size, eByteOrderLittle);
+          }
         }
       }
 #endif
@@ -2379,7 +2465,7 @@
             // problem. For binaries outside the shared cache, it's faster to
             // read the entire strtab at once instead of piece-by-piece as we
             // process the nlist records.
-            if ((m_header.flags & 0x80000000u) == 0) {
+            if ((is_shared_cache_image) == 0) {
               DataBufferSP strtab_data_sp(
                   ReadMemory(process_sp, strtab_addr, strtab_data_byte_size));
               if (strtab_data_sp) {
@@ -2608,7 +2694,7 @@
   // to parse any DSC unmapped symbol information. If we find any, we set a
   // flag that tells the normal nlist parser to ignore all LOCAL symbols.
 
-  if (m_header.flags & 0x80000000u) {
+  if (m_header.flags & MH_DYLIB_IN_CACHE) {
     // Before we can start mapping the DSC, we need to make certain the
     // target process is actually using the cache we can find.
 
@@ -5807,8 +5893,7 @@
   uuid.Clear();
   base_addr = LLDB_INVALID_ADDRESS;
 
-#if defined(__APPLE__) &&                                                      \
-    (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+#if defined(__APPLE__)
   uint8_t *(*dyld_get_all_image_infos)(void);
   dyld_get_all_image_infos =
       (uint8_t * (*)()) dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos");
Index: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
===================================================================
--- lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Core/Section.h"
 #include "lldb/Expression/DiagnosticManager.h"
 #include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/ABI.h"
@@ -123,19 +124,44 @@
       module_sp.reset();
   }
 
-  if (!module_sp) {
-    if (can_create) {
-      // We'll call Target::ModulesDidLoad after all the modules have been
-      // added to the target, don't let it be called for every one.
-      module_sp = target.GetOrCreateModule(module_spec, false /* notify */);
-      if (!module_sp || module_sp->GetObjectFile() == nullptr)
-        module_sp = m_process->ReadModuleFromMemory(image_info.file_spec,
-                                                    image_info.address);
-
-      if (did_create_ptr)
-        *did_create_ptr = (bool)module_sp;
+  if (module_sp || !can_create)
+    return module_sp;
+
+#if __APPLE__
+  if (HostInfo::GetArchitecture().IsExactMatch(target.GetArchitecture())) {
+    // When debugging on the host, we are most likely using the same shared
+    // cache as our inferior. The dylibs from the shared cache might not
+    // exist on the filesystem, so let's use the images in our own memory
+    // to create the modules.
+    const auto &shared_cache_info = HostInfo::GetSharedCacheInfo();
+    const auto &shared_cache_images = shared_cache_info.GetImages();
+    // Check if the requested image is in our shared cache.
+    SharedCacheImageInfo image_info =
+        shared_cache_images.lookup(module_spec.GetFileSpec().GetPath());
+
+    // If we found it and it has the correct UUID, let's proceed with
+    // creating a module from the memory contents.
+    if (image_info.unslidTextOffset &&
+        (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
+      ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
+                                   shared_cache_info.GetData());
+      shared_cache_spec.SetObjectOffset(image_info.unslidTextOffset);
+      module_sp =
+          target.GetOrCreateModule(shared_cache_spec, false /* notify */);
     }
   }
+#endif
+  // We'll call Target::ModulesDidLoad after all the modules have been
+  // added to the target, don't let it be called for every one.
+  if (!module_sp)
+    module_sp = target.GetOrCreateModule(module_spec, false /* notify */);
+  if (!module_sp || module_sp->GetObjectFile() == nullptr)
+    module_sp = m_process->ReadModuleFromMemory(image_info.file_spec,
+                                                image_info.address);
+
+  if (did_create_ptr)
+    *did_create_ptr = (bool)module_sp;
+
   return module_sp;
 }
 
Index: lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
===================================================================
--- lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -457,3 +457,45 @@
   auto it_new = g_sdk_path.insert({sdk.GetString(), GetXcodeSDK(sdk)});
   return it_new.first->second;
 }
+
+const SharedCacheInfo &HostInfoMacOSX::GetSharedCacheInfo() {
+  static SharedCacheInfo g_shared_cache_info;
+  return g_shared_cache_info;
+}
+
+typedef unsigned char uuid_t[16];
+struct dyld_shared_cache_dylib_text_info {
+  uint64_t version; // current version 1
+  // following fields all exist in version 1
+  uint64_t loadAddressUnslid;
+  uint64_t textSegmentSize;
+  uuid_t dylibUuid;
+  const char *path; // pointer invalid at end of iterations
+  // following fields all exist in version 2
+  uint64_t textSegmentOffset; // offset from start of cache
+};
+typedef struct dyld_shared_cache_dylib_text_info
+    dyld_shared_cache_dylib_text_info;
+
+extern "C" int dyld_shared_cache_iterate_text(
+    const uuid_t cacheUuid,
+    void (^callback)(const dyld_shared_cache_dylib_text_info *info));
+extern "C" uint8_t *_dyld_get_shared_cache_range(size_t *length);
+extern "C" bool _dyld_get_shared_cache_uuid(uuid_t uuid);
+
+SharedCacheInfo::SharedCacheInfo() {
+  size_t shared_cache_size;
+  uint8_t *shared_cache_start =
+      _dyld_get_shared_cache_range(&shared_cache_size);
+  m_data = std::make_shared<DataBufferHostMemory>(shared_cache_start,
+                                                  shared_cache_size);
+  uuid_t dsc_uuid;
+  _dyld_get_shared_cache_uuid(dsc_uuid);
+  m_uuid = UUID::fromData(dsc_uuid);
+
+  dyld_shared_cache_iterate_text(
+      dsc_uuid, ^(const dyld_shared_cache_dylib_text_info *info) {
+        m_images[info->path] = SharedCacheImageInfo{
+            info->textSegmentOffset, UUID::fromData(info->dylibUuid, 16)};
+      });
+}
Index: lldb/source/Core/Module.cpp
===================================================================
--- lldb/source/Core/Module.cpp
+++ lldb/source/Core/Module.cpp
@@ -147,11 +147,23 @@
                   : module_spec.GetObjectName().AsCString(""),
               module_spec.GetObjectName().IsEmpty() ? "" : ")");
 
+  lldb::offset_t file_offset = 0;
+  lldb::offset_t file_size = 0;
+
+  auto data_sp = module_spec.GetData();
+  // If the ModuleSpec provided a DataBuffer, let's respect the ModuleSpec's
+  // file offset when reading in this buffer.
+  if (data_sp) {
+    file_offset = module_spec.GetObjectOffset();
+    file_size = module_spec.GetData()->GetByteSize();
+  }
+
   // First extract all module specifications from the file using the local file
   // path. If there are no specifications, then don't fill anything in
   ModuleSpecList modules_specs;
-  if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0,
-                                          modules_specs) == 0)
+  if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(),
+                                          file_offset, file_size, modules_specs,
+                                          data_sp) == 0)
     return;
 
   // Now make sure that one of the module specifications matches what we just
@@ -170,11 +182,20 @@
     return;
   }
 
-  if (module_spec.GetFileSpec())
-    m_mod_time = FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec());
-  else if (matching_module_spec.GetFileSpec())
-    m_mod_time =
-        FileSystem::Instance().GetModificationTime(matching_module_spec.GetFileSpec());
+  // Set m_data_sp if it was initially provided in the ModuleSpec. Note that
+  // we cannot use the data_sp variable here, because it will have been
+  // modified by GetModuleSpecifications().
+  if (auto module_spec_data_sp = module_spec.GetData()) {
+    m_data_sp = module_spec_data_sp;
+    m_mod_time = {};
+  } else {
+    if (module_spec.GetFileSpec())
+      m_mod_time =
+          FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec());
+    else if (matching_module_spec.GetFileSpec())
+      m_mod_time = FileSystem::Instance().GetModificationTime(
+          matching_module_spec.GetFileSpec());
+  }
 
   // Copy the architecture from the actual spec if we got one back, else use
   // the one that was specified
@@ -209,6 +230,11 @@
   else
     m_object_name = module_spec.GetObjectName();
 
+  if (lldb::offset_t size = matching_module_spec.GetObjectSize())
+    m_object_size = size;
+  else if (auto data_sp = matching_module_spec.GetData())
+    m_object_size = data_sp->GetByteSize();
+
   // Always trust the object offset (file offset) and object modification time
   // (for mod time in a BSD static archive) of from the matching module
   // specification
@@ -1110,6 +1136,10 @@
 }
 
 bool Module::FileHasChanged() const {
+  // We have provided the DataBuffer for this module to avoid accessing the
+  // filesystem. We never want to reload those files.
+  if (m_data_sp)
+    return false;
   if (!m_file_has_changed)
     m_file_has_changed =
         (FileSystem::Instance().GetModificationTime(m_file) != m_mod_time);
@@ -1229,15 +1259,26 @@
       static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
       Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s",
                          GetFileSpec().GetFilename().AsCString(""));
-      DataBufferSP data_sp;
       lldb::offset_t data_offset = 0;
-      const lldb::offset_t file_size =
-          FileSystem::Instance().GetByteSize(m_file);
+      lldb::offset_t file_size;
+
+      if (m_object_size)
+        file_size = m_object_size;
+      else
+        file_size =
+            FileSystem::Instance().GetByteSize(m_file) - m_object_offset;
+
+      if (m_data_sp)
+        data_offset = m_object_offset;
+
       if (file_size > m_object_offset) {
         m_did_load_objfile = true;
-        m_objfile_sp = ObjectFile::FindPlugin(
-            shared_from_this(), &m_file, m_object_offset,
-            file_size - m_object_offset, data_sp, data_offset);
+        // FindPlugin will modify its data_sp argument. Do not let it
+        // modify our m_data_sp member.
+        auto data_sp = m_data_sp;
+        m_objfile_sp =
+            ObjectFile::FindPlugin(shared_from_this(), &m_file, m_object_offset,
+                                   file_size, data_sp, data_offset);
         if (m_objfile_sp) {
           // Once we get the object file, update our module with the object
           // file's architecture since it might differ in vendor/os if some
Index: lldb/include/lldb/Utility/DataBuffer.h
===================================================================
--- lldb/include/lldb/Utility/DataBuffer.h
+++ lldb/include/lldb/Utility/DataBuffer.h
@@ -79,6 +79,20 @@
   }
 };
 
+class DataBufferHostMemory : public DataBuffer {
+public:
+  DataBufferHostMemory(uint8_t *bytes, lldb::offset_t size)
+      : m_bytes(bytes), m_size(size) {}
+
+  uint8_t *GetBytes() override { return m_bytes; }
+  const uint8_t *GetBytes() const override { return m_bytes; }
+  lldb::offset_t GetByteSize() const override { return m_size; }
+
+private:
+  uint8_t *m_bytes;
+  lldb::offset_t m_size;
+};
+
 } // namespace lldb_private
 
 #endif /// #if defined(__cplusplus)
Index: lldb/include/lldb/Symbol/ObjectFile.h
===================================================================
--- lldb/include/lldb/Symbol/ObjectFile.h
+++ lldb/include/lldb/Symbol/ObjectFile.h
@@ -172,10 +172,10 @@
                                        lldb::addr_t header_addr,
                                        lldb::DataBufferSP &file_data_sp);
 
-  static size_t GetModuleSpecifications(const FileSpec &file,
-                                        lldb::offset_t file_offset,
-                                        lldb::offset_t file_size,
-                                        ModuleSpecList &specs);
+  static size_t
+  GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset,
+                          lldb::offset_t file_size, ModuleSpecList &specs,
+                          lldb::DataBufferSP data_sp = lldb::DataBufferSP());
 
   static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
                                         lldb::DataBufferSP &data_sp,
Index: lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
===================================================================
--- lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
+++ lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Host/posix/HostInfoPosix.h"
 #include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
 #include "lldb/Utility/XcodeSDK.h"
 #include "llvm/Support/VersionTuple.h"
 
@@ -18,6 +19,28 @@
 
 class ArchSpec;
 
+struct SharedCacheImageInfo {
+  lldb::offset_t unslidTextOffset;
+  UUID uuid;
+};
+
+class SharedCacheInfo {
+public:
+  lldb::DataBufferSP GetData() const { return m_data; };
+  const UUID &GetUUID() const { return m_uuid; };
+  const llvm::StringMap<SharedCacheImageInfo> &GetImages() const {
+    return m_images;
+  };
+
+private:
+  llvm::StringMap<SharedCacheImageInfo> m_images;
+  UUID m_uuid;
+  lldb::DataBufferSP m_data;
+
+  SharedCacheInfo();
+  friend class HostInfoMacOSX;
+};
+
 class HostInfoMacOSX : public HostInfoPosix {
   friend class HostInfoBase;
 
@@ -37,6 +60,10 @@
 
   /// Query xcrun to find an Xcode SDK directory.
   static llvm::StringRef GetXcodeSDKPath(XcodeSDK sdk);
+
+  /// Shared cache utilities
+  static const SharedCacheInfo &GetSharedCacheInfo();
+
 protected:
   static bool ComputeSupportExeDirectory(FileSpec &file_spec);
   static void ComputeHostArchitectureSupport(ArchSpec &arch_32,
Index: lldb/include/lldb/Core/ModuleSpec.h
===================================================================
--- lldb/include/lldb/Core/ModuleSpec.h
+++ lldb/include/lldb/Core/ModuleSpec.h
@@ -30,11 +30,15 @@
         m_object_name(), m_object_offset(0), m_object_size(0),
         m_source_mappings() {}
 
-  ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID())
+  /// If the \param data argument is passed, its contents will be used
+  /// as the module contents instead of trying to read them from
+  /// \param file_spec.
+  ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID(),
+             lldb::DataBufferSP data = lldb::DataBufferSP())
       : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(),
         m_uuid(uuid), m_object_name(), m_object_offset(0),
         m_object_size(FileSystem::Instance().GetByteSize(file_spec)),
-        m_source_mappings() {}
+        m_source_mappings(), m_data(data) {}
 
   ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch)
       : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(arch),
@@ -146,6 +150,8 @@
 
   PathMappingList &GetSourceMappingList() const { return m_source_mappings; }
 
+  lldb::DataBufferSP GetData() const { return m_data; }
+
   void Clear() {
     m_file.Clear();
     m_platform_file.Clear();
@@ -289,6 +295,7 @@
   uint64_t m_object_size;
   llvm::sys::TimePoint<> m_object_mod_time;
   mutable PathMappingList m_source_mappings;
+  lldb::DataBufferSP m_data = {};
 };
 
 class ModuleSpecList {
Index: lldb/include/lldb/Core/Module.h
===================================================================
--- lldb/include/lldb/Core/Module.h
+++ lldb/include/lldb/Core/Module.h
@@ -957,7 +957,14 @@
                              ///selected, or empty of the module is represented
                              ///by \a m_file.
   uint64_t m_object_offset;
+  uint64_t m_object_size = 0;
   llvm::sys::TimePoint<> m_object_mod_time;
+
+  /// DataBuffer containing the module image, if it was provided at
+  /// construction time. Otherwise the data will be retrieved by mapping
+  /// one of the FileSpec members above.
+  lldb::DataBufferSP m_data_sp;
+
   lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file
                                    ///parser for this module as it may or may
                                    ///not be shared with the SymbolFile
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to