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 
39   HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
40 
41   bool Contains(void *Handle) {
42     return Handle == Process || Find(Handle) != Handles.end();
43   }
44 
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 
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 
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 {
133 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
134   return DoSearch(SymbolName); // DynamicLibrary.inc
135 }
136 } // namespace llvm
137 
138 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
139   SmartScopedLock<true> Lock(*SymbolsMutex);
140   (*ExplicitSymbols)[SymbolName] = SymbolValue;
141 }
142 
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 
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 
168 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
169   if (!isValid())
170     return nullptr;
171   return HandleSet::DLSym(Data, SymbolName);
172 }
173 
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 
200 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
201   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
202 }
203 
204 void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
205   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
206 }
207 
208 void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
209   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
210 }
211