diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h --- a/lldb/include/lldb/Core/Module.h +++ b/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 diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/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 { diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h --- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/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 &GetImages() const { + return m_images; + }; + +private: + llvm::StringMap 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, diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/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, diff --git a/lldb/include/lldb/Utility/DataBuffer.h b/lldb/include/lldb/Utility/DataBuffer.h --- a/lldb/include/lldb/Utility/DataBuffer.h +++ b/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) diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp --- a/lldb/source/Core/Module.cpp +++ b/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 diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/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(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)}; + }); +} diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/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; } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/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 §ion_data) override; + static bool ParseHeader(lldb_private::DataExtractor &data, lldb::offset_t *data_offset_ptr, llvm::MachO::mach_header &header); diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/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 // GetLLDBSharedCacheUUID() needs to call dlsym() #include #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 §ion_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"); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/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 + +#include #if defined(__APPLE__) #include @@ -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); diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/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); diff --git a/lldb/unittests/Host/HostInfoTest.cpp b/lldb/unittests/Host/HostInfoTest.cpp --- a/lldb/unittests/Host/HostInfoTest.cpp +++ b/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 diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/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 {