| //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the operating system DynamicLibrary concept. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Support/DynamicLibrary.h" |
| #include "llvm-c/Support.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Config/config.h" |
| #include "llvm/Support/Mutex.h" |
| #include <vector> |
| |
| using namespace llvm; |
| using namespace llvm::sys; |
| |
| // All methods for HandleSet should be used holding SymbolsMutex. |
| class DynamicLibrary::HandleSet { |
| typedef std::vector<void *> HandleList; |
| HandleList Handles; |
| void *Process = nullptr; |
| |
| public: |
| static void *DLOpen(const char *Filename, std::string *Err); |
| static void DLClose(void *Handle); |
| static void *DLSym(void *Handle, const char *Symbol); |
| |
| HandleSet() = default; |
| ~HandleSet(); |
| |
| HandleList::iterator Find(void *Handle) { return find(Handles, Handle); } |
| |
| bool Contains(void *Handle) { |
| return Handle == Process || Find(Handle) != Handles.end(); |
| } |
| |
| bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true, |
| bool AllowDuplicates = false) { |
| #ifdef _WIN32 |
| assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); |
| #endif |
| assert((!AllowDuplicates || !CanClose) && |
| "CanClose must be false if AllowDuplicates is true."); |
| |
| if (LLVM_LIKELY(!IsProcess)) { |
| if (!AllowDuplicates && Find(Handle) != Handles.end()) { |
| if (CanClose) |
| DLClose(Handle); |
| return false; |
| } |
| Handles.push_back(Handle); |
| } else { |
| #ifndef _WIN32 |
| if (Process) { |
| if (CanClose) |
| DLClose(Process); |
| if (Process == Handle) |
| return false; |
| } |
| #endif |
| Process = Handle; |
| } |
| return true; |
| } |
| |
| void CloseLibrary(void *Handle) { |
| DLClose(Handle); |
| HandleList::iterator it = Find(Handle); |
| if (it != Handles.end()) { |
| Handles.erase(it); |
| } |
| } |
| |
| void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { |
| if (Order & SO_LoadOrder) { |
| for (void *Handle : Handles) { |
| if (void *Ptr = DLSym(Handle, Symbol)) |
| return Ptr; |
| } |
| } else { |
| for (void *Handle : llvm::reverse(Handles)) { |
| if (void *Ptr = DLSym(Handle, Symbol)) |
| return Ptr; |
| } |
| } |
| return nullptr; |
| } |
| |
| void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { |
| assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && |
| "Invalid Ordering"); |
| |
| if (!Process || (Order & SO_LoadedFirst)) { |
| if (void *Ptr = LibLookup(Symbol, Order)) |
| return Ptr; |
| } |
| if (Process) { |
| // Use OS facilities to search the current binary and all loaded libs. |
| if (void *Ptr = DLSym(Process, Symbol)) |
| return Ptr; |
| |
| // Search any libs that might have been skipped because of RTLD_LOCAL. |
| if (Order & SO_LoadedLast) { |
| if (void *Ptr = LibLookup(Symbol, Order)) |
| return Ptr; |
| } |
| } |
| return nullptr; |
| } |
| }; |
| |
| namespace { |
| |
| struct Globals { |
| // Collection of symbol name/value pairs to be searched prior to any |
| // libraries. |
| llvm::StringMap<void *> ExplicitSymbols; |
| // Collections of known library handles. |
| DynamicLibrary::HandleSet OpenedHandles; |
| DynamicLibrary::HandleSet OpenedTemporaryHandles; |
| // Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles. |
| llvm::sys::SmartMutex<true> SymbolsMutex; |
| }; |
| |
| Globals &getGlobals() { |
| static Globals G; |
| return G; |
| } |
| |
| } // namespace |
| |
| #ifdef _WIN32 |
| |
| #include "Windows/DynamicLibrary.inc" |
| |
| #else |
| |
| #include "Unix/DynamicLibrary.inc" |
| |
| #endif |
| |
| char DynamicLibrary::Invalid; |
| DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder = |
| DynamicLibrary::SO_Linker; |
| |
| namespace llvm { |
| void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { |
| return DoSearch(SymbolName); // DynamicLibrary.inc |
| } |
| } // namespace llvm |
| |
| void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { |
| auto &G = getGlobals(); |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| G.ExplicitSymbols[SymbolName] = SymbolValue; |
| } |
| |
| DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, |
| std::string *Err) { |
| auto &G = getGlobals(); |
| void *Handle = HandleSet::DLOpen(FileName, Err); |
| if (Handle != &Invalid) { |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); |
| } |
| |
| return DynamicLibrary(Handle); |
| } |
| |
| DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, |
| std::string *Err) { |
| auto &G = getGlobals(); |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| // If we've already loaded this library, tell the caller. |
| if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false, |
| /*CanClose*/ false)) |
| *Err = "Library already loaded"; |
| |
| return DynamicLibrary(Handle); |
| } |
| |
| DynamicLibrary DynamicLibrary::getLibrary(const char *FileName, |
| std::string *Err) { |
| assert(FileName && "Use getPermanentLibrary() for opening process handle"); |
| void *Handle = HandleSet::DLOpen(FileName, Err); |
| if (Handle != &Invalid) { |
| auto &G = getGlobals(); |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false, |
| /*CanClose*/ false, |
| /*AllowDuplicates*/ true); |
| } |
| return DynamicLibrary(Handle); |
| } |
| |
| void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) { |
| auto &G = getGlobals(); |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| if (Lib.isValid()) { |
| G.OpenedTemporaryHandles.CloseLibrary(Lib.Data); |
| Lib.Data = &Invalid; |
| } |
| } |
| |
| void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { |
| if (!isValid()) |
| return nullptr; |
| return HandleSet::DLSym(Data, SymbolName); |
| } |
| |
| void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { |
| { |
| auto &G = getGlobals(); |
| SmartScopedLock<true> Lock(G.SymbolsMutex); |
| |
| // First check symbols added via AddSymbol(). |
| StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName); |
| |
| if (i != G.ExplicitSymbols.end()) |
| return i->second; |
| |
| // Now search the libraries. |
| if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder)) |
| return Ptr; |
| if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder)) |
| return Ptr; |
| } |
| |
| return llvm::SearchForAddressOfSpecialSymbol(SymbolName); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // C API. |
| //===----------------------------------------------------------------------===// |
| |
| LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { |
| return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); |
| } |
| |
| void *LLVMSearchForAddressOfSymbol(const char *symbolName) { |
| return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName); |
| } |
| |
| void LLVMAddSymbol(const char *symbolName, void *symbolValue) { |
| return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); |
| } |