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