xref: /src/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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