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/ManagedStatic.h"
19 #include "llvm/Support/Mutex.h"
20 #include <vector>
21
22 using namespace llvm;
23 using namespace llvm::sys;
24
25 // All methods for HandleSet should be used holding SymbolsMutex.
26 class DynamicLibrary::HandleSet {
27 typedef std::vector<void *> HandleList;
28 HandleList Handles;
29 void *Process = nullptr;
30
31 public:
32 static void *DLOpen(const char *Filename, std::string *Err);
33 static void DLClose(void *Handle);
34 static void *DLSym(void *Handle, const char *Symbol);
35
36 HandleSet() = default;
37 ~HandleSet();
38
Find(void * Handle)39 HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
40
Contains(void * Handle)41 bool Contains(void *Handle) {
42 return Handle == Process || Find(Handle) != Handles.end();
43 }
44
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true)45 bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
46 #ifdef _WIN32
47 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
48 #endif
49
50 if (LLVM_LIKELY(!IsProcess)) {
51 if (Find(Handle) != Handles.end()) {
52 if (CanClose)
53 DLClose(Handle);
54 return false;
55 }
56 Handles.push_back(Handle);
57 } else {
58 #ifndef _WIN32
59 if (Process) {
60 if (CanClose)
61 DLClose(Process);
62 if (Process == Handle)
63 return false;
64 }
65 #endif
66 Process = Handle;
67 }
68 return true;
69 }
70
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)71 void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
72 if (Order & SO_LoadOrder) {
73 for (void *Handle : Handles) {
74 if (void *Ptr = DLSym(Handle, Symbol))
75 return Ptr;
76 }
77 } else {
78 for (void *Handle : llvm::reverse(Handles)) {
79 if (void *Ptr = DLSym(Handle, Symbol))
80 return Ptr;
81 }
82 }
83 return nullptr;
84 }
85
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)86 void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
87 assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
88 "Invalid Ordering");
89
90 if (!Process || (Order & SO_LoadedFirst)) {
91 if (void *Ptr = LibLookup(Symbol, Order))
92 return Ptr;
93 }
94 if (Process) {
95 // Use OS facilities to search the current binary and all loaded libs.
96 if (void *Ptr = DLSym(Process, Symbol))
97 return Ptr;
98
99 // Search any libs that might have been skipped because of RTLD_LOCAL.
100 if (Order & SO_LoadedLast) {
101 if (void *Ptr = LibLookup(Symbol, Order))
102 return Ptr;
103 }
104 }
105 return nullptr;
106 }
107 };
108
109 namespace {
110 // Collection of symbol name/value pairs to be searched prior to any libraries.
111 static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
112 // Collection of known library handles.
113 static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
114 // Lock for ExplicitSymbols and OpenedHandles.
115 static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
116 } // namespace
117
118 #ifdef _WIN32
119
120 #include "Windows/DynamicLibrary.inc"
121
122 #else
123
124 #include "Unix/DynamicLibrary.inc"
125
126 #endif
127
128 char DynamicLibrary::Invalid;
129 DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
130 DynamicLibrary::SO_Linker;
131
132 namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)133 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
134 return DoSearch(SymbolName); // DynamicLibrary.inc
135 }
136 } // namespace llvm
137
AddSymbol(StringRef SymbolName,void * SymbolValue)138 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
139 SmartScopedLock<true> Lock(*SymbolsMutex);
140 (*ExplicitSymbols)[SymbolName] = SymbolValue;
141 }
142
getPermanentLibrary(const char * FileName,std::string * Err)143 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
144 std::string *Err) {
145 // Force OpenedHandles to be added into the ManagedStatic list before any
146 // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
147 HandleSet& HS = *OpenedHandles;
148
149 void *Handle = HandleSet::DLOpen(FileName, Err);
150 if (Handle != &Invalid) {
151 SmartScopedLock<true> Lock(*SymbolsMutex);
152 HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
153 }
154
155 return DynamicLibrary(Handle);
156 }
157
addPermanentLibrary(void * Handle,std::string * Err)158 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
159 std::string *Err) {
160 SmartScopedLock<true> Lock(*SymbolsMutex);
161 // If we've already loaded this library, tell the caller.
162 if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
163 *Err = "Library already loaded";
164
165 return DynamicLibrary(Handle);
166 }
167
getAddressOfSymbol(const char * SymbolName)168 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
169 if (!isValid())
170 return nullptr;
171 return HandleSet::DLSym(Data, SymbolName);
172 }
173
SearchForAddressOfSymbol(const char * SymbolName)174 void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
175 {
176 SmartScopedLock<true> Lock(*SymbolsMutex);
177
178 // First check symbols added via AddSymbol().
179 if (ExplicitSymbols.isConstructed()) {
180 StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
181
182 if (i != ExplicitSymbols->end())
183 return i->second;
184 }
185
186 // Now search the libraries.
187 if (OpenedHandles.isConstructed()) {
188 if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
189 return Ptr;
190 }
191 }
192
193 return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
194 }
195
196 //===----------------------------------------------------------------------===//
197 // C API.
198 //===----------------------------------------------------------------------===//
199
LLVMLoadLibraryPermanently(const char * Filename)200 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
201 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
202 }
203
LLVMSearchForAddressOfSymbol(const char * symbolName)204 void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
205 return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
206 }
207
LLVMAddSymbol(const char * symbolName,void * symbolValue)208 void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
209 return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
210 }
211