Author: Jonas Devlieghere Date: 2026-06-26T08:54:09-07:00 New Revision: 6a5fe4bf112d2d60f7e03a233d486ff502ce1b8c
URL: https://github.com/llvm/llvm-project/commit/6a5fe4bf112d2d60f7e03a233d486ff502ce1b8c DIFF: https://github.com/llvm/llvm-project/commit/6a5fe4bf112d2d60f7e03a233d486ff502ce1b8c.diff LOG: [lldb] Confine host shared cache reads to mapped segments (#205454) When reading shared cache libraries out of lldb's own memory (the default, eSymbolSharedCacheUseHostAndInferiorSharedCache), the dyld introspection path built a plain DataExtractor spanning an image's [minVmAddr, maxVmAddr). A shared cache image's segments may not be contiguous: other images' data and unmapped guard pages may lie between them. Take advantage of the VirtualDataExtractor with a per-segment lookup table instead, matching the map_shared_cache_binary_segments path, so reads are confined to mapped segments. Added: lldb/test/API/macosx/shared-cache-host-memory/Makefile lldb/test/API/macosx/shared-cache-host-memory/TestSharedCacheHostMemory.py lldb/test/API/macosx/shared-cache-host-memory/main.c Modified: lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm Removed: ################################################################################ diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index 75a584d90121a..69f8bbdce91f6 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -32,6 +32,8 @@ // C++ Includes #include <optional> #include <string> +#include <utility> +#include <vector> // C inclues #include <cstdlib> @@ -1023,6 +1025,10 @@ static DataExtractorSP map_shared_cache_binary_segments(void *image) { __block uint64_t maxVmAddr = 0; uuid_t uuidStore; __block uuid_t *uuid = &uuidStore; + // A shared cache image's segments can occupy non-adjacent regions of the + // cache. Keep track of the segment's start and end so we can build a + // VirtualDataExtractor that prevents reads between segments. + __block std::vector<std::pair<uint64_t, uint64_t>> segments; dyld_image_for_each_segment_info( image, @@ -1030,12 +1036,22 @@ static DataExtractorSP map_shared_cache_binary_segments(void *image) { minVmAddr = std::min(minVmAddr, vmAddr); maxVmAddr = std::max(maxVmAddr, vmAddr + vmSize); dyld_image_copy_uuid(image, uuid); + if (vmSize > 0) + segments.emplace_back(vmAddr, vmSize); }); assert(minVmAddr != UINT_MAX); assert(maxVmAddr != 0); lldb::DataBufferSP data_sp = std::make_shared<DataBufferUnowned>( (uint8_t *)minVmAddr, maxVmAddr - minVmAddr); - lldb::DataExtractorSP extractor_sp = std::make_shared<DataExtractor>(data_sp); + // Data is read in place from lldb's own shared cache, so each segment's + // virtual offset (image base at 0) equals its physical offset in the + // buffer. + VirtualDataExtractor::LookupTable table; + for (const std::pair<uint64_t, uint64_t> &seg : segments) + table.Append(VirtualDataExtractor::LookupTable::Entry( + seg.first - minVmAddr, seg.second, seg.first - minVmAddr)); + lldb::DataExtractorSP extractor_sp = + std::make_shared<VirtualDataExtractor>(data_sp, table); // Copy the filename into the const string pool to // ensure lifetime. ConstString installname(dyld_image_get_installname(image)); diff --git a/lldb/test/API/macosx/shared-cache-host-memory/Makefile b/lldb/test/API/macosx/shared-cache-host-memory/Makefile new file mode 100644 index 0000000000000..4774d1d781b3c --- /dev/null +++ b/lldb/test/API/macosx/shared-cache-host-memory/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +MAKE_DSYM := NO + +include Makefile.rules diff --git a/lldb/test/API/macosx/shared-cache-host-memory/TestSharedCacheHostMemory.py b/lldb/test/API/macosx/shared-cache-host-memory/TestSharedCacheHostMemory.py new file mode 100644 index 0000000000000..f45bf89b99444 --- /dev/null +++ b/lldb/test/API/macosx/shared-cache-host-memory/TestSharedCacheHostMemory.py @@ -0,0 +1,48 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class SharedCacheHostMemoryTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessDarwin + @skipIfRemote + def test_host_lldb_memory(self): + """Stop in a shared cache binary loaded from lldb's own memory and + backtrace through it.""" + self.build() + + self.runCmd("settings set symbols.shared-cache-binary-loading host-lldb-memory") + self.addTearDownHook( + lambda: self.runCmd("settings clear symbols.shared-cache-binary-loading") + ) + + target = self.createTestTarget() + + # Breaking on puts forces lldb to load and symbolicate the shared cache + # binary it lives in. The breakpoint resolves once that library is + # loaded as the process launches. + breakpoint = target.BreakpointCreateByName("puts") + + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + self.assertGreater( + breakpoint.GetNumLocations(), + 0, + "puts breakpoint should resolve in the shared cache binary", + ) + + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertIsNotNone(thread, "Expected to stop at the puts breakpoint") + + # We should be able to walk the stack out of the shared cache binary + # and back to main without crashing. + self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "puts") + self.assertGreater(thread.GetNumFrames(), 1) + frame_names = [ + thread.GetFrameAtIndex(i).GetFunctionName() + for i in range(thread.GetNumFrames()) + ] + self.assertIn("main", frame_names) diff --git a/lldb/test/API/macosx/shared-cache-host-memory/main.c b/lldb/test/API/macosx/shared-cache-host-memory/main.c new file mode 100644 index 0000000000000..9d2a89dc43140 --- /dev/null +++ b/lldb/test/API/macosx/shared-cache-host-memory/main.c @@ -0,0 +1,4 @@ +#include <stdio.h> +int main() { + puts("HI"); // break here +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
