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 @@ -84,6 +84,8 @@ bool IsDynamicLoader() const; + bool IsSharedCacheBinary() const; + uint32_t GetAddressByteSize() const override; lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; 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 @@ -1127,6 +1127,10 @@ return m_header.filetype == MH_DYLINKER; } +bool ObjectFileMachO::IsSharedCacheBinary() const { + return m_header.flags & MH_DYLIB_IN_CACHE; +} + uint32_t ObjectFileMachO::GetAddressByteSize() const { return m_data.GetAddressByteSize(); } @@ -1377,7 +1381,7 @@ if (m_length == 0 || seg_cmd.filesize == 0) return; - if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { + if (IsSharedCacheBinary() && !IsInMemory()) { // In shared cache images, the load commands are relative to the // shared cache file, and not the specific image we are // examining. Let's fix this up so that it looks like a normal @@ -1675,29 +1679,38 @@ if (add_to_unified) context.UnifiedList.AddSection(segment_sp); } else if (unified_section_sp) { + // If this is a dSYM and the file addresses in the dSYM differ from the + // file addresses in the ObjectFile, we must use the file base address for + // the Section from the dSYM for the DWARF to resolve correctly. + // This only happens with binaries in the shared cache in practice; + // normally a mismatch like this would give a binary & dSYM that do not + // match UUIDs. When a binary is included in the shared cache, its + // segments are rearranged to optimize the shared cache, so its file + // addresses will differ from what the ObjectFile had originally, + // and what the dSYM has. if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { - // Check to see if the module was read from memory? - if (module_sp->GetObjectFile()->IsInMemory()) { - // We have a module that is in memory and needs to have its file - // address adjusted. We need to do this because when we load a file - // from memory, its addresses will be slid already, yet the addresses - // in the new symbol file will still be unslid. Since everything is - // stored as section offset, this shouldn't cause any problems. - - // Make sure we've parsed the symbol table from the ObjectFile before - // we go around changing its Sections. - module_sp->GetObjectFile()->GetSymtab(); - // eh_frame would present the same problems but we parse that on a per- - // function basis as-needed so it's more difficult to remove its use of - // the Sections. Realistically, the environments where this code path - // will be taken will not have eh_frame sections. - - unified_section_sp->SetFileAddress(load_cmd.vmaddr); - - // Notify the module that the section addresses have been changed once - // we're done so any file-address caches can be updated. - context.FileAddressesChanged = true; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); + if (log) { + log->Printf( + "Installing dSYM's %s segment file address over ObjectFile's " + "so symbol table/debug info resolves correctly for %s", + const_segname.AsCString(), + module_sp->GetFileSpec().GetFilename().AsCString()); } + + // Make sure we've parsed the symbol table from the ObjectFile before + // we go around changing its Sections. + module_sp->GetObjectFile()->GetSymtab(); + // eh_frame would present the same problems but we parse that on a per- + // function basis as-needed so it's more difficult to remove its use of + // the Sections. Realistically, the environments where this code path + // will be taken will not have eh_frame sections. + + unified_section_sp->SetFileAddress(load_cmd.vmaddr); + + // Notify the module that the section addresses have been changed once + // we're done so any file-address caches can be updated. + context.FileAddressesChanged = true; } m_sections_up->AddSection(unified_section_sp); } @@ -1726,7 +1739,7 @@ if (m_data.GetU32(&offset, §64.offset, num_u32s) == nullptr) break; - if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { + if (IsSharedCacheBinary() && !IsInMemory()) { sect64.offset = sect64.addr - m_text_address; } @@ -2352,7 +2365,7 @@ Process *process = process_sp.get(); uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete; - bool is_shared_cache_image = m_header.flags & MH_DYLIB_IN_CACHE; + bool is_shared_cache_image = IsSharedCacheBinary(); bool is_local_shared_cache_image = is_shared_cache_image && !IsInMemory(); SectionSP linkedit_section_sp( section_list->FindSectionByName(GetSegmentNameLINKEDIT())); @@ -2668,7 +2681,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 & MH_DYLIB_IN_CACHE) { + if (IsSharedCacheBinary()) { // Before we can start mapping the DSC, we need to make certain the // target process is actually using the cache we can find.