254 lines · cpp
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-exception6//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 21using namespace llvm;22using namespace llvm::sys;23 24// All methods for HandleSet should be used holding SymbolsMutex.25class DynamicLibrary::HandleSet {26 using HandleList = std::vector<void *>;27 HandleList Handles;28 void *Process = &Invalid;29 30public: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 _WIN3247 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");48#endif49 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 _WIN3261 if (Process != &Invalid) {62 if (CanClose)63 DLClose(Process);64 if (Process == Handle)65 return false;66 }67#endif68 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 == &Invalid || (Order & SO_LoadedFirst)) {101 if (void *Ptr = LibLookup(Symbol, Order))102 return Ptr;103 }104 if (Process != &Invalid) {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 119namespace {120 121struct Globals {122 // Collection of symbol name/value pairs to be searched prior to any123 // 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 132Globals &getGlobals() {133 static Globals G;134 return G;135}136 137} // namespace138 139#ifdef _WIN32140 141#include "Windows/DynamicLibrary.inc"142 143#else144 145#include "Unix/DynamicLibrary.inc"146 147#endif148 149char DynamicLibrary::Invalid;150DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =151 DynamicLibrary::SO_Linker;152 153namespace llvm {154void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {155 return DoSearch(SymbolName); // DynamicLibrary.inc156}157} // namespace llvm158 159void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {160 auto &G = getGlobals();161 SmartScopedLock<true> Lock(G.SymbolsMutex);162 G.ExplicitSymbols[SymbolName] = SymbolValue;163}164 165DynamicLibrary 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 177DynamicLibrary 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 189DynamicLibrary 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 203void 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 212void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {213 if (!isValid())214 return nullptr;215 return HandleSet::DLSym(Data, SymbolName);216}217 218void *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 243LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {244 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);245}246 247void *LLVMSearchForAddressOfSymbol(const char *symbolName) {248 return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);249}250 251void LLVMAddSymbol(const char *symbolName, void *symbolValue) {252 return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);253}254