1cf099d11SDimitry Andric //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2cf099d11SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cf099d11SDimitry Andric //
7cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
8cf099d11SDimitry Andric //
95ca98fd9SDimitry Andric // This file implements the operating system DynamicLibrary concept.
10cf099d11SDimitry Andric //
11cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
12cf099d11SDimitry Andric
13cf099d11SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
145ca98fd9SDimitry Andric #include "llvm-c/Support.h"
15ca089b24SDimitry Andric #include "llvm/ADT/STLExtras.h"
164a16efa3SDimitry Andric #include "llvm/ADT/StringMap.h"
17cf099d11SDimitry Andric #include "llvm/Config/config.h"
184a16efa3SDimitry Andric #include "llvm/Support/Mutex.h"
19a303c417SDimitry Andric #include <vector>
20cf099d11SDimitry Andric
21a303c417SDimitry Andric using namespace llvm;
22a303c417SDimitry Andric using namespace llvm::sys;
2330815c53SDimitry Andric
24a303c417SDimitry Andric // All methods for HandleSet should be used holding SymbolsMutex.
25a303c417SDimitry Andric class DynamicLibrary::HandleSet {
26a303c417SDimitry Andric typedef std::vector<void *> HandleList;
27a303c417SDimitry Andric HandleList Handles;
28145449b1SDimitry Andric void *Process = nullptr;
29a303c417SDimitry Andric
30a303c417SDimitry Andric public:
31a303c417SDimitry Andric static void *DLOpen(const char *Filename, std::string *Err);
32a303c417SDimitry Andric static void DLClose(void *Handle);
33a303c417SDimitry Andric static void *DLSym(void *Handle, const char *Symbol);
34a303c417SDimitry Andric
35145449b1SDimitry Andric HandleSet() = default;
36a303c417SDimitry Andric ~HandleSet();
37a303c417SDimitry Andric
Find(void * Handle)38b60736ecSDimitry Andric HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
39cf099d11SDimitry Andric
Contains(void * Handle)40a303c417SDimitry Andric bool Contains(void *Handle) {
41a303c417SDimitry Andric return Handle == Process || Find(Handle) != Handles.end();
42a303c417SDimitry Andric }
43a303c417SDimitry Andric
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true,bool AllowDuplicates=false)44e3b55780SDimitry Andric bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true,
45e3b55780SDimitry Andric bool AllowDuplicates = false) {
46eb11fae6SDimitry Andric #ifdef _WIN32
47a303c417SDimitry Andric assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
48a303c417SDimitry Andric #endif
49e3b55780SDimitry Andric assert((!AllowDuplicates || !CanClose) &&
50e3b55780SDimitry Andric "CanClose must be false if AllowDuplicates is true.");
51a303c417SDimitry Andric
52a303c417SDimitry Andric if (LLVM_LIKELY(!IsProcess)) {
53e3b55780SDimitry Andric if (!AllowDuplicates && Find(Handle) != Handles.end()) {
54a303c417SDimitry Andric if (CanClose)
55a303c417SDimitry Andric DLClose(Handle);
56a303c417SDimitry Andric return false;
57a303c417SDimitry Andric }
58a303c417SDimitry Andric Handles.push_back(Handle);
59a303c417SDimitry Andric } else {
60eb11fae6SDimitry Andric #ifndef _WIN32
61a303c417SDimitry Andric if (Process) {
62a303c417SDimitry Andric if (CanClose)
63a303c417SDimitry Andric DLClose(Process);
64a303c417SDimitry Andric if (Process == Handle)
65a303c417SDimitry Andric return false;
66a303c417SDimitry Andric }
67a303c417SDimitry Andric #endif
68a303c417SDimitry Andric Process = Handle;
69a303c417SDimitry Andric }
70a303c417SDimitry Andric return true;
71a303c417SDimitry Andric }
72a303c417SDimitry Andric
CloseLibrary(void * Handle)73e3b55780SDimitry Andric void CloseLibrary(void *Handle) {
74e3b55780SDimitry Andric DLClose(Handle);
75e3b55780SDimitry Andric HandleList::iterator it = Find(Handle);
76e3b55780SDimitry Andric if (it != Handles.end()) {
77e3b55780SDimitry Andric Handles.erase(it);
78e3b55780SDimitry Andric }
79e3b55780SDimitry Andric }
80e3b55780SDimitry Andric
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)81ca089b24SDimitry Andric void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
82ca089b24SDimitry Andric if (Order & SO_LoadOrder) {
83ca089b24SDimitry Andric for (void *Handle : Handles) {
84ca089b24SDimitry Andric if (void *Ptr = DLSym(Handle, Symbol))
85ca089b24SDimitry Andric return Ptr;
86ca089b24SDimitry Andric }
87ca089b24SDimitry Andric } else {
88ca089b24SDimitry Andric for (void *Handle : llvm::reverse(Handles)) {
89ca089b24SDimitry Andric if (void *Ptr = DLSym(Handle, Symbol))
90ca089b24SDimitry Andric return Ptr;
91ca089b24SDimitry Andric }
92ca089b24SDimitry Andric }
93ca089b24SDimitry Andric return nullptr;
94ca089b24SDimitry Andric }
95ca089b24SDimitry Andric
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)96ca089b24SDimitry Andric void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
97ca089b24SDimitry Andric assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
98ca089b24SDimitry Andric "Invalid Ordering");
99ca089b24SDimitry Andric
100ca089b24SDimitry Andric if (!Process || (Order & SO_LoadedFirst)) {
101ca089b24SDimitry Andric if (void *Ptr = LibLookup(Symbol, Order))
102ca089b24SDimitry Andric return Ptr;
103ca089b24SDimitry Andric }
104a303c417SDimitry Andric if (Process) {
105ca089b24SDimitry Andric // Use OS facilities to search the current binary and all loaded libs.
106a303c417SDimitry Andric if (void *Ptr = DLSym(Process, Symbol))
107a303c417SDimitry Andric return Ptr;
108ca089b24SDimitry Andric
109ca089b24SDimitry Andric // Search any libs that might have been skipped because of RTLD_LOCAL.
110ca089b24SDimitry Andric if (Order & SO_LoadedLast) {
111ca089b24SDimitry Andric if (void *Ptr = LibLookup(Symbol, Order))
112a303c417SDimitry Andric return Ptr;
113a303c417SDimitry Andric }
114a303c417SDimitry Andric }
115a303c417SDimitry Andric return nullptr;
116a303c417SDimitry Andric }
117a303c417SDimitry Andric };
118a303c417SDimitry Andric
119a303c417SDimitry Andric namespace {
120e3b55780SDimitry Andric
121e3b55780SDimitry Andric struct Globals {
122e3b55780SDimitry Andric // Collection of symbol name/value pairs to be searched prior to any
123e3b55780SDimitry Andric // libraries.
124e3b55780SDimitry Andric llvm::StringMap<void *> ExplicitSymbols;
125e3b55780SDimitry Andric // Collections of known library handles.
126e3b55780SDimitry Andric DynamicLibrary::HandleSet OpenedHandles;
127e3b55780SDimitry Andric DynamicLibrary::HandleSet OpenedTemporaryHandles;
128e3b55780SDimitry Andric // Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles.
129e3b55780SDimitry Andric llvm::sys::SmartMutex<true> SymbolsMutex;
130e3b55780SDimitry Andric };
131e3b55780SDimitry Andric
getGlobals()132e3b55780SDimitry Andric Globals &getGlobals() {
133e3b55780SDimitry Andric static Globals G;
134e3b55780SDimitry Andric return G;
135e3b55780SDimitry Andric }
136e3b55780SDimitry Andric
137344a3780SDimitry Andric } // namespace
13830815c53SDimitry Andric
139eb11fae6SDimitry Andric #ifdef _WIN32
140cf099d11SDimitry Andric
141cf099d11SDimitry Andric #include "Windows/DynamicLibrary.inc"
142cf099d11SDimitry Andric
143cf099d11SDimitry Andric #else
144cf099d11SDimitry Andric
145a303c417SDimitry Andric #include "Unix/DynamicLibrary.inc"
14630815c53SDimitry Andric
147cf099d11SDimitry Andric #endif
148cf099d11SDimitry Andric
149a303c417SDimitry Andric char DynamicLibrary::Invalid;
150ca089b24SDimitry Andric DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
151ca089b24SDimitry Andric DynamicLibrary::SO_Linker;
152a303c417SDimitry Andric
153cf099d11SDimitry Andric namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)154a303c417SDimitry Andric void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
155a303c417SDimitry Andric return DoSearch(SymbolName); // DynamicLibrary.inc
156a303c417SDimitry Andric }
157344a3780SDimitry Andric } // namespace llvm
158cf099d11SDimitry Andric
AddSymbol(StringRef SymbolName,void * SymbolValue)159a303c417SDimitry Andric void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
160e3b55780SDimitry Andric auto &G = getGlobals();
161e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
162e3b55780SDimitry Andric G.ExplicitSymbols[SymbolName] = SymbolValue;
163a303c417SDimitry Andric }
164a303c417SDimitry Andric
getPermanentLibrary(const char * FileName,std::string * Err)165a303c417SDimitry Andric DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
166a303c417SDimitry Andric std::string *Err) {
167e3b55780SDimitry Andric auto &G = getGlobals();
168a303c417SDimitry Andric void *Handle = HandleSet::DLOpen(FileName, Err);
169ab44ce3dSDimitry Andric if (Handle != &Invalid) {
170e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
171e3b55780SDimitry Andric G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
172ab44ce3dSDimitry Andric }
173a303c417SDimitry Andric
174a303c417SDimitry Andric return DynamicLibrary(Handle);
175a303c417SDimitry Andric }
176a303c417SDimitry Andric
addPermanentLibrary(void * Handle,std::string * Err)177a303c417SDimitry Andric DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
178a303c417SDimitry Andric std::string *Err) {
179e3b55780SDimitry Andric auto &G = getGlobals();
180e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
181a303c417SDimitry Andric // If we've already loaded this library, tell the caller.
182e3b55780SDimitry Andric if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false,
183e3b55780SDimitry Andric /*CanClose*/ false))
184a303c417SDimitry Andric *Err = "Library already loaded";
185a303c417SDimitry Andric
186a303c417SDimitry Andric return DynamicLibrary(Handle);
187a303c417SDimitry Andric }
188a303c417SDimitry Andric
getLibrary(const char * FileName,std::string * Err)189e3b55780SDimitry Andric DynamicLibrary DynamicLibrary::getLibrary(const char *FileName,
190e3b55780SDimitry Andric std::string *Err) {
191e3b55780SDimitry Andric assert(FileName && "Use getPermanentLibrary() for opening process handle");
192e3b55780SDimitry Andric void *Handle = HandleSet::DLOpen(FileName, Err);
193e3b55780SDimitry Andric if (Handle != &Invalid) {
194e3b55780SDimitry Andric auto &G = getGlobals();
195e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
196e3b55780SDimitry Andric G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false,
197e3b55780SDimitry Andric /*CanClose*/ false,
198e3b55780SDimitry Andric /*AllowDuplicates*/ true);
199e3b55780SDimitry Andric }
200e3b55780SDimitry Andric return DynamicLibrary(Handle);
201e3b55780SDimitry Andric }
202e3b55780SDimitry Andric
closeLibrary(DynamicLibrary & Lib)203e3b55780SDimitry Andric void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) {
204e3b55780SDimitry Andric auto &G = getGlobals();
205e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
206e3b55780SDimitry Andric if (Lib.isValid()) {
207e3b55780SDimitry Andric G.OpenedTemporaryHandles.CloseLibrary(Lib.Data);
208e3b55780SDimitry Andric Lib.Data = &Invalid;
209e3b55780SDimitry Andric }
210e3b55780SDimitry Andric }
211e3b55780SDimitry Andric
getAddressOfSymbol(const char * SymbolName)212a303c417SDimitry Andric void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
213a303c417SDimitry Andric if (!isValid())
214a303c417SDimitry Andric return nullptr;
215a303c417SDimitry Andric return HandleSet::DLSym(Data, SymbolName);
216a303c417SDimitry Andric }
217a303c417SDimitry Andric
SearchForAddressOfSymbol(const char * SymbolName)218a303c417SDimitry Andric void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
219a303c417SDimitry Andric {
220e3b55780SDimitry Andric auto &G = getGlobals();
221e3b55780SDimitry Andric SmartScopedLock<true> Lock(G.SymbolsMutex);
22230815c53SDimitry Andric
223cf099d11SDimitry Andric // First check symbols added via AddSymbol().
224e3b55780SDimitry Andric StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName);
225cf099d11SDimitry Andric
226e3b55780SDimitry Andric if (i != G.ExplicitSymbols.end())
22730815c53SDimitry Andric return i->second;
228cf099d11SDimitry Andric
229cf099d11SDimitry Andric // Now search the libraries.
230e3b55780SDimitry Andric if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder))
231a303c417SDimitry Andric return Ptr;
232e3b55780SDimitry Andric if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder))
233e3b55780SDimitry Andric return Ptr;
234cf099d11SDimitry Andric }
235cf099d11SDimitry Andric
236a303c417SDimitry Andric return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
237a303c417SDimitry Andric }
238f8af5cf6SDimitry Andric
239f8af5cf6SDimitry Andric //===----------------------------------------------------------------------===//
240f8af5cf6SDimitry Andric // C API.
241f8af5cf6SDimitry Andric //===----------------------------------------------------------------------===//
242f8af5cf6SDimitry Andric
LLVMLoadLibraryPermanently(const char * Filename)243f8af5cf6SDimitry Andric LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
244f8af5cf6SDimitry Andric return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
245f8af5cf6SDimitry Andric }
24685d8b2bbSDimitry Andric
LLVMSearchForAddressOfSymbol(const char * symbolName)24785d8b2bbSDimitry Andric void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
24885d8b2bbSDimitry Andric return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
24985d8b2bbSDimitry Andric }
25085d8b2bbSDimitry Andric
LLVMAddSymbol(const char * symbolName,void * symbolValue)25185d8b2bbSDimitry Andric void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
25285d8b2bbSDimitry Andric return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
25385d8b2bbSDimitry Andric }
254