1*0b57cec5SDimitry Andric //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements the operating system DynamicLibrary concept.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
14*0b57cec5SDimitry Andric #include "llvm-c/Support.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
16*0b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
17*0b57cec5SDimitry Andric #include "llvm/Config/config.h"
18*0b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
19*0b57cec5SDimitry Andric #include <vector>
20*0b57cec5SDimitry Andric
21*0b57cec5SDimitry Andric using namespace llvm;
22*0b57cec5SDimitry Andric using namespace llvm::sys;
23*0b57cec5SDimitry Andric
24*0b57cec5SDimitry Andric // All methods for HandleSet should be used holding SymbolsMutex.
25*0b57cec5SDimitry Andric class DynamicLibrary::HandleSet {
26*0b57cec5SDimitry Andric typedef std::vector<void *> HandleList;
27*0b57cec5SDimitry Andric HandleList Handles;
28*0b57cec5SDimitry Andric void *Process = nullptr;
29*0b57cec5SDimitry Andric
30*0b57cec5SDimitry Andric public:
31*0b57cec5SDimitry Andric static void *DLOpen(const char *Filename, std::string *Err);
32*0b57cec5SDimitry Andric static void DLClose(void *Handle);
33*0b57cec5SDimitry Andric static void *DLSym(void *Handle, const char *Symbol);
34*0b57cec5SDimitry Andric
35*0b57cec5SDimitry Andric HandleSet() = default;
36*0b57cec5SDimitry Andric ~HandleSet();
37*0b57cec5SDimitry Andric
Find(void * Handle)38*0b57cec5SDimitry Andric HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
39*0b57cec5SDimitry Andric
Contains(void * Handle)40*0b57cec5SDimitry Andric bool Contains(void *Handle) {
41*0b57cec5SDimitry Andric return Handle == Process || Find(Handle) != Handles.end();
42*0b57cec5SDimitry Andric }
43*0b57cec5SDimitry Andric
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true,bool AllowDuplicates=false)44*0b57cec5SDimitry Andric bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true,
45*0b57cec5SDimitry Andric bool AllowDuplicates = false) {
46*0b57cec5SDimitry Andric #ifdef _WIN32
47*0b57cec5SDimitry Andric assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
48*0b57cec5SDimitry Andric #endif
49*0b57cec5SDimitry Andric assert((!AllowDuplicates || !CanClose) &&
50*0b57cec5SDimitry Andric "CanClose must be false if AllowDuplicates is true.");
51*0b57cec5SDimitry Andric
52*0b57cec5SDimitry Andric if (LLVM_LIKELY(!IsProcess)) {
53*0b57cec5SDimitry Andric if (!AllowDuplicates && Find(Handle) != Handles.end()) {
54*0b57cec5SDimitry Andric if (CanClose)
55*0b57cec5SDimitry Andric DLClose(Handle);
56*0b57cec5SDimitry Andric return false;
57*0b57cec5SDimitry Andric }
58*0b57cec5SDimitry Andric Handles.push_back(Handle);
59*0b57cec5SDimitry Andric } else {
60*0b57cec5SDimitry Andric #ifndef _WIN32
61*0b57cec5SDimitry Andric if (Process) {
62*0b57cec5SDimitry Andric if (CanClose)
63*0b57cec5SDimitry Andric DLClose(Process);
64*0b57cec5SDimitry Andric if (Process == Handle)
65*0b57cec5SDimitry Andric return false;
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric #endif
68*0b57cec5SDimitry Andric Process = Handle;
69*0b57cec5SDimitry Andric }
70*0b57cec5SDimitry Andric return true;
71*0b57cec5SDimitry Andric }
72*0b57cec5SDimitry Andric
CloseLibrary(void * Handle)73*0b57cec5SDimitry Andric void CloseLibrary(void *Handle) {
74*0b57cec5SDimitry Andric DLClose(Handle);
75*0b57cec5SDimitry Andric HandleList::iterator it = Find(Handle);
76*0b57cec5SDimitry Andric if (it != Handles.end()) {
77*0b57cec5SDimitry Andric Handles.erase(it);
78*0b57cec5SDimitry Andric }
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)81*0b57cec5SDimitry Andric void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
82*0b57cec5SDimitry Andric if (Order & SO_LoadOrder) {
83*0b57cec5SDimitry Andric for (void *Handle : Handles) {
84*0b57cec5SDimitry Andric if (void *Ptr = DLSym(Handle, Symbol))
85*0b57cec5SDimitry Andric return Ptr;
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric } else {
88*0b57cec5SDimitry Andric for (void *Handle : llvm::reverse(Handles)) {
89*0b57cec5SDimitry Andric if (void *Ptr = DLSym(Handle, Symbol))
90*0b57cec5SDimitry Andric return Ptr;
91*0b57cec5SDimitry Andric }
92*0b57cec5SDimitry Andric }
93*0b57cec5SDimitry Andric return nullptr;
94*0b57cec5SDimitry Andric }
95*0b57cec5SDimitry Andric
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)96*0b57cec5SDimitry Andric void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
97*0b57cec5SDimitry Andric assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
98*0b57cec5SDimitry Andric "Invalid Ordering");
99*0b57cec5SDimitry Andric
100*0b57cec5SDimitry Andric if (!Process || (Order & SO_LoadedFirst)) {
101*0b57cec5SDimitry Andric if (void *Ptr = LibLookup(Symbol, Order))
102*0b57cec5SDimitry Andric return Ptr;
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric if (Process) {
105*0b57cec5SDimitry Andric // Use OS facilities to search the current binary and all loaded libs.
106*0b57cec5SDimitry Andric if (void *Ptr = DLSym(Process, Symbol))
107*0b57cec5SDimitry Andric return Ptr;
108*0b57cec5SDimitry Andric
109*0b57cec5SDimitry Andric // Search any libs that might have been skipped because of RTLD_LOCAL.
110*0b57cec5SDimitry Andric if (Order & SO_LoadedLast) {
111*0b57cec5SDimitry Andric if (void *Ptr = LibLookup(Symbol, Order))
112*0b57cec5SDimitry Andric return Ptr;
113*0b57cec5SDimitry Andric }
114*0b57cec5SDimitry Andric }
115*0b57cec5SDimitry Andric return nullptr;
116*0b57cec5SDimitry Andric }
117*0b57cec5SDimitry Andric };
118*0b57cec5SDimitry Andric
119*0b57cec5SDimitry Andric namespace {
120*0b57cec5SDimitry Andric
121*0b57cec5SDimitry Andric struct Globals {
122*0b57cec5SDimitry Andric // Collection of symbol name/value pairs to be searched prior to any
123*0b57cec5SDimitry Andric // libraries.
124*0b57cec5SDimitry Andric llvm::StringMap<void *> ExplicitSymbols;
125*0b57cec5SDimitry Andric // Collections of known library handles.
126*0b57cec5SDimitry Andric DynamicLibrary::HandleSet OpenedHandles;
127*0b57cec5SDimitry Andric DynamicLibrary::HandleSet OpenedTemporaryHandles;
128*0b57cec5SDimitry Andric // Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles.
129*0b57cec5SDimitry Andric llvm::sys::SmartMutex<true> SymbolsMutex;
130*0b57cec5SDimitry Andric };
131*0b57cec5SDimitry Andric
getGlobals()132*0b57cec5SDimitry Andric Globals &getGlobals() {
133*0b57cec5SDimitry Andric static Globals G;
134*0b57cec5SDimitry Andric return G;
135*0b57cec5SDimitry Andric }
136*0b57cec5SDimitry Andric
137*0b57cec5SDimitry Andric } // namespace
138*0b57cec5SDimitry Andric
139*0b57cec5SDimitry Andric #ifdef _WIN32
140*0b57cec5SDimitry Andric
141*0b57cec5SDimitry Andric #include "Windows/DynamicLibrary.inc"
142*0b57cec5SDimitry Andric
143*0b57cec5SDimitry Andric #else
144*0b57cec5SDimitry Andric
145*0b57cec5SDimitry Andric #include "Unix/DynamicLibrary.inc"
146*0b57cec5SDimitry Andric
147*0b57cec5SDimitry Andric #endif
148*0b57cec5SDimitry Andric
149*0b57cec5SDimitry Andric char DynamicLibrary::Invalid;
150*0b57cec5SDimitry Andric DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
151*0b57cec5SDimitry Andric DynamicLibrary::SO_Linker;
152*0b57cec5SDimitry Andric
153*0b57cec5SDimitry Andric namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)154*0b57cec5SDimitry Andric void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
155*0b57cec5SDimitry Andric return DoSearch(SymbolName); // DynamicLibrary.inc
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric } // namespace llvm
158*0b57cec5SDimitry Andric
AddSymbol(StringRef SymbolName,void * SymbolValue)159*0b57cec5SDimitry Andric void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
160*0b57cec5SDimitry Andric auto &G = getGlobals();
161*0b57cec5SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
162*0b57cec5SDimitry Andric G.ExplicitSymbols[SymbolName] = SymbolValue;
163*0b57cec5SDimitry Andric }
164*0b57cec5SDimitry Andric
getPermanentLibrary(const char * FileName,std::string * Err)165*0b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
166*0b57cec5SDimitry Andric std::string *Err) {
167*0b57cec5SDimitry Andric auto &G = getGlobals();
168*0b57cec5SDimitry Andric void *Handle = HandleSet::DLOpen(FileName, Err);
169*0b57cec5SDimitry Andric if (Handle != &Invalid) {
170*0b57cec5SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
171*0b57cec5SDimitry Andric G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
172*0b57cec5SDimitry Andric }
173*0b57cec5SDimitry Andric
174*0b57cec5SDimitry Andric return DynamicLibrary(Handle);
175*0b57cec5SDimitry Andric }
176*0b57cec5SDimitry Andric
addPermanentLibrary(void * Handle,std::string * Err)177*0b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
178*0b57cec5SDimitry Andric std::string *Err) {
179*0b57cec5SDimitry Andric auto &G = getGlobals();
180*0b57cec5SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
181*0b57cec5SDimitry Andric // If we've already loaded this library, tell the caller.
182*0b57cec5SDimitry Andric if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false,
183*0b57cec5SDimitry Andric /*CanClose*/ false))
184*0b57cec5SDimitry Andric *Err = "Library already loaded";
185*0b57cec5SDimitry Andric
186*0b57cec5SDimitry Andric return DynamicLibrary(Handle);
187*0b57cec5SDimitry Andric }
188*0b57cec5SDimitry Andric
getLibrary(const char * FileName,std::string * Err)189*0b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::getLibrary(const char *FileName,
190*0b57cec5SDimitry Andric std::string *Err) {
191*0b57cec5SDimitry Andric assert(FileName && "Use getPermanentLibrary() for opening process handle");
192*0b57cec5SDimitry Andric void *Handle = HandleSet::DLOpen(FileName, Err);
193*0b57cec5SDimitry Andric if (Handle != &Invalid) {
194*0b57cec5SDimitry Andric auto &G = getGlobals();
195*0b57cec5SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
196*0b57cec5SDimitry Andric G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false,
197*0b57cec5SDimitry Andric /*CanClose*/ false,
198*0b57cec5SDimitry Andric /*AllowDuplicates*/ true);
199*0b57cec5SDimitry Andric }
200*0b57cec5SDimitry Andric return DynamicLibrary(Handle);
201*0b57cec5SDimitry Andric }
202*0b57cec5SDimitry Andric
closeLibrary(DynamicLibrary & Lib)203*0b57cec5SDimitry Andric void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) {
204*0b57cec5SDimitry Andric auto &G = getGlobals();
205*0b57cec5SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
206*0b57cec5SDimitry Andric if (Lib.isValid()) {
207*0b57cec5SDimitry Andric G.OpenedTemporaryHandles.CloseLibrary(Lib.Data);
208*0b57cec5SDimitry Andric Lib.Data = &Invalid;
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric }
211*0b57cec5SDimitry Andric
getAddressOfSymbol(const char * SymbolName)212*0b57cec5SDimitry Andric void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
213*0b57cec5SDimitry Andric if (!isValid())
214*0b57cec5SDimitry Andric return nullptr;
215*0b57cec5SDimitry Andric return HandleSet::DLSym(Data, SymbolName);
216 }
217
SearchForAddressOfSymbol(const char * SymbolName)218 void *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
LLVMLoadLibraryPermanently(const char * Filename)243 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
244 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
245 }
246
LLVMSearchForAddressOfSymbol(const char * symbolName)247 void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
248 return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
249 }
250
LLVMAddSymbol(const char * symbolName,void * symbolValue)251 void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
252 return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
253 }
254