[Lldb-commits] [lldb] [lldb] Add a new way of loading files from a shared cache (PR #179881)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Thu Feb 5 18:22:59 PST 2026
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/179881
>From 35ad58fbdac164ade024d13bb9b61bc8a8853564 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 5 Feb 2026 00:13:35 -0800
Subject: [PATCH 1/8] [lldb] Add a new way of loading files from a shared cache
Taking advantage of a few new SPI in macOS 26.4 libdyld, it is
possible for lldb to load binaries out of a shared cache binary
blob, instead of needing discrete files on disk. lldb has had one
special case where it has done this for years -- if the debugee
process and lldb itself are using the same shared cache, it could
create ObjectFiles based on its own memory contents. This new
method requires only the shared cache on disk, not depending on it
being mapped into lldb's address space already.
In HostInfoMacOSX.mm, we create an array of binaries in lldb's
shared cache, by one of two methods depending on the availability
of SPI/SDKs. This PR adds a new third method for loading lldb's
shared cache off disk as a proof of concept. It will prefer this
new method when the needed SPI are available at runtime. There is
also a user setting to disable this new method in case we uncover
a problem as it is deployed.
I did change the internal store of the shared cache files from a
single array, to being organized by shared cache UUIDs, so we can
have multiple shared caches indexed in the future.
In HostInfoBase.h's SharedCacheImageInfo class, you can now create
an ImageInfo with a DataExtractorSP or a void* baton. I added
GetUUID and GetExtractor methods, and the latter will use the libdyld
SPI to map the segments for a specific binary into lldb's memory
and return a DataExtractorSP.
The setting is currently called symbols.shared-cache-segment-mapping.
In DynamicLoaderDarwin::FindTargetModuleForImageInfo there was an
ordering mistake where we would always consult the HostInfoMacOSX.mm
shared cache provider, instead of checking lldb's own global module
cache first when looking for a binary, resulting in creating a new
Module repeatedly for shared cache binaries with the new method,
parsing the symbol table repeatedly. I fixed the ordering so we
look at existing Modules before we check the shared cache for one.
In ObjectFileMachOTest, it tests a TEXT and a DATA symbol, checking
that the contents of the function/data object match the bytes we
got from the shared cache. The test was using a DATA_DIRTY symbol,
which was fine when using lldb's own shared cache memory, but when
we worked on the shared cache binary on-disk directly, we were
seeing different values for the bytes because of relocations in
there. I changed this to a constant DATA symbol.
rdar://148939795
---
lldb/include/lldb/Core/ModuleList.h | 2 +
lldb/include/lldb/Host/HostInfoBase.h | 35 ++-
lldb/source/Core/CoreProperties.td | 4 +
lldb/source/Core/ModuleList.cpp | 10 +
lldb/source/Host/macosx/objcxx/CMakeLists.txt | 1 +
.../Host/macosx/objcxx/HostInfoMacOSX.mm | 242 ++++++++++++++++--
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 21 +-
.../Platform/MacOSX/PlatformDarwinDevice.cpp | 10 +-
.../SymbolLocatorDebugSymbols.cpp | 10 +-
.../unittests/ObjectFile/MachO/CMakeLists.txt | 1 +
.../ObjectFile/MachO/TestObjectFileMachO.cpp | 19 +-
11 files changed, 309 insertions(+), 46 deletions(-)
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index dd17f7558e2b4..6cccbc806294d 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -81,6 +81,8 @@ class ModuleListProperties : public Properties {
bool SetClangModulesCachePath(const FileSpec &path);
bool GetEnableExternalLookup() const;
bool SetEnableExternalLookup(bool new_value);
+ bool GetSharedCacheSegmentLoads() const;
+ bool SetSharedCacheSegmentLoads(bool new_value);
bool GetEnableLLDBIndexCache() const;
bool SetEnableLLDBIndexCache(bool new_value);
uint64_t GetLLDBIndexCacheMaxByteSize();
diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h
index 670fee19fca3d..895808716844b 100644
--- a/lldb/include/lldb/Host/HostInfoBase.h
+++ b/lldb/include/lldb/Host/HostInfoBase.h
@@ -10,6 +10,7 @@
#define LLDB_HOST_HOSTINFOBASE_H
#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/UUID.h"
#include "lldb/Utility/UserIDResolver.h"
@@ -28,8 +29,38 @@ namespace lldb_private {
class FileSpec;
struct SharedCacheImageInfo {
- UUID uuid;
- lldb::DataExtractorSP extractor_sp;
+ SharedCacheImageInfo()
+ : m_uuid(), m_extractor_sp(), m_create_data_extractor(nullptr),
+ m_image_baton(nullptr) {}
+ SharedCacheImageInfo(UUID uuid, lldb::DataExtractorSP extractor_sp)
+ : m_uuid(uuid), m_extractor_sp(extractor_sp),
+ m_create_data_extractor(nullptr), m_image_baton(nullptr) {}
+ SharedCacheImageInfo(
+ UUID uuid, lldb::DataExtractorSP (*create_data_extractor)(void *image),
+ void *image_baton)
+ : m_uuid(uuid), m_extractor_sp(),
+ m_create_data_extractor(create_data_extractor),
+ m_image_baton(image_baton) {}
+
+ lldb::DataExtractorSP GetExtractor() {
+ if (!m_extractor_sp && m_image_baton)
+ m_extractor_sp = m_create_data_extractor(m_image_baton);
+ return m_extractor_sp;
+ }
+ UUID &GetUUID() { return m_uuid; }
+ void *GetImageBaton();
+ void SetExtractor(lldb::DataExtractorSP extractor_sp) {
+ m_extractor_sp = extractor_sp;
+ }
+ void SetImageBaton(void *image_baton) { m_image_baton = image_baton; }
+ void SetDataExtractorCreateFunction(
+ lldb::DataExtractorSP (*create_data_extractor)(void *image));
+
+private:
+ UUID m_uuid;
+ lldb::DataExtractorSP m_extractor_sp;
+ lldb::DataExtractorSP (*m_create_data_extractor)(void *image);
+ void *m_image_baton;
};
namespace {
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index 2bc62464f91bd..a9cc88f5483da 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -14,6 +14,10 @@ let Definition = "modulelist" in {
DefaultEnumValue<"eSymbolDownloadOff">,
EnumValues<"OptionEnumValues(g_auto_download_enum_values)">,
Desc<"On macOS, automatically download symbols with dsymForUUID (or an equivalent script/binary) for relevant images in the debug session.">;
+ def SharedCacheSegmentLoads: Property<"shared-cache-segment-mapping", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"On macOS, a feature to load the binaries from a shared cache blob directly, instead of requiring discrete binaries or using lldb's own shared cache memory.">;
def ClangModulesCachePath: Property<"clang-modules-cache-path", "FileSpec">,
Global,
DefaultStringValue<"">,
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 613e469dc6318..99da887dfaa92 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -118,6 +118,16 @@ SymbolDownload ModuleListProperties::GetSymbolAutoDownload() const {
g_modulelist_properties[idx].default_uint_value));
}
+bool ModuleListProperties::GetSharedCacheSegmentLoads() const {
+ const uint32_t idx = ePropertySharedCacheSegmentLoads;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_modulelist_properties[idx].default_uint_value != 0);
+}
+
+bool ModuleListProperties::SetSharedCacheSegmentLoads(bool new_value) {
+ return SetPropertyAtIndex(ePropertySharedCacheSegmentLoads, new_value);
+}
+
FileSpec ModuleListProperties::GetClangModulesCachePath() const {
const uint32_t idx = ePropertyClangModulesCachePath;
return GetPropertyAtIndexAs<FileSpec>(idx, {});
diff --git a/lldb/source/Host/macosx/objcxx/CMakeLists.txt b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
index 1d7573335b8ec..a47a1e5086eee 100644
--- a/lldb/source/Host/macosx/objcxx/CMakeLists.txt
+++ b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
@@ -14,6 +14,7 @@ add_lldb_library(lldbHostMacOSXObjCXX NO_PLUGIN_DEPENDENCIES
Support
TargetParser
LINK_LIBS
+ lldbCore
lldbUtility
${EXTRA_LIBS}
)
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 8effe4cc169e0..dde49f498a470 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/macosx/HostInfoMacOSX.h"
+#include "lldb/Core/ModuleList.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -16,6 +17,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Timer.h"
+#include "lldb/Utility/VirtualDataExtractor.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
@@ -30,6 +32,7 @@
// C inclues
#include <cstdlib>
+#include <dlfcn.h>
#include <sys/sysctl.h>
#include <sys/syslimits.h>
#include <sys/types.h>
@@ -65,6 +68,7 @@
#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
+using namespace lldb;
using namespace lldb_private;
std::optional<std::string> HostInfoMacOSX::GetOSBuildString() {
@@ -649,30 +653,228 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
dyld_shared_cache_dylib_text_info;
}
-extern "C" int dyld_shared_cache_iterate_text(
+// All available on at least macOS 12
+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);
+uint8_t *_dyld_get_shared_cache_range(size_t *length);
+bool _dyld_get_shared_cache_uuid(uuid_t uuid);
+bool dyld_image_for_each_segment_info(void *image,
+ void (^)(const char *segmentName,
+ uint64_t vmAddr, uint64_t vmSize,
+ int perm));
+const char *dyld_shared_cache_file_path(void);
+bool dyld_shared_cache_for_file(const char *filePath,
+ void (^block)(void *cache));
+void dyld_shared_cache_copy_uuid(void *cache, uuid_t *uuid);
+uint64_t dyld_shared_cache_get_base_address(void *cache);
+void dyld_shared_cache_for_each_image(void *cache, void (^block)(void *image));
+bool dyld_image_copy_uuid(void *cache, uuid_t *uuid);
+const char *dyld_image_get_installname(void *image);
+const char *dyld_image_get_file_path(void *image);
+}
namespace {
class SharedCacheInfo {
public:
- const UUID &GetUUID() const { return m_uuid; }
- const llvm::StringMap<SharedCacheImageInfo> &GetImages() const {
- return m_images;
+ llvm::StringMap<SharedCacheImageInfo> &GetImages() {
+ return m_caches[m_host_uuid];
}
SharedCacheInfo();
private:
bool CreateSharedCacheInfoWithInstrospectionSPIs();
+ void CreateSharedCacheInfoLLDBsVirtualMemory();
+ bool CreateHostSharedCacheImageList();
+
+ // Given the UUID and filepath to a shared cache on the local debug host
+ // system, open it and add all of the binary images to m_caches.
+ bool CreateSharedCacheImageList(UUID uuid, std::string filepath);
- llvm::StringMap<SharedCacheImageInfo> m_images;
- UUID m_uuid;
+ std::map<UUID, llvm::StringMap<SharedCacheImageInfo>> m_caches;
+ UUID m_host_uuid;
+
+ // macOS 26.4 and newer
+ void (*m_dyld_image_retain_4HWTrace)(void *image);
+ void (*m_dyld_image_release_4HWTrace)(void *image);
+ dispatch_data_t (*m_dyld_image_segment_data_4HWTrace)(
+ void *image, const char *segmentName);
};
+
+} // namespace
+
+SharedCacheInfo::SharedCacheInfo() {
+ // macOS 26.4 and newer
+ m_dyld_image_retain_4HWTrace =
+ (void (*)(void *))dlsym(RTLD_DEFAULT, "dyld_image_retain_4HWTrace");
+ m_dyld_image_release_4HWTrace =
+ (void (*)(void *))dlsym(RTLD_DEFAULT, "dyld_image_release_4HWTrace");
+ m_dyld_image_segment_data_4HWTrace =
+ (dispatch_data_t(*)(void *image, const char *segmentName))dlsym(
+ RTLD_DEFAULT, "dyld_image_segment_data_4HWTrace");
+
+ uuid_t dsc_uuid;
+ _dyld_get_shared_cache_uuid(dsc_uuid);
+ m_host_uuid = UUID(dsc_uuid);
+
+ if (ModuleList::GetGlobalModuleListProperties()
+ .GetSharedCacheSegmentLoads() &&
+ CreateHostSharedCacheImageList())
+ return;
+
+ if (CreateSharedCacheInfoWithInstrospectionSPIs())
+ return;
+
+ CreateSharedCacheInfoLLDBsVirtualMemory();
}
+struct segment {
+ std::string name;
+ uint64_t vmaddr;
+ size_t vmsize;
+
+ // Mapped into lldb's own address space via libdispatch:
+ const void *data;
+ size_t size;
+};
+
+static DataExtractorSP map_shared_cache_binary_segments(void *image) {
+ // dyld_image_segment_data_4HWTrace can't be called on
+ // multiple threads simultaneously.
+ static std::mutex g_mutex;
+ std::lock_guard<std::mutex> guard(g_mutex);
+
+ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
+ void *image, const char *segmentName);
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, [&]() {
+ g_dyld_image_segment_data_4HWTrace =
+ (dispatch_data_t(*)(void *, const char *))dlsym(
+ RTLD_DEFAULT, "dyld_image_segment_data_4HWTrace");
+ });
+ if (!g_dyld_image_segment_data_4HWTrace)
+ return {};
+
+ __block std::vector<segment> segments;
+ __block void *image_copy = image;
+ dyld_image_for_each_segment_info(
+ image,
+ ^(const char *segmentName, uint64_t vmAddr, uint64_t vmSize, int perm) {
+ segment seg;
+ seg.name = segmentName;
+ seg.vmaddr = vmAddr;
+ seg.vmsize = vmSize;
+
+ dispatch_data_t data_from_libdyld =
+ g_dyld_image_segment_data_4HWTrace(image_copy, segmentName);
+ (void)dispatch_data_create_map(data_from_libdyld, &seg.data, &seg.size);
+
+ segments.push_back(seg);
+ });
+
+ if (!segments.size())
+ return {};
+
+ Log *log = GetLog(LLDBLog::Modules);
+ for (segment seg : segments) {
+ if (log && log->GetVerbose())
+ LLDB_LOGF(
+ log,
+ "image %p %s vmaddr 0x%llx vmsize 0x%zx mapped to lldb vm addr %p",
+ image, seg.name.c_str(), seg.vmaddr, seg.vmsize, seg.data);
+ }
+
+ // Calculate the virtual address range in lldb's
+ // address space (lowest memory address to highest) so
+ // we can contain the entire range in an unowned data buffer.
+ uint64_t min_lldb_vm_addr = UINT64_MAX;
+ uint64_t max_lldb_vm_addr = 0;
+ // Calculate the minimum shared cache address seen; we want the first
+ // segment, __TEXT, at "vm offset" 0 in our DataExtractor.
+ // A __DATA segment which is at the __TEXT vm addr + 0x1000 needs to be
+ // listed as offset 0x1000.
+ uint64_t min_file_vm_addr = UINT64_MAX;
+ for (segment seg : segments) {
+ min_lldb_vm_addr = std::min(min_lldb_vm_addr, (uint64_t)seg.data);
+ max_lldb_vm_addr =
+ std::max(max_lldb_vm_addr, (uint64_t)seg.data + seg.vmsize);
+ min_file_vm_addr = std::min(min_file_vm_addr, (uint64_t)seg.vmaddr);
+ }
+ DataBufferSP data_sp = std::make_shared<DataBufferUnowned>(
+ (uint8_t *)min_lldb_vm_addr, max_lldb_vm_addr - min_lldb_vm_addr);
+ VirtualDataExtractor::LookupTable remap_table;
+ for (segment seg : segments)
+ remap_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ (uint64_t)seg.vmaddr - min_file_vm_addr, (uint64_t)seg.vmsize,
+ (uint64_t)seg.data - (uint64_t)min_lldb_vm_addr));
+
+ return std::make_shared<VirtualDataExtractor>(data_sp, remap_table);
+}
+
+// Scan the binaries in the specified shared cache filepath
+// if the UUID matches, using the macOS 26.4 libdyld SPI,
+// create a new entry in m_caches.
+bool SharedCacheInfo::CreateSharedCacheImageList(UUID uuid,
+ std::string filepath) {
+ if (!m_dyld_image_retain_4HWTrace || !m_dyld_image_release_4HWTrace ||
+ !m_dyld_image_segment_data_4HWTrace)
+ return false;
+
+ __block bool return_failed = false;
+ dyld_shared_cache_for_file(filepath.c_str(), ^(void *cache) {
+ uuid_t sc_uuid;
+ dyld_shared_cache_copy_uuid(cache, &sc_uuid);
+ UUID this_cache(sc_uuid, sizeof(uuid_t));
+ if (this_cache != uuid) {
+ return_failed = true;
+ return;
+ }
+
+ dyld_shared_cache_for_each_image(cache, ^(void *image) {
+ uuid_t uuid_tmp;
+ if (!dyld_image_copy_uuid(image, &uuid_tmp))
+ return;
+ UUID image_uuid(uuid_tmp, sizeof(uuid_t));
+
+ Log *log = GetLog(LLDBLog::Modules);
+ if (log && log->GetVerbose())
+ LLDB_LOGF(log, "sc file %s image %p", dyld_image_get_installname(image),
+ image);
+
+ m_dyld_image_retain_4HWTrace(image);
+ m_caches[m_host_uuid][dyld_image_get_installname(image)] =
+ SharedCacheImageInfo(image_uuid, map_shared_cache_binary_segments,
+ image);
+ });
+ });
+ if (return_failed)
+ return false;
+
+ return true;
+}
+
+// Get the filename and uuid of lldb's own shared cache, scan
+// the files in it using the macOS 26.4 and newer libdyld SPI.
+bool SharedCacheInfo::CreateHostSharedCacheImageList() {
+ std::string host_shared_cache_file = dyld_shared_cache_file_path();
+ __block UUID host_sc_uuid;
+ dyld_shared_cache_for_file(host_shared_cache_file.c_str(), ^(void *cache) {
+ uuid_t sc_uuid;
+ dyld_shared_cache_copy_uuid(cache, &sc_uuid);
+ host_sc_uuid = UUID{sc_uuid, sizeof(uuid_t)};
+ });
+
+ if (host_sc_uuid.IsValid())
+ return CreateSharedCacheImageList(host_sc_uuid, host_shared_cache_file);
+
+ return false;
+}
+
+// Index the binaries in lldb's own shared cache memory, using
+// libdyld SPI present on macOS 12 and newer, when building against
+// the internal SDK, and add an entry to the m_caches map.
bool SharedCacheInfo::CreateSharedCacheInfoWithInstrospectionSPIs() {
#if defined(SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS)
dyld_process_t dyld_process = dyld_process_create_for_current_task();
@@ -713,33 +915,31 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
lldb::DataBufferSP data_sp = std::make_shared<DataBufferUnowned>(
(uint8_t *)minVmAddr, maxVmAddr - minVmAddr);
lldb::DataExtractorSP extractor_sp = std::make_shared<DataExtractor>(data_sp);
- m_images[dyld_image_get_installname(image)] = SharedCacheImageInfo{
- UUID(uuid, 16), extractor_sp};
+ m_caches[m_host_uuid][dyld_image_get_installname(image)] =
+ SharedCacheImageInfo{UUID(uuid, 16), extractor_sp};
});
return true;
#endif
return false;
}
-SharedCacheInfo::SharedCacheInfo() {
- if (CreateSharedCacheInfoWithInstrospectionSPIs())
- return;
-
+// Index the binaries in lldb's own shared cache memory using
+// libdyld SPI available on macOS 10.13 or newer, add an entry to
+// m_caches.
+void SharedCacheInfo::CreateSharedCacheInfoLLDBsVirtualMemory() {
size_t shared_cache_size;
uint8_t *shared_cache_start =
_dyld_get_shared_cache_range(&shared_cache_size);
- uuid_t dsc_uuid;
- _dyld_get_shared_cache_uuid(dsc_uuid);
- m_uuid = UUID(dsc_uuid);
dyld_shared_cache_iterate_text(
- dsc_uuid, ^(const dyld_shared_cache_dylib_text_info *info) {
- lldb::DataBufferSP data_sp = std::make_shared<DataBufferUnowned>(
+ m_host_uuid.GetBytes().data(),
+ ^(const dyld_shared_cache_dylib_text_info *info) {
+ lldb::DataBufferSP buffer_sp = std::make_shared<DataBufferUnowned>(
shared_cache_start + info->textSegmentOffset,
shared_cache_size - info->textSegmentOffset);
lldb::DataExtractorSP extractor_sp =
- std::make_shared<DataExtractor>(data_sp);
- m_images[info->path] =
+ std::make_shared<DataExtractor>(buffer_sp);
+ m_caches[m_host_uuid][info->path] =
SharedCacheImageInfo{UUID(info->dylibUuid, 16), extractor_sp};
});
}
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index e7128ca875b94..a51854df5280b 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -124,7 +124,12 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
if (module_sp || !can_create)
return module_sp;
- if (HostInfo::GetArchitecture().IsCompatibleMatch(target.GetArchitecture())) {
+ // See if we have this binary in the Target or the global Module
+ // cache already.
+ module_sp = target.GetOrCreateModule(module_spec, false /* notify */);
+
+ if (!module_sp &&
+ HostInfo::GetArchitecture().IsCompatibleMatch(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
@@ -135,18 +140,16 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
// If we found it and it has the correct UUID, let's proceed with
// creating a module from the memory contents.
- if (image_info.uuid &&
- (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
- ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
- image_info.extractor_sp);
+ if (image_info.GetUUID() &&
+ (!module_spec.GetUUID() ||
+ module_spec.GetUUID() == image_info.GetUUID())) {
+ ModuleSpec shared_cache_spec(module_spec.GetFileSpec(),
+ image_info.GetUUID(),
+ image_info.GetExtractor());
module_sp =
target.GetOrCreateModule(shared_cache_spec, false /* notify */);
}
}
- // 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);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
index a6dc6759c16df..c1a04e801107e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
@@ -323,10 +323,12 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
// If we found it and it has the correct UUID, let's proceed with
// creating a module from the memory contents.
- if (image_info.uuid &&
- (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
- ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
- image_info.extractor_sp);
+ if (image_info.GetUUID() &&
+ (!module_spec.GetUUID() ||
+ module_spec.GetUUID() == image_info.GetUUID())) {
+ ModuleSpec shared_cache_spec(module_spec.GetFileSpec(),
+ image_info.GetUUID(),
+ image_info.GetExtractor());
err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
old_modules, did_create_ptr);
if (module_sp) {
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
index 1e51dda15d6e9..f4b572c9e88ac 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
@@ -208,8 +208,9 @@ std::optional<ModuleSpec> SymbolLocatorDebugSymbols::LocateExecutableObjectFile(
// If we found it and it has the correct UUID, let's proceed with
// creating a module from the memory contents.
- if (image_info.uuid && (!module_spec.GetUUID() ||
- module_spec.GetUUID() == image_info.uuid)) {
+ if (image_info.GetUUID() &&
+ (!module_spec.GetUUID() ||
+ module_spec.GetUUID() == image_info.GetUUID())) {
success = true;
return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
LLDB_LOGF(log,
@@ -650,8 +651,9 @@ static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
// If we found it and it has the correct UUID, let's proceed with
// creating a module from the memory contents.
- if (image_info.uuid && (!module_spec.GetUUID() ||
- module_spec.GetUUID() == image_info.uuid)) {
+ if (image_info.GetUUID() &&
+ (!module_spec.GetUUID() ||
+ module_spec.GetUUID() == image_info.GetUUID())) {
success = true;
return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
LLDB_LOGF(log,
diff --git a/lldb/unittests/ObjectFile/MachO/CMakeLists.txt b/lldb/unittests/ObjectFile/MachO/CMakeLists.txt
index b6c4225114a36..1b071ff1bd738 100644
--- a/lldb/unittests/ObjectFile/MachO/CMakeLists.txt
+++ b/lldb/unittests/ObjectFile/MachO/CMakeLists.txt
@@ -6,5 +6,6 @@ add_lldb_unittest(ObjectFileMachOTests
lldbPluginSymbolFileSymtab
lldbCore
lldbUtilityHelpers
+ lldbPluginPlatformMacOSX
LLVMTestingSupport
)
diff --git a/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp b/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp
index 3adb642c1108e..5b516fc2582f5 100644
--- a/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp
+++ b/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp
@@ -6,12 +6,14 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Host/HostInfo.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/lldb-defines.h"
#include "gtest/gtest.h"
@@ -19,6 +21,7 @@
#include <dlfcn.h>
#endif
+using namespace lldb;
using namespace lldb_private;
using namespace llvm;
@@ -30,12 +33,16 @@ class ObjectFileMachOTest : public ::testing::Test {
#if defined(__APPLE__)
TEST_F(ObjectFileMachOTest, ModuleFromSharedCacheInfo) {
+ ArchSpec arch("arm64-apple-macosx-");
+
+ Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
+
SharedCacheImageInfo image_info =
HostInfo::GetSharedCacheImageInfo("/usr/lib/libobjc.A.dylib");
- EXPECT_TRUE(image_info.uuid);
- EXPECT_TRUE(image_info.extractor_sp);
+ EXPECT_TRUE(image_info.GetUUID());
+ EXPECT_TRUE(image_info.GetExtractor());
- ModuleSpec spec(FileSpec(), UUID(), image_info.extractor_sp);
+ ModuleSpec spec(FileSpec(), UUID(), image_info.GetExtractor());
lldb::ModuleSP module = std::make_shared<Module>(spec);
ObjectFile *OF = module->GetObjectFile();
ASSERT_TRUE(llvm::isa<ObjectFileMachO>(OF));
@@ -74,13 +81,13 @@ TEST_F(ObjectFileMachOTest, ModuleFromSharedCacheInfo) {
// Read a symbol from the __TEXT segment...
check_symbol("objc_msgSend");
// ... and one from the __DATA segment
- check_symbol("OBJC_CLASS_$_NSObject");
+ check_symbol("OBJC_IVAR_$_NSObject.isa");
}
TEST_F(ObjectFileMachOTest, IndirectSymbolsInTheSharedCache) {
SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
"/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit");
- ModuleSpec spec(FileSpec(), UUID(), image_info.extractor_sp);
+ ModuleSpec spec(FileSpec(), UUID(), image_info.GetExtractor());
lldb::ModuleSP module = std::make_shared<Module>(spec);
ObjectFile *OF = module->GetObjectFile();
>From f7f0ef2b724482da51d82f4736188609c2046bd6 Mon Sep 17 00:00:00 2001
From: Jason Molenda <github-mail at molenda.com>
Date: Thu, 5 Feb 2026 16:14:28 -0800
Subject: [PATCH 2/8] Update
lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
.../Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 101a44e05b962..3f2459c760d36 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -126,7 +126,7 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
// See if we have this binary in the Target or the global Module
// cache already.
- module_sp = target.GetOrCreateModule(module_spec, false /* notify */);
+ module_sp = target.GetOrCreateModule(module_spec, /*notify=*/false );
if (!module_sp &&
HostInfo::GetArchitecture().IsCompatibleMatch(target.GetArchitecture())) {
>From 616bd00c398753369131ba3ef5e6f80f5cf6f8c9 Mon Sep 17 00:00:00 2001
From: Jason Molenda <github-mail at molenda.com>
Date: Thu, 5 Feb 2026 16:18:04 -0800
Subject: [PATCH 3/8] Update lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index dde49f498a470..ee77a1366abe0 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -863,7 +863,7 @@ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
dyld_shared_cache_for_file(host_shared_cache_file.c_str(), ^(void *cache) {
uuid_t sc_uuid;
dyld_shared_cache_copy_uuid(cache, &sc_uuid);
- host_sc_uuid = UUID{sc_uuid, sizeof(uuid_t)};
+ host_sc_uuid = UUID(sc_uuid, sizeof(uuid_t));
});
if (host_sc_uuid.IsValid())
>From 62f3f7a399b8c6199fb0a716f8a53bc84dbd1a10 Mon Sep 17 00:00:00 2001
From: Jason Molenda <github-mail at molenda.com>
Date: Thu, 5 Feb 2026 16:25:45 -0800
Subject: [PATCH 4/8] Update lldb/source/Core/CoreProperties.td
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
lldb/source/Core/CoreProperties.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index a9cc88f5483da..ee70b5a0953e0 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -17,7 +17,7 @@ let Definition = "modulelist" in {
def SharedCacheSegmentLoads: Property<"shared-cache-segment-mapping", "Boolean">,
Global,
DefaultTrue,
- Desc<"On macOS, a feature to load the binaries from a shared cache blob directly, instead of requiring discrete binaries or using lldb's own shared cache memory.">;
+ Desc<"On macOS, load the binaries from a shared cache blob directly, instead of loading them from lldb's own in-process shared cache.">;
def ClangModulesCachePath: Property<"clang-modules-cache-path", "FileSpec">,
Global,
DefaultStringValue<"">,
>From ab92493a266f997ed1a3866ee9edf70eac740d2c Mon Sep 17 00:00:00 2001
From: Jason Molenda <github-mail at molenda.com>
Date: Thu, 5 Feb 2026 16:30:27 -0800
Subject: [PATCH 5/8] Update lldb/include/lldb/Host/HostInfoBase.h
Co-authored-by: Alex Langford <nirvashtzero at gmail.com>
---
lldb/include/lldb/Host/HostInfoBase.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h
index 895808716844b..149810ff53924 100644
--- a/lldb/include/lldb/Host/HostInfoBase.h
+++ b/lldb/include/lldb/Host/HostInfoBase.h
@@ -47,7 +47,7 @@ struct SharedCacheImageInfo {
m_extractor_sp = m_create_data_extractor(m_image_baton);
return m_extractor_sp;
}
- UUID &GetUUID() { return m_uuid; }
+ const UUID &GetUUID() const { return m_uuid; }
void *GetImageBaton();
void SetExtractor(lldb::DataExtractorSP extractor_sp) {
m_extractor_sp = extractor_sp;
>From ab672155241eff5a3b61fd6dd271be4c8eb30489 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 5 Feb 2026 16:32:06 -0800
Subject: [PATCH 6/8] rename setting to symbols.shared-cache-binary-loading
which I think is a little more descriptive.
---
lldb/include/lldb/Core/ModuleList.h | 4 ++--
lldb/source/Core/CoreProperties.td | 2 +-
lldb/source/Core/ModuleList.cpp | 8 ++++----
lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm | 2 +-
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index 6cccbc806294d..6f7224fdeb0b3 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -81,8 +81,8 @@ class ModuleListProperties : public Properties {
bool SetClangModulesCachePath(const FileSpec &path);
bool GetEnableExternalLookup() const;
bool SetEnableExternalLookup(bool new_value);
- bool GetSharedCacheSegmentLoads() const;
- bool SetSharedCacheSegmentLoads(bool new_value);
+ bool GetSharedCacheBinaryLoading() const;
+ bool SetSharedCacheBinaryLoading(bool new_value);
bool GetEnableLLDBIndexCache() const;
bool SetEnableLLDBIndexCache(bool new_value);
uint64_t GetLLDBIndexCacheMaxByteSize();
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index ee70b5a0953e0..63efcae3d15d3 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -14,7 +14,7 @@ let Definition = "modulelist" in {
DefaultEnumValue<"eSymbolDownloadOff">,
EnumValues<"OptionEnumValues(g_auto_download_enum_values)">,
Desc<"On macOS, automatically download symbols with dsymForUUID (or an equivalent script/binary) for relevant images in the debug session.">;
- def SharedCacheSegmentLoads: Property<"shared-cache-segment-mapping", "Boolean">,
+ def SharedCacheBinaryLoading: Property<"shared-cache-binary-loading", "Boolean">,
Global,
DefaultTrue,
Desc<"On macOS, load the binaries from a shared cache blob directly, instead of loading them from lldb's own in-process shared cache.">;
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 99da887dfaa92..fb4a80740200d 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -118,14 +118,14 @@ SymbolDownload ModuleListProperties::GetSymbolAutoDownload() const {
g_modulelist_properties[idx].default_uint_value));
}
-bool ModuleListProperties::GetSharedCacheSegmentLoads() const {
- const uint32_t idx = ePropertySharedCacheSegmentLoads;
+bool ModuleListProperties::GetSharedCacheBinaryLoading() const {
+ const uint32_t idx = ePropertySharedCacheBinaryLoading;
return GetPropertyAtIndexAs<bool>(
idx, g_modulelist_properties[idx].default_uint_value != 0);
}
-bool ModuleListProperties::SetSharedCacheSegmentLoads(bool new_value) {
- return SetPropertyAtIndex(ePropertySharedCacheSegmentLoads, new_value);
+bool ModuleListProperties::SetSharedCacheBinaryLoading(bool new_value) {
+ return SetPropertyAtIndex(ePropertySharedCacheBinaryLoading, new_value);
}
FileSpec ModuleListProperties::GetClangModulesCachePath() const {
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index ee77a1366abe0..6ea3d4303b68b 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -720,7 +720,7 @@ bool dyld_shared_cache_for_file(const char *filePath,
m_host_uuid = UUID(dsc_uuid);
if (ModuleList::GetGlobalModuleListProperties()
- .GetSharedCacheSegmentLoads() &&
+ .GetSharedCacheBinaryLoading() &&
CreateHostSharedCacheImageList())
return;
>From 18b8ceba5336c8694b83973ab7b89f235b7f6c3d Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 5 Feb 2026 16:37:14 -0800
Subject: [PATCH 7/8] Avoid copying the segment objects when iterating over
them. Move the verbose logging detection out of the loop for clarity.
---
lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 6ea3d4303b68b..114b91fc0b4d3 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -778,8 +778,9 @@ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
return {};
Log *log = GetLog(LLDBLog::Modules);
- for (segment seg : segments) {
- if (log && log->GetVerbose())
+ bool log_verbosely = log && log->GetVerbose();
+ for (const segment &seg : segments) {
+ if (log_verbosely)
LLDB_LOGF(
log,
"image %p %s vmaddr 0x%llx vmsize 0x%zx mapped to lldb vm addr %p",
@@ -796,7 +797,7 @@ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
// A __DATA segment which is at the __TEXT vm addr + 0x1000 needs to be
// listed as offset 0x1000.
uint64_t min_file_vm_addr = UINT64_MAX;
- for (segment seg : segments) {
+ for (const segment &seg : segments) {
min_lldb_vm_addr = std::min(min_lldb_vm_addr, (uint64_t)seg.data);
max_lldb_vm_addr =
std::max(max_lldb_vm_addr, (uint64_t)seg.data + seg.vmsize);
@@ -805,7 +806,7 @@ static dispatch_data_t (*g_dyld_image_segment_data_4HWTrace)(
DataBufferSP data_sp = std::make_shared<DataBufferUnowned>(
(uint8_t *)min_lldb_vm_addr, max_lldb_vm_addr - min_lldb_vm_addr);
VirtualDataExtractor::LookupTable remap_table;
- for (segment seg : segments)
+ for (const segment &seg : segments)
remap_table.Append(VirtualDataExtractor::LookupTable::Entry(
(uint64_t)seg.vmaddr - min_file_vm_addr, (uint64_t)seg.vmsize,
(uint64_t)seg.data - (uint64_t)min_lldb_vm_addr));
>From c67ae32a34e845dfb5664b6d79a9d62ba47ec506 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 5 Feb 2026 16:42:29 -0800
Subject: [PATCH 8/8] ws fix
---
.../Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 3f2459c760d36..00cae1c6cea1e 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -126,7 +126,7 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
// See if we have this binary in the Target or the global Module
// cache already.
- module_sp = target.GetOrCreateModule(module_spec, /*notify=*/false );
+ module_sp = target.GetOrCreateModule(module_spec, /*notify=*/false);
if (!module_sp &&
HostInfo::GetArchitecture().IsCompatibleMatch(target.GetArchitecture())) {
More information about the lldb-commits
mailing list