| //===-- 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); | |
| } |