/src/llvm-project/llvm/lib/Support/DynamicLibrary.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | HandleSet() = default; |
36 | | ~HandleSet(); |
37 | | |
38 | 0 | HandleList::iterator Find(void *Handle) { return find(Handles, Handle); } |
39 | | |
40 | 0 | bool Contains(void *Handle) { |
41 | 0 | return Handle == Process || Find(Handle) != Handles.end(); |
42 | 0 | } |
43 | | |
44 | | bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true, |
45 | 0 | bool AllowDuplicates = false) { |
46 | | #ifdef _WIN32 |
47 | | assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); |
48 | | #endif |
49 | 0 | assert((!AllowDuplicates || !CanClose) && |
50 | 0 | "CanClose must be false if AllowDuplicates is true."); |
51 | | |
52 | 0 | if (LLVM_LIKELY(!IsProcess)) { |
53 | 0 | if (!AllowDuplicates && Find(Handle) != Handles.end()) { |
54 | 0 | if (CanClose) |
55 | 0 | DLClose(Handle); |
56 | 0 | return false; |
57 | 0 | } |
58 | 0 | Handles.push_back(Handle); |
59 | 0 | } else { |
60 | 0 | #ifndef _WIN32 |
61 | 0 | if (Process) { |
62 | 0 | if (CanClose) |
63 | 0 | DLClose(Process); |
64 | 0 | if (Process == Handle) |
65 | 0 | return false; |
66 | 0 | } |
67 | 0 | #endif |
68 | 0 | Process = Handle; |
69 | 0 | } |
70 | 0 | return true; |
71 | 0 | } |
72 | | |
73 | 0 | void CloseLibrary(void *Handle) { |
74 | 0 | DLClose(Handle); |
75 | 0 | HandleList::iterator it = Find(Handle); |
76 | 0 | if (it != Handles.end()) { |
77 | 0 | Handles.erase(it); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | 0 | void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { |
82 | 0 | if (Order & SO_LoadOrder) { |
83 | 0 | for (void *Handle : Handles) { |
84 | 0 | if (void *Ptr = DLSym(Handle, Symbol)) |
85 | 0 | return Ptr; |
86 | 0 | } |
87 | 0 | } else { |
88 | 0 | for (void *Handle : llvm::reverse(Handles)) { |
89 | 0 | if (void *Ptr = DLSym(Handle, Symbol)) |
90 | 0 | return Ptr; |
91 | 0 | } |
92 | 0 | } |
93 | 0 | return nullptr; |
94 | 0 | } |
95 | | |
96 | 0 | void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { |
97 | 0 | assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && |
98 | 0 | "Invalid Ordering"); |
99 | | |
100 | 0 | if (!Process || (Order & SO_LoadedFirst)) { |
101 | 0 | if (void *Ptr = LibLookup(Symbol, Order)) |
102 | 0 | return Ptr; |
103 | 0 | } |
104 | 0 | if (Process) { |
105 | | // Use OS facilities to search the current binary and all loaded libs. |
106 | 0 | if (void *Ptr = DLSym(Process, Symbol)) |
107 | 0 | return Ptr; |
108 | | |
109 | | // Search any libs that might have been skipped because of RTLD_LOCAL. |
110 | 0 | if (Order & SO_LoadedLast) { |
111 | 0 | if (void *Ptr = LibLookup(Symbol, Order)) |
112 | 0 | return Ptr; |
113 | 0 | } |
114 | 0 | } |
115 | 0 | return nullptr; |
116 | 0 | } |
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 | 0 | Globals &getGlobals() { |
133 | 0 | static Globals G; |
134 | 0 | return G; |
135 | 0 | } |
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 | 0 | void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { |
155 | 0 | return DoSearch(SymbolName); // DynamicLibrary.inc |
156 | 0 | } |
157 | | } // namespace llvm |
158 | | |
159 | 0 | void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { |
160 | 0 | auto &G = getGlobals(); |
161 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
162 | 0 | G.ExplicitSymbols[SymbolName] = SymbolValue; |
163 | 0 | } |
164 | | |
165 | | DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, |
166 | 0 | std::string *Err) { |
167 | 0 | auto &G = getGlobals(); |
168 | 0 | void *Handle = HandleSet::DLOpen(FileName, Err); |
169 | 0 | if (Handle != &Invalid) { |
170 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
171 | 0 | G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); |
172 | 0 | } |
173 | |
|
174 | 0 | return DynamicLibrary(Handle); |
175 | 0 | } |
176 | | |
177 | | DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, |
178 | 0 | std::string *Err) { |
179 | 0 | auto &G = getGlobals(); |
180 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
181 | | // If we've already loaded this library, tell the caller. |
182 | 0 | if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false, |
183 | 0 | /*CanClose*/ false)) |
184 | 0 | *Err = "Library already loaded"; |
185 | |
|
186 | 0 | return DynamicLibrary(Handle); |
187 | 0 | } |
188 | | |
189 | | DynamicLibrary DynamicLibrary::getLibrary(const char *FileName, |
190 | 0 | std::string *Err) { |
191 | 0 | assert(FileName && "Use getPermanentLibrary() for opening process handle"); |
192 | 0 | void *Handle = HandleSet::DLOpen(FileName, Err); |
193 | 0 | if (Handle != &Invalid) { |
194 | 0 | auto &G = getGlobals(); |
195 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
196 | 0 | G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false, |
197 | 0 | /*CanClose*/ false, |
198 | 0 | /*AllowDuplicates*/ true); |
199 | 0 | } |
200 | 0 | return DynamicLibrary(Handle); |
201 | 0 | } |
202 | | |
203 | 0 | void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) { |
204 | 0 | auto &G = getGlobals(); |
205 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
206 | 0 | if (Lib.isValid()) { |
207 | 0 | G.OpenedTemporaryHandles.CloseLibrary(Lib.Data); |
208 | 0 | Lib.Data = &Invalid; |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | 0 | void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { |
213 | 0 | if (!isValid()) |
214 | 0 | return nullptr; |
215 | 0 | return HandleSet::DLSym(Data, SymbolName); |
216 | 0 | } |
217 | | |
218 | 0 | void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { |
219 | 0 | { |
220 | 0 | auto &G = getGlobals(); |
221 | 0 | SmartScopedLock<true> Lock(G.SymbolsMutex); |
222 | | |
223 | | // First check symbols added via AddSymbol(). |
224 | 0 | StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName); |
225 | |
|
226 | 0 | if (i != G.ExplicitSymbols.end()) |
227 | 0 | return i->second; |
228 | | |
229 | | // Now search the libraries. |
230 | 0 | if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder)) |
231 | 0 | return Ptr; |
232 | 0 | if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder)) |
233 | 0 | return Ptr; |
234 | 0 | } |
235 | | |
236 | 0 | return llvm::SearchForAddressOfSpecialSymbol(SymbolName); |
237 | 0 | } |
238 | | |
239 | | //===----------------------------------------------------------------------===// |
240 | | // C API. |
241 | | //===----------------------------------------------------------------------===// |
242 | | |
243 | 0 | LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { |
244 | 0 | return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); |
245 | 0 | } |
246 | | |
247 | 0 | void *LLVMSearchForAddressOfSymbol(const char *symbolName) { |
248 | 0 | return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName); |
249 | 0 | } |
250 | | |
251 | 0 | void LLVMAddSymbol(const char *symbolName, void *symbolValue) { |
252 | 0 | return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); |
253 | 0 | } |