1 //===-- DynamicLoader.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/DynamicLoader.h" 10 11 #include "lldb/Core/Module.h" 12 #include "lldb/Core/ModuleList.h" 13 #include "lldb/Core/ModuleSpec.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/Section.h" 16 #include "lldb/Symbol/ObjectFile.h" 17 #include "lldb/Target/MemoryRegionInfo.h" 18 #include "lldb/Target/Process.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Utility/ConstString.h" 21 #include "lldb/lldb-private-interfaces.h" 22 23 #include "llvm/ADT/StringRef.h" 24 25 #include <memory> 26 27 #include <cassert> 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 DynamicLoader *DynamicLoader::FindPlugin(Process *process, 33 llvm::StringRef plugin_name) { 34 DynamicLoaderCreateInstance create_callback = nullptr; 35 if (!plugin_name.empty()) { 36 create_callback = 37 PluginManager::GetDynamicLoaderCreateCallbackForPluginName(plugin_name); 38 if (create_callback) { 39 std::unique_ptr<DynamicLoader> instance_up( 40 create_callback(process, true)); 41 if (instance_up) 42 return instance_up.release(); 43 } 44 } else { 45 for (uint32_t idx = 0; 46 (create_callback = 47 PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != 48 nullptr; 49 ++idx) { 50 std::unique_ptr<DynamicLoader> instance_up( 51 create_callback(process, false)); 52 if (instance_up) 53 return instance_up.release(); 54 } 55 } 56 return nullptr; 57 } 58 59 DynamicLoader::DynamicLoader(Process *process) : m_process(process) {} 60 61 // Accessosors to the global setting as to whether to stop at image (shared 62 // library) loading/unloading. 63 64 bool DynamicLoader::GetStopWhenImagesChange() const { 65 return m_process->GetStopOnSharedLibraryEvents(); 66 } 67 68 void DynamicLoader::SetStopWhenImagesChange(bool stop) { 69 m_process->SetStopOnSharedLibraryEvents(stop); 70 } 71 72 ModuleSP DynamicLoader::GetTargetExecutable() { 73 Target &target = m_process->GetTarget(); 74 ModuleSP executable = target.GetExecutableModule(); 75 76 if (executable) { 77 if (FileSystem::Instance().Exists(executable->GetFileSpec())) { 78 ModuleSpec module_spec(executable->GetFileSpec(), 79 executable->GetArchitecture()); 80 auto module_sp = std::make_shared<Module>(module_spec); 81 82 // Check if the executable has changed and set it to the target 83 // executable if they differ. 84 if (module_sp && module_sp->GetUUID().IsValid() && 85 executable->GetUUID().IsValid()) { 86 if (module_sp->GetUUID() != executable->GetUUID()) 87 executable.reset(); 88 } else if (executable->FileHasChanged()) { 89 executable.reset(); 90 } 91 92 if (!executable) { 93 executable = target.GetOrCreateModule(module_spec, true /* notify */); 94 if (executable.get() != target.GetExecutableModulePointer()) { 95 // Don't load dependent images since we are in dyld where we will 96 // know and find out about all images that are loaded 97 target.SetExecutableModule(executable, eLoadDependentsNo); 98 } 99 } 100 } 101 } 102 return executable; 103 } 104 105 void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, 106 addr_t base_addr, 107 bool base_addr_is_offset) { 108 UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); 109 } 110 111 void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, 112 addr_t base_addr, 113 bool base_addr_is_offset) { 114 bool changed; 115 module->SetLoadAddress(m_process->GetTarget(), base_addr, base_addr_is_offset, 116 changed); 117 } 118 119 void DynamicLoader::UnloadSections(const ModuleSP module) { 120 UnloadSectionsCommon(module); 121 } 122 123 void DynamicLoader::UnloadSectionsCommon(const ModuleSP module) { 124 Target &target = m_process->GetTarget(); 125 const SectionList *sections = GetSectionListFromModule(module); 126 127 assert(sections && "SectionList missing from unloaded module."); 128 129 const size_t num_sections = sections->GetSize(); 130 for (size_t i = 0; i < num_sections; ++i) { 131 SectionSP section_sp(sections->GetSectionAtIndex(i)); 132 target.SetSectionUnloaded(section_sp); 133 } 134 } 135 136 const SectionList * 137 DynamicLoader::GetSectionListFromModule(const ModuleSP module) const { 138 SectionList *sections = nullptr; 139 if (module) { 140 ObjectFile *obj_file = module->GetObjectFile(); 141 if (obj_file != nullptr) { 142 sections = obj_file->GetSectionList(); 143 } 144 } 145 return sections; 146 } 147 148 ModuleSP DynamicLoader::FindModuleViaTarget(const FileSpec &file) { 149 Target &target = m_process->GetTarget(); 150 ModuleSpec module_spec(file, target.GetArchitecture()); 151 152 if (ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec)) 153 return module_sp; 154 155 if (ModuleSP module_sp = target.GetOrCreateModule(module_spec, false)) 156 return module_sp; 157 158 return nullptr; 159 } 160 161 ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file, 162 addr_t link_map_addr, 163 addr_t base_addr, 164 bool base_addr_is_offset) { 165 if (ModuleSP module_sp = FindModuleViaTarget(file)) { 166 UpdateLoadedSections(module_sp, link_map_addr, base_addr, 167 base_addr_is_offset); 168 return module_sp; 169 } 170 171 return nullptr; 172 } 173 174 int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr, 175 int size_in_bytes) { 176 Status error; 177 uint64_t value = 178 m_process->ReadUnsignedIntegerFromMemory(addr, size_in_bytes, 0, error); 179 if (error.Fail()) 180 return -1; 181 else 182 return (int64_t)value; 183 } 184 185 addr_t DynamicLoader::ReadPointer(addr_t addr) { 186 Status error; 187 addr_t value = m_process->ReadPointerFromMemory(addr, error); 188 if (error.Fail()) 189 return LLDB_INVALID_ADDRESS; 190 else 191 return value; 192 } 193 194 void DynamicLoader::LoadOperatingSystemPlugin(bool flush) 195 { 196 if (m_process) 197 m_process->LoadOperatingSystemPlugin(flush); 198 } 199 200