//===-- DynamicLoader.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Target/DynamicLoader.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/lldb-private-interfaces.h" #include "llvm/ADT/StringRef.h" #include #include using namespace lldb; using namespace lldb_private; DynamicLoader *DynamicLoader::FindPlugin(Process *process, llvm::StringRef plugin_name) { DynamicLoaderCreateInstance create_callback = nullptr; if (!plugin_name.empty()) { create_callback = PluginManager::GetDynamicLoaderCreateCallbackForPluginName(plugin_name); if (create_callback) { std::unique_ptr instance_up( create_callback(process, true)); if (instance_up) return instance_up.release(); } } else { for (uint32_t idx = 0; (create_callback = PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != nullptr; ++idx) { std::unique_ptr instance_up( create_callback(process, false)); if (instance_up) return instance_up.release(); } } return nullptr; } DynamicLoader::DynamicLoader(Process *process) : m_process(process) {} // Accessors to the global setting as to whether to stop at image (shared // library) loading/unloading. bool DynamicLoader::GetStopWhenImagesChange() const { return m_process->GetStopOnSharedLibraryEvents(); } void DynamicLoader::SetStopWhenImagesChange(bool stop) { m_process->SetStopOnSharedLibraryEvents(stop); } ModuleSP DynamicLoader::GetTargetExecutable() { Target &target = m_process->GetTarget(); ModuleSP executable = target.GetExecutableModule(); if (executable) { if (FileSystem::Instance().Exists(executable->GetFileSpec())) { ModuleSpec module_spec(executable->GetFileSpec(), executable->GetArchitecture()); auto module_sp = std::make_shared(module_spec); // Check if the executable has changed and set it to the target // executable if they differ. if (module_sp && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) { if (module_sp->GetUUID() != executable->GetUUID()) executable.reset(); } else if (executable->FileHasChanged()) { executable.reset(); } if (!executable) { executable = target.GetOrCreateModule(module_spec, true /* notify */); if (executable.get() != target.GetExecutableModulePointer()) { // Don't load dependent images since we are in dyld where we will // know and find out about all images that are loaded target.SetExecutableModule(executable, eLoadDependentsNo); } } } } return executable; } void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr, bool base_addr_is_offset) { UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { bool changed; module->SetLoadAddress(m_process->GetTarget(), base_addr, base_addr_is_offset, changed); } void DynamicLoader::UnloadSections(const ModuleSP module) { UnloadSectionsCommon(module); } void DynamicLoader::UnloadSectionsCommon(const ModuleSP module) { Target &target = m_process->GetTarget(); const SectionList *sections = GetSectionListFromModule(module); assert(sections && "SectionList missing from unloaded module."); const size_t num_sections = sections->GetSize(); for (size_t i = 0; i < num_sections; ++i) { SectionSP section_sp(sections->GetSectionAtIndex(i)); target.SetSectionUnloaded(section_sp); } } const SectionList * DynamicLoader::GetSectionListFromModule(const ModuleSP module) const { SectionList *sections = nullptr; if (module) { ObjectFile *obj_file = module->GetObjectFile(); if (obj_file != nullptr) { sections = obj_file->GetSectionList(); } } return sections; } ModuleSP DynamicLoader::FindModuleViaTarget(const FileSpec &file) { Target &target = m_process->GetTarget(); ModuleSpec module_spec(file, target.GetArchitecture()); if (ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec)) return module_sp; if (ModuleSP module_sp = target.GetOrCreateModule(module_spec, false)) return module_sp; return nullptr; } ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr, bool base_addr_is_offset) { if (ModuleSP module_sp = FindModuleViaTarget(file)) { UpdateLoadedSections(module_sp, link_map_addr, base_addr, base_addr_is_offset); return module_sp; } return nullptr; } static ModuleSP ReadUnnamedMemoryModule(Process *process, addr_t addr, llvm::StringRef name) { char namebuf[80]; if (name.empty()) { snprintf(namebuf, sizeof(namebuf), "memory-image-0x%" PRIx64, addr); name = namebuf; } return process->ReadModuleFromMemory(FileSpec(name), addr); } ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( Process *process, llvm::StringRef name, UUID uuid, addr_t value, bool value_is_offset, bool force_symbol_search, bool notify, bool set_address_in_target, bool allow_memory_image_last_resort) { ModuleSP memory_module_sp; ModuleSP module_sp; PlatformSP platform_sp = process->GetTarget().GetPlatform(); Target &target = process->GetTarget(); Status error; StreamString prog_str; if (!name.empty()) { prog_str << name.str() << " "; } if (uuid.IsValid()) prog_str << uuid.GetAsString(); if (value_is_offset == 0 && value != LLDB_INVALID_ADDRESS) { prog_str << "at 0x"; prog_str.PutHex64(value); } if (!uuid.IsValid() && !value_is_offset) { memory_module_sp = ReadUnnamedMemoryModule(process, value, name); if (memory_module_sp) { uuid = memory_module_sp->GetUUID(); if (uuid.IsValid()) { prog_str << " "; prog_str << uuid.GetAsString(); } } } ModuleSpec module_spec; module_spec.GetUUID() = uuid; FileSpec name_filespec(name); if (uuid.IsValid()) { Progress progress("Locating binary", prog_str.GetString().str()); // Has lldb already seen a module with this UUID? // Or have external lookup enabled in DebugSymbols on macOS. if (!module_sp) error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr, nullptr, nullptr); // Can lldb's symbol/executable location schemes // find an executable and symbol file. if (!module_sp) { FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); module_spec.GetSymbolFileSpec() = PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); ModuleSpec objfile_module_spec = PluginManager::LocateExecutableObjectFile(module_spec); module_spec.GetFileSpec() = objfile_module_spec.GetFileSpec(); if (FileSystem::Instance().Exists(module_spec.GetFileSpec()) && FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec())) { module_sp = std::make_shared(module_spec); } } // If we haven't found a binary, or we don't have a SymbolFile, see // if there is an external search tool that can find it. if (!module_sp || !module_sp->GetSymbolFileFileSpec()) { PluginManager::DownloadObjectAndSymbolFile(module_spec, error, force_symbol_search); if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { module_sp = std::make_shared(module_spec); } else if (force_symbol_search && error.AsCString("") && error.AsCString("")[0] != '\0') { target.GetDebugger().GetErrorStream() << error.AsCString(); } } // If we only found the executable, create a Module based on that. if (!module_sp && FileSystem::Instance().Exists(module_spec.GetFileSpec())) module_sp = std::make_shared(module_spec); } // If we couldn't find the binary anywhere else, as a last resort, // read it out of memory. if (allow_memory_image_last_resort && !module_sp.get() && value != LLDB_INVALID_ADDRESS && !value_is_offset) { if (!memory_module_sp) memory_module_sp = ReadUnnamedMemoryModule(process, value, name); if (memory_module_sp) module_sp = memory_module_sp; } Log *log = GetLog(LLDBLog::DynamicLoader); if (module_sp.get()) { // Ensure the Target has an architecture set in case // we need it while processing this binary/eh_frame/debug info. if (!target.GetArchitecture().IsValid()) target.SetArchitecture(module_sp->GetArchitecture()); target.GetImages().AppendIfNeeded(module_sp, false); bool changed = false; if (set_address_in_target) { if (module_sp->GetObjectFile()) { if (value != LLDB_INVALID_ADDRESS) { LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading " "binary %s UUID %s at %s 0x%" PRIx64, name.str().c_str(), uuid.GetAsString().c_str(), value_is_offset ? "offset" : "address", value); module_sp->SetLoadAddress(target, value, value_is_offset, changed); } else { // No address/offset/slide, load the binary at file address, // offset 0. LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading " "binary %s UUID %s at file address", name.str().c_str(), uuid.GetAsString().c_str()); module_sp->SetLoadAddress(target, 0, true /* value_is_slide */, changed); } } else { // In-memory image, load at its true address, offset 0. LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading binary " "%s UUID %s from memory at address 0x%" PRIx64, name.str().c_str(), uuid.GetAsString().c_str(), value); module_sp->SetLoadAddress(target, 0, true /* value_is_slide */, changed); } } if (notify) { ModuleList added_module; added_module.Append(module_sp, false); target.ModulesDidLoad(added_module); } } else { if (force_symbol_search) { Stream &s = target.GetDebugger().GetErrorStream(); s.Printf("Unable to find file"); if (!name.empty()) s.Printf(" %s", name.str().c_str()); if (uuid.IsValid()) s.Printf(" with UUID %s", uuid.GetAsString().c_str()); if (value != LLDB_INVALID_ADDRESS) { if (value_is_offset) s.Printf(" with slide 0x%" PRIx64, value); else s.Printf(" at address 0x%" PRIx64, value); } s.Printf("\n"); } LLDB_LOGF(log, "Unable to find binary %s with UUID %s and load it at " "%s 0x%" PRIx64, name.str().c_str(), uuid.GetAsString().c_str(), value_is_offset ? "offset" : "address", value); } return module_sp; } int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr, int size_in_bytes) { Status error; uint64_t value = m_process->ReadUnsignedIntegerFromMemory(addr, size_in_bytes, 0, error); if (error.Fail()) return -1; else return (int64_t)value; } addr_t DynamicLoader::ReadPointer(addr_t addr) { Status error; addr_t value = m_process->ReadPointerFromMemory(addr, error); if (error.Fail()) return LLDB_INVALID_ADDRESS; else return value; } void DynamicLoader::LoadOperatingSystemPlugin(bool flush) { if (m_process) m_process->LoadOperatingSystemPlugin(flush); }