1 //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// 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 // This file implements the operating system DynamicLibrary concept. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Support/DynamicLibrary.h" 14 #include "llvm-c/Support.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/Config/config.h" 18 #include "llvm/Support/Mutex.h" 19 #include <vector> 20 21 using namespace llvm; 22 using namespace llvm::sys; 23 24 // All methods for HandleSet should be used holding SymbolsMutex. 25 class DynamicLibrary::HandleSet { 26 typedef std::vector<void *> HandleList; 27 HandleList Handles; 28 void *Process = nullptr; 29 30 public: 31 static void *DLOpen(const char *Filename, std::string *Err); 32 static void DLClose(void *Handle); 33 static void *DLSym(void *Handle, const char *Symbol); 34 35 HandleSet() = default; 36 ~HandleSet(); 37 38 HandleList::iterator Find(void *Handle) { return find(Handles, Handle); } 39 40 bool Contains(void *Handle) { 41 return Handle == Process || Find(Handle) != Handles.end(); 42 } 43 44 bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true, 45 bool AllowDuplicates = false) { 46 #ifdef _WIN32 47 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); 48 #endif 49 assert((!AllowDuplicates || !CanClose) && 50 "CanClose must be false if AllowDuplicates is true."); 51 52 if (LLVM_LIKELY(!IsProcess)) { 53 if (!AllowDuplicates && Find(Handle) != Handles.end()) { 54 if (CanClose) 55 DLClose(Handle); 56 return false; 57 } 58 Handles.push_back(Handle); 59 } else { 60 #ifndef _WIN32 61 if (Process) { 62 if (CanClose) 63 DLClose(Process); 64 if (Process == Handle) 65 return false; 66 } 67 #endif 68 Process = Handle; 69 } 70 return true; 71 } 72 73 void CloseLibrary(void *Handle) { 74 DLClose(Handle); 75 HandleList::iterator it = Find(Handle); 76 if (it != Handles.end()) { 77 Handles.erase(it); 78 } 79 } 80 81 void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 82 if (Order & SO_LoadOrder) { 83 for (void *Handle : Handles) { 84 if (void *Ptr = DLSym(Handle, Symbol)) 85 return Ptr; 86 } 87 } else { 88 for (void *Handle : llvm::reverse(Handles)) { 89 if (void *Ptr = DLSym(Handle, Symbol)) 90 return Ptr; 91 } 92 } 93 return nullptr; 94 } 95 96 void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { 97 assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && 98 "Invalid Ordering"); 99 100 if (!Process || (Order & SO_LoadedFirst)) { 101 if (void *Ptr = LibLookup(Symbol, Order)) 102 return Ptr; 103 } 104 if (Process) { 105 // Use OS facilities to search the current binary and all loaded libs. 106 if (void *Ptr = DLSym(Process, Symbol)) 107 return Ptr; 108 109 // Search any libs that might have been skipped because of RTLD_LOCAL. 110 if (Order & SO_LoadedLast) { 111 if (void *Ptr = LibLookup(Symbol, Order)) 112 return Ptr; 113 } 114 } 115 return nullptr; 116 } 117 }; 118 119 namespace { 120 121 struct Globals { 122 // Collection of symbol name/value pairs to be searched prior to any 123 // libraries. 124 llvm::StringMap<void *> ExplicitSymbols; 125 // Collections of known library handles. 126 DynamicLibrary::HandleSet OpenedHandles; 127 DynamicLibrary::HandleSet OpenedTemporaryHandles; 128 // Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles. 129 llvm::sys::SmartMutex<true> SymbolsMutex; 130 }; 131 132 Globals &getGlobals() { 133 static Globals G; 134 return G; 135 } 136 137 } // namespace 138 139 #ifdef _WIN32 140 141 #include "Windows/DynamicLibrary.inc" 142 143 #else 144 145 #include "Unix/DynamicLibrary.inc" 146 147 #endif 148 149 char DynamicLibrary::Invalid; 150 DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder = 151 DynamicLibrary::SO_Linker; 152 153 namespace llvm { 154 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { 155 return DoSearch(SymbolName); // DynamicLibrary.inc 156 } 157 } // namespace llvm 158 159 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { 160 auto &G = getGlobals(); 161 SmartScopedLock<true> Lock(G.SymbolsMutex); 162 G.ExplicitSymbols[SymbolName] = SymbolValue; 163 } 164 165 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, 166 std::string *Err) { 167 auto &G = getGlobals(); 168 void *Handle = HandleSet::DLOpen(FileName, Err); 169 if (Handle != &Invalid) { 170 SmartScopedLock<true> Lock(G.SymbolsMutex); 171 G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); 172 } 173 174 return DynamicLibrary(Handle); 175 } 176 177 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, 178 std::string *Err) { 179 auto &G = getGlobals(); 180 SmartScopedLock<true> Lock(G.SymbolsMutex); 181 // If we've already loaded this library, tell the caller. 182 if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false, 183 /*CanClose*/ false)) 184 *Err = "Library already loaded"; 185 186 return DynamicLibrary(Handle); 187 } 188 189 DynamicLibrary DynamicLibrary::getLibrary(const char *FileName, 190 std::string *Err) { 191 assert(FileName && "Use getPermanentLibrary() for opening process handle"); 192 void *Handle = HandleSet::DLOpen(FileName, Err); 193 if (Handle != &Invalid) { 194 auto &G = getGlobals(); 195 SmartScopedLock<true> Lock(G.SymbolsMutex); 196 G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false, 197 /*CanClose*/ false, 198 /*AllowDuplicates*/ true); 199 } 200 return DynamicLibrary(Handle); 201 } 202 203 void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) { 204 auto &G = getGlobals(); 205 SmartScopedLock<true> Lock(G.SymbolsMutex); 206 if (Lib.isValid()) { 207 G.OpenedTemporaryHandles.CloseLibrary(Lib.Data); 208 Lib.Data = &Invalid; 209 } 210 } 211 212 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { 213 if (!isValid()) 214 return nullptr; 215 return HandleSet::DLSym(Data, SymbolName); 216 } 217 218 void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { 219 { 220 auto &G = getGlobals(); 221 SmartScopedLock<true> Lock(G.SymbolsMutex); 222 223 // First check symbols added via AddSymbol(). 224 StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName); 225 226 if (i != G.ExplicitSymbols.end()) 227 return i->second; 228 229 // Now search the libraries. 230 if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder)) 231 return Ptr; 232 if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder)) 233 return Ptr; 234 } 235 236 return llvm::SearchForAddressOfSpecialSymbol(SymbolName); 237 } 238 239 //===----------------------------------------------------------------------===// 240 // C API. 241 //===----------------------------------------------------------------------===// 242 243 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { 244 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); 245 } 246 247 void *LLVMSearchForAddressOfSymbol(const char *symbolName) { 248 return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName); 249 } 250 251 void LLVMAddSymbol(const char *symbolName, void *symbolValue) { 252 return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); 253 } 254