[Lldb-commits] [lldb] [lldb] Look up shared cache images by UUID instead of iterating (PR #194998)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 29 21:02:09 PDT 2026


https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/194998

Add HostInfo::WithSharedCacheImage to look up a dyld shared cache image directly by UUID, replacing the expensive iteration through all installed shared caches and their images in ObjectFileMachO's symbol table parsing. The new API takes a callback that receives the retained image handle, ensuring it remains valid for the duration of the call.

>From 1d3a0fc35d5420450a6bda197478559428bf8e77 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Wed, 29 Apr 2026 21:00:57 -0700
Subject: [PATCH] [lldb] Look up shared cache images by UUID instead of
 iterating

Add HostInfo::WithSharedCacheImage to look up a dyld shared cache
image directly by UUID, replacing the expensive iteration through
all installed shared caches and their images in ObjectFileMachO's
symbol table parsing. The new API takes a callback that receives
the retained image handle, ensuring it remains valid for the
duration of the call.
---
 lldb/include/lldb/Host/HostInfoBase.h         |  11 ++
 .../include/lldb/Host/macosx/HostInfoMacOSX.h |   5 +
 .../Host/macosx/objcxx/HostInfoMacOSX.mm      |  26 +++++
 .../ObjectFile/Mach-O/ObjectFileMachO.cpp     | 105 +++++++-----------
 4 files changed, 84 insertions(+), 63 deletions(-)

diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h
index 3074a97a6fac1..a003b39276cf2 100644
--- a/lldb/include/lldb/Host/HostInfoBase.h
+++ b/lldb/include/lldb/Host/HostInfoBase.h
@@ -16,6 +16,7 @@
 #include "lldb/Utility/UserIDResolver.h"
 #include "lldb/Utility/XcodeSDK.h"
 #include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Errc.h"
 
@@ -266,6 +267,16 @@ class HostInfoBase {
     return false;
   }
 
+  /// Invoke \p callback with the retained dyld_image_t for a shared cache
+  /// image matching \p image_uuid. The image handle is only valid for the
+  /// duration of the callback. Returns true if the image was found.
+  static bool
+  WithSharedCacheImage(const UUID &image_uuid, const UUID &sc_uuid,
+                       lldb::SymbolSharedCacheUse sc_mode,
+                       llvm::function_ref<void(void *image)> callback) {
+    return false;
+  }
+
   /// Returns the distribution id of the host
   ///
   /// This will be something like "ubuntu", "fedora", etc. on Linux.
diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
index 6c2cabbf55c74..9ee4612591b0c 100644
--- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
+++ b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
@@ -58,6 +58,11 @@ class HostInfoMacOSX : public HostInfoPosix {
   static bool SharedCacheIndexFiles(FileSpec &filepath, UUID &uuid,
                                     lldb::SymbolSharedCacheUse sc_mode);
 
+  static bool
+  WithSharedCacheImage(const UUID &image_uuid, const UUID &sc_uuid,
+                       lldb::SymbolSharedCacheUse sc_mode,
+                       llvm::function_ref<void(void *image)> callback);
+
   /// Check whether a bundle at the given path has a valid code signature that
   /// chains to a trusted anchor in the system trust store.
   static bool IsBundleCodeSignTrusted(const FileSpec &bundle_path);
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 9f1335ee2946d..5efe4fc74d145 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -717,6 +717,25 @@ SharedCacheImageInfo GetByUUID(UUID sc_uuid, UUID file_uuid) {
   /// system, open it and add all of the binary images to m_caches.
   bool CreateSharedCacheImageList(UUID uuid, std::string filepath);
 
+  /// Invoke \p callback with the retained dyld_image_t for the image matching
+  /// \p file_uuid in shared cache \p sc_uuid. Returns true if found.
+  bool WithImageBaton(UUID sc_uuid, UUID file_uuid,
+                      llvm::function_ref<void(void *image)> callback) {
+    llvm::sys::ScopedReader guard(m_mutex);
+    if (!sc_uuid)
+      sc_uuid = m_host_uuid;
+    if (!m_uuid_map.contains(sc_uuid))
+      return false;
+    if (!m_uuid_map[sc_uuid].contains(file_uuid))
+      return false;
+    size_t idx = m_uuid_map[sc_uuid][file_uuid];
+    void *baton = m_file_infos[sc_uuid][idx].GetImageBaton();
+    if (!baton)
+      return false;
+    callback(baton);
+    return true;
+  }
+
   SharedCacheInfo(SymbolSharedCacheUse sc_mode);
 
 private:
@@ -1099,6 +1118,13 @@ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
   return false;
 }
 
+bool HostInfoMacOSX::WithSharedCacheImage(
+    const UUID &image_uuid, const UUID &sc_uuid, SymbolSharedCacheUse sc_mode,
+    llvm::function_ref<void(void *image)> callback) {
+  return GetSharedCacheSingleton(sc_mode).WithImageBaton(sc_uuid, image_uuid,
+                                                         callback);
+}
+
 bool HostInfoMacOSX::IsBundleCodeSignTrusted(const FileSpec &bundle_path) {
   std::string path = bundle_path.GetPath();
   CFURLRef url = CFURLCreateFromFileSystemRepresentation(
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 814eb58b7b9b8..692f3eb766fb9 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -15,11 +15,13 @@
 #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Progress.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/DWARFCallFrameInfo.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/DynamicLoader.h"
@@ -2718,73 +2720,50 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
     UndefinedNameToDescMap undefined_name_to_desc;
     SymbolIndexToName reexport_shlib_needs_fixup;
 
-    dyld_for_each_installed_shared_cache(^(dyld_shared_cache_t shared_cache) {
-      uuid_t cache_uuid;
-      dyld_shared_cache_copy_uuid(shared_cache, &cache_uuid);
-      if (found_image)
+    auto nlist_extraction_block = ^(const void *nlistStart, uint64_t nlistCount,
+                                    const char *stringTable) {
+      if (!nlistStart || !nlistCount)
         return;
 
-        if (process_shared_cache_uuid.IsValid() &&
-          process_shared_cache_uuid != UUID(&cache_uuid, 16))
+      kern_return_t ret = vm_read(mach_task_self(), (vm_address_t)nlistStart,
+                                  nlist_byte_size * nlistCount,
+                                  &vm_nlist_memory, &vm_nlist_bytes_read);
+      if (ret != KERN_SUCCESS)
+        return;
+      assert(vm_nlist_bytes_read == nlist_byte_size * nlistCount);
+
+      vm_address_t string_address = (vm_address_t)stringTable;
+      vm_size_t region_size;
+      mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
+      vm_region_basic_info_data_t info;
+      memory_object_name_t object;
+      ret = vm_region_64(mach_task_self(), &string_address, &region_size,
+                         VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info,
+                         &info_count, &object);
+      if (ret != KERN_SUCCESS)
         return;
 
-      dyld_shared_cache_for_each_image(shared_cache, ^(dyld_image_t image) {
-        uuid_t dsc_image_uuid;
-        if (found_image)
-          return;
-
-        dyld_image_copy_uuid(image, &dsc_image_uuid);
-        if (image_uuid != UUID(dsc_image_uuid, 16))
-          return;
-
-        found_image = true;
-
-        // Compute the size of the string table. We need to ask dyld for a
-        // new SPI to avoid this step.
-        dyld_image_local_nlist_content_4Symbolication(
-            image, ^(const void *nlistStart, uint64_t nlistCount,
-                     const char *stringTable) {
-              if (!nlistStart || !nlistCount)
-                return;
-
-              // The buffers passed here are valid only inside the block.
-              // Use vm_read to make a cheap copy of them available for our
-              // processing later.
-              kern_return_t ret =
-                  vm_read(mach_task_self(), (vm_address_t)nlistStart,
-                          nlist_byte_size * nlistCount, &vm_nlist_memory,
-                          &vm_nlist_bytes_read);
-              if (ret != KERN_SUCCESS)
-                return;
-              assert(vm_nlist_bytes_read == nlist_byte_size * nlistCount);
-
-              // We don't know the size of the string table. It's cheaper
-              // to map the whole VM region than to determine the size by
-              // parsing all the nlist entries.
-              vm_address_t string_address = (vm_address_t)stringTable;
-              vm_size_t region_size;
-              mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
-              vm_region_basic_info_data_t info;
-              memory_object_name_t object;
-              ret = vm_region_64(mach_task_self(), &string_address,
-                                 &region_size, VM_REGION_BASIC_INFO_64,
-                                 (vm_region_info_t)&info, &info_count, &object);
-              if (ret != KERN_SUCCESS)
-                return;
-
-              ret = vm_read(mach_task_self(), (vm_address_t)stringTable,
-                            region_size -
-                                ((vm_address_t)stringTable - string_address),
-                            &vm_string_memory, &vm_string_bytes_read);
-              if (ret != KERN_SUCCESS)
-                return;
-
-              nlist_buffer = (void *)vm_nlist_memory;
-              string_table = (char *)vm_string_memory;
-              nlist_count = nlistCount;
-            });
-      });
-    });
+      ret = vm_read(mach_task_self(), (vm_address_t)stringTable,
+                    region_size - ((vm_address_t)stringTable - string_address),
+                    &vm_string_memory, &vm_string_bytes_read);
+      if (ret != KERN_SUCCESS)
+        return;
+
+      nlist_buffer = (void *)vm_nlist_memory;
+      string_table = (char *)vm_string_memory;
+      nlist_count = nlistCount;
+    };
+
+    // Use the host shared cache to look up the image directly by UUID, avoiding
+    // the expensive iteration through all installed shared caches.
+    SymbolSharedCacheUse sc_mode = ModuleList::GetGlobalModuleListProperties()
+                                       .GetSharedCacheBinaryLoading();
+    found_image = HostInfo::WithSharedCacheImage(
+        image_uuid, process_shared_cache_uuid, sc_mode, [&](void *image) {
+          dyld_image_local_nlist_content_4Symbolication((dyld_image_t)image,
+                                                        nlist_extraction_block);
+        });
+
     if (nlist_buffer) {
       DataExtractor dsc_local_symbols_data(nlist_buffer,
                                            nlist_count * nlist_byte_size,



More information about the lldb-commits mailing list