diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp new file mode 100644 index 000000000000..531c035ab926 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp @@ -0,0 +1,253 @@ +//===-- 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); +} |