diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt @@ -17,6 +17,7 @@ lldbSymbol lldbTarget lldbUtility + lldbPluginObjectFileMachO ) add_dependencies(lldbPluginDynamicLoaderDarwinKernel diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" @@ -713,6 +714,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( Process *process) { + Log *log = GetLog(LLDBLog::DynamicLoader); if (IsLoaded()) return true; @@ -810,6 +812,28 @@ } } + if (m_module_sp && m_uuid.IsValid() && m_module_sp->GetUUID() == m_uuid) { + ObjectFileMachO *ondisk_objfile_macho = + llvm::dyn_cast_or_null( + m_module_sp ? m_module_sp->GetObjectFile() : nullptr); + if (ondisk_objfile_macho) { + if (!IsKernel() && !ondisk_objfile_macho->IsKext()) { + // We have a non-kext, non-kernel binary. If we already have this + // loaded in the Target with load addresses, don't re-load it again. + ModuleSP existing_module_sp = target.GetImages().FindModule(m_uuid); + if (existing_module_sp && + existing_module_sp->IsLoadedInTarget(&target)) { + LLDB_LOGF(log, + "'%s' with UUID %s is not a kext or kernel, and is " + "already registered in target, not loading.", + m_name.c_str(), m_uuid.GetAsString().c_str()); + // It's already loaded, return true. + return true; + } + } + } + } + // If we managed to find a module, append it to the target's list of // images. If we also have a memory module, require that they have matching // UUIDs @@ -837,6 +861,34 @@ // it. const bool ignore_linkedit = !IsKernel(); + // Normally a kext will have its segment load commands + // (LC_SEGMENT vmaddrs) corrected in memory to have their + // actual segment addresses. + // Userland proceses have their libraries updated the same way + // by dyld. The Mach-O load commands in memory are the canonical + // addresses. + // + // If the kernel gives us a binary where the in-memory segment + // vmaddr is incorrect, then this binary was put in memory without + // updating its Mach-O load commands. We should assume a static + // slide value will be applied to every segment; we don't have the + // correct addresses for each individual segment. + addr_t fixed_slide = LLDB_INVALID_ADDRESS; + if (ObjectFileMachO *memory_objfile_macho = + llvm::dyn_cast(memory_object_file)) { + if (Section *header_sect = + memory_objfile_macho->GetMachHeaderSection()) { + if (header_sect->GetFileAddress() != m_load_address) { + fixed_slide = m_load_address - header_sect->GetFileAddress(); + LLDB_LOGF( + log, + "kext %s in-memory LC_SEGMENT vmaddr is not correct, using a " + "fixed slide of 0x%" PRIx64, + m_name.c_str(), fixed_slide); + } + } + } + SectionList *ondisk_section_list = ondisk_object_file->GetSectionList(); SectionList *memory_section_list = memory_object_file->GetSectionList(); if (memory_section_list && ondisk_section_list) { @@ -865,14 +917,20 @@ ondisk_section_sp->GetName() == g_section_name_LINKEDIT) continue; - const Section *memory_section = - memory_section_list - ->FindSectionByName(ondisk_section_sp->GetName()) - .get(); - if (memory_section) { - target.SetSectionLoadAddress(ondisk_section_sp, - memory_section->GetFileAddress()); - ++num_sections_loaded; + if (fixed_slide != LLDB_INVALID_ADDRESS) { + target.SetSectionLoadAddress( + ondisk_section_sp, + ondisk_section_sp->GetFileAddress() + fixed_slide); + } else { + const Section *memory_section = + memory_section_list + ->FindSectionByName(ondisk_section_sp->GetName()) + .get(); + if (memory_section) { + target.SetSectionLoadAddress( + ondisk_section_sp, memory_section->GetFileAddress()); + ++num_sections_loaded; + } } } } 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 @@ -90,6 +90,8 @@ bool IsSharedCacheBinary() const; + bool IsKext() const; + uint32_t GetAddressByteSize() const override; lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; @@ -151,6 +153,8 @@ bool AllowAssemblyEmulationUnwindPlans() override; + lldb_private::Section *GetMachHeaderSection(); + // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } @@ -193,8 +197,6 @@ /// should not be used. void GetLLDBSharedCacheUUID(lldb::addr_t &base_addir, lldb_private::UUID &uuid); - lldb_private::Section *GetMachHeaderSection(); - lldb::addr_t CalculateSectionLoadAddressForMemoryImage( lldb::addr_t mach_header_load_address, const lldb_private::Section *mach_header_section, 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 @@ -1141,6 +1141,10 @@ return m_header.flags & MH_DYLIB_IN_CACHE; } +bool ObjectFileMachO::IsKext() const { + return m_header.filetype == MH_KEXT_BUNDLE; +} + uint32_t ObjectFileMachO::GetAddressByteSize() const { return m_data.GetAddressByteSize(); }