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