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(Range&: Handles, Val: 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(x: Handle); |
59 | } else { |
60 | #ifndef _WIN32 |
61 | if (Process) { |
62 | if (CanClose) |
63 | DLClose(Handle: 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(position: 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(C&: 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(Handle: 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(File: 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(File: 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(Handle: 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(Handle: Data, Symbol: 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(Key: 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(Symbol: SymbolName, Order: SearchOrder)) |
231 | return Ptr; |
232 | if (void *Ptr = G.OpenedTemporaryHandles.Lookup(Symbol: SymbolName, Order: 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: symbolName); |
249 | } |
250 | |
251 | void LLVMAddSymbol(const char *symbolName, void *symbolValue) { |
252 | return llvm::sys::DynamicLibrary::AddSymbol(SymbolName: symbolName, SymbolValue: symbolValue); |
253 | } |
254 | |