| //===-- 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/DenseSet.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Config/config.h" |
| #include "llvm/Support/ManagedStatic.h" |
| #include "llvm/Support/Mutex.h" |
| #include <cstdio> |
| #include <cstring> |
| #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; |
| |
| public: |
| static void *DLOpen(const char *Filename, std::string *Err); |
| static void DLClose(void *Handle); |
| static void *DLSym(void *Handle, const char *Symbol); |
| |
| HandleSet() : Process(nullptr) {} |
| ~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) { |
| #ifdef _WIN32 |
| assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); |
| #endif |
| |
| if (LLVM_LIKELY(!IsProcess)) { |
| if (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 *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 { |
| // Collection of symbol name/value pairs to be searched prior to any libraries. |
| static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols; |
| // Collection of known library handles. |
| static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles; |
| // Lock for ExplicitSymbols and OpenedHandles. |
| static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex; |
| } // 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) { |
| SmartScopedLock<true> Lock(*SymbolsMutex); |
| (*ExplicitSymbols)[SymbolName] = SymbolValue; |
| } |
| |
| DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, |
| std::string *Err) { |
| // Force OpenedHandles to be added into the ManagedStatic list before any |
| // ManagedStatic can be added from static constructors in HandleSet::DLOpen. |
| HandleSet& HS = *OpenedHandles; |
| |
| void *Handle = HandleSet::DLOpen(FileName, Err); |
| if (Handle != &Invalid) { |
| SmartScopedLock<true> Lock(*SymbolsMutex); |
| HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); |
| } |
| |
| return DynamicLibrary(Handle); |
| } |
| |
| DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, |
| std::string *Err) { |
| SmartScopedLock<true> Lock(*SymbolsMutex); |
| // If we've already loaded this library, tell the caller. |
| if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false)) |
| *Err = "Library already loaded"; |
| |
| return DynamicLibrary(Handle); |
| } |
| |
| void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { |
| if (!isValid()) |
| return nullptr; |
| return HandleSet::DLSym(Data, SymbolName); |
| } |
| |
| void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { |
| { |
| SmartScopedLock<true> Lock(*SymbolsMutex); |
| |
| // First check symbols added via AddSymbol(). |
| if (ExplicitSymbols.isConstructed()) { |
| StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName); |
| |
| if (i != ExplicitSymbols->end()) |
| return i->second; |
| } |
| |
| // Now search the libraries. |
| if (OpenedHandles.isConstructed()) { |
| if (void *Ptr = OpenedHandles->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); |
| } |