xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file implements the operating system DynamicLibrary concept.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
140b57cec5SDimitry Andric #include "llvm-c/Support.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
170b57cec5SDimitry Andric #include "llvm/Config/config.h"
180b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
190b57cec5SDimitry Andric #include <vector>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace llvm::sys;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric // All methods for HandleSet should be used holding SymbolsMutex.
250b57cec5SDimitry Andric class DynamicLibrary::HandleSet {
260b57cec5SDimitry Andric   typedef std::vector<void *> HandleList;
270b57cec5SDimitry Andric   HandleList Handles;
2881ad6265SDimitry Andric   void *Process = nullptr;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric   static void *DLOpen(const char *Filename, std::string *Err);
320b57cec5SDimitry Andric   static void DLClose(void *Handle);
330b57cec5SDimitry Andric   static void *DLSym(void *Handle, const char *Symbol);
340b57cec5SDimitry Andric 
3581ad6265SDimitry Andric   HandleSet() = default;
360b57cec5SDimitry Andric   ~HandleSet();
370b57cec5SDimitry Andric 
Find(void * Handle)38e8d8bef9SDimitry Andric   HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
390b57cec5SDimitry Andric 
Contains(void * Handle)400b57cec5SDimitry Andric   bool Contains(void *Handle) {
410b57cec5SDimitry Andric     return Handle == Process || Find(Handle) != Handles.end();
420b57cec5SDimitry Andric   }
430b57cec5SDimitry Andric 
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true,bool AllowDuplicates=false)44*bdd1243dSDimitry Andric   bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true,
45*bdd1243dSDimitry Andric                   bool AllowDuplicates = false) {
460b57cec5SDimitry Andric #ifdef _WIN32
470b57cec5SDimitry Andric     assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
480b57cec5SDimitry Andric #endif
49*bdd1243dSDimitry Andric     assert((!AllowDuplicates || !CanClose) &&
50*bdd1243dSDimitry Andric            "CanClose must be false if AllowDuplicates is true.");
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric     if (LLVM_LIKELY(!IsProcess)) {
53*bdd1243dSDimitry Andric       if (!AllowDuplicates && Find(Handle) != Handles.end()) {
540b57cec5SDimitry Andric         if (CanClose)
550b57cec5SDimitry Andric           DLClose(Handle);
560b57cec5SDimitry Andric         return false;
570b57cec5SDimitry Andric       }
580b57cec5SDimitry Andric       Handles.push_back(Handle);
590b57cec5SDimitry Andric     } else {
600b57cec5SDimitry Andric #ifndef _WIN32
610b57cec5SDimitry Andric       if (Process) {
620b57cec5SDimitry Andric         if (CanClose)
630b57cec5SDimitry Andric           DLClose(Process);
640b57cec5SDimitry Andric         if (Process == Handle)
650b57cec5SDimitry Andric           return false;
660b57cec5SDimitry Andric       }
670b57cec5SDimitry Andric #endif
680b57cec5SDimitry Andric       Process = Handle;
690b57cec5SDimitry Andric     }
700b57cec5SDimitry Andric     return true;
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
CloseLibrary(void * Handle)73*bdd1243dSDimitry Andric   void CloseLibrary(void *Handle) {
74*bdd1243dSDimitry Andric     DLClose(Handle);
75*bdd1243dSDimitry Andric     HandleList::iterator it = Find(Handle);
76*bdd1243dSDimitry Andric     if (it != Handles.end()) {
77*bdd1243dSDimitry Andric       Handles.erase(it);
78*bdd1243dSDimitry Andric     }
79*bdd1243dSDimitry Andric   }
80*bdd1243dSDimitry Andric 
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)810b57cec5SDimitry Andric   void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
820b57cec5SDimitry Andric     if (Order & SO_LoadOrder) {
830b57cec5SDimitry Andric       for (void *Handle : Handles) {
840b57cec5SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
850b57cec5SDimitry Andric           return Ptr;
860b57cec5SDimitry Andric       }
870b57cec5SDimitry Andric     } else {
880b57cec5SDimitry Andric       for (void *Handle : llvm::reverse(Handles)) {
890b57cec5SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
900b57cec5SDimitry Andric           return Ptr;
910b57cec5SDimitry Andric       }
920b57cec5SDimitry Andric     }
930b57cec5SDimitry Andric     return nullptr;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric 
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)960b57cec5SDimitry Andric   void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
970b57cec5SDimitry Andric     assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
980b57cec5SDimitry Andric            "Invalid Ordering");
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric     if (!Process || (Order & SO_LoadedFirst)) {
1010b57cec5SDimitry Andric       if (void *Ptr = LibLookup(Symbol, Order))
1020b57cec5SDimitry Andric         return Ptr;
1030b57cec5SDimitry Andric     }
1040b57cec5SDimitry Andric     if (Process) {
1050b57cec5SDimitry Andric       // Use OS facilities to search the current binary and all loaded libs.
1060b57cec5SDimitry Andric       if (void *Ptr = DLSym(Process, Symbol))
1070b57cec5SDimitry Andric         return Ptr;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric       // Search any libs that might have been skipped because of RTLD_LOCAL.
1100b57cec5SDimitry Andric       if (Order & SO_LoadedLast) {
1110b57cec5SDimitry Andric         if (void *Ptr = LibLookup(Symbol, Order))
1120b57cec5SDimitry Andric           return Ptr;
1130b57cec5SDimitry Andric       }
1140b57cec5SDimitry Andric     }
1150b57cec5SDimitry Andric     return nullptr;
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric };
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric namespace {
120*bdd1243dSDimitry Andric 
121*bdd1243dSDimitry Andric struct Globals {
122*bdd1243dSDimitry Andric   // Collection of symbol name/value pairs to be searched prior to any
123*bdd1243dSDimitry Andric   // libraries.
124*bdd1243dSDimitry Andric   llvm::StringMap<void *> ExplicitSymbols;
125*bdd1243dSDimitry Andric   // Collections of known library handles.
126*bdd1243dSDimitry Andric   DynamicLibrary::HandleSet OpenedHandles;
127*bdd1243dSDimitry Andric   DynamicLibrary::HandleSet OpenedTemporaryHandles;
128*bdd1243dSDimitry Andric   // Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles.
129*bdd1243dSDimitry Andric   llvm::sys::SmartMutex<true> SymbolsMutex;
130*bdd1243dSDimitry Andric };
131*bdd1243dSDimitry Andric 
getGlobals()132*bdd1243dSDimitry Andric Globals &getGlobals() {
133*bdd1243dSDimitry Andric   static Globals G;
134*bdd1243dSDimitry Andric   return G;
135*bdd1243dSDimitry Andric }
136*bdd1243dSDimitry Andric 
137fe6060f1SDimitry Andric } // namespace
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric #ifdef _WIN32
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric #include "Windows/DynamicLibrary.inc"
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric #else
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric #include "Unix/DynamicLibrary.inc"
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric #endif
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric char DynamicLibrary::Invalid;
1500b57cec5SDimitry Andric DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
1510b57cec5SDimitry Andric     DynamicLibrary::SO_Linker;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)1540b57cec5SDimitry Andric void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
1550b57cec5SDimitry Andric   return DoSearch(SymbolName); // DynamicLibrary.inc
1560b57cec5SDimitry Andric }
157fe6060f1SDimitry Andric } // namespace llvm
1580b57cec5SDimitry Andric 
AddSymbol(StringRef SymbolName,void * SymbolValue)1590b57cec5SDimitry Andric void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
160*bdd1243dSDimitry Andric   auto &G = getGlobals();
161*bdd1243dSDimitry Andric   SmartScopedLock<true> Lock(G.SymbolsMutex);
162*bdd1243dSDimitry Andric   G.ExplicitSymbols[SymbolName] = SymbolValue;
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
getPermanentLibrary(const char * FileName,std::string * Err)1650b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
1660b57cec5SDimitry Andric                                                    std::string *Err) {
167*bdd1243dSDimitry Andric   auto &G = getGlobals();
1680b57cec5SDimitry Andric   void *Handle = HandleSet::DLOpen(FileName, Err);
1690b57cec5SDimitry Andric   if (Handle != &Invalid) {
170*bdd1243dSDimitry Andric     SmartScopedLock<true> Lock(G.SymbolsMutex);
171*bdd1243dSDimitry Andric     G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   return DynamicLibrary(Handle);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
addPermanentLibrary(void * Handle,std::string * Err)1770b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
1780b57cec5SDimitry Andric                                                    std::string *Err) {
179*bdd1243dSDimitry Andric   auto &G = getGlobals();
180*bdd1243dSDimitry Andric   SmartScopedLock<true> Lock(G.SymbolsMutex);
1810b57cec5SDimitry Andric   // If we've already loaded this library, tell the caller.
182*bdd1243dSDimitry Andric   if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false,
183*bdd1243dSDimitry Andric                                   /*CanClose*/ false))
1840b57cec5SDimitry Andric     *Err = "Library already loaded";
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   return DynamicLibrary(Handle);
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
getLibrary(const char * FileName,std::string * Err)189*bdd1243dSDimitry Andric DynamicLibrary DynamicLibrary::getLibrary(const char *FileName,
190*bdd1243dSDimitry Andric                                           std::string *Err) {
191*bdd1243dSDimitry Andric   assert(FileName && "Use getPermanentLibrary() for opening process handle");
192*bdd1243dSDimitry Andric   void *Handle = HandleSet::DLOpen(FileName, Err);
193*bdd1243dSDimitry Andric   if (Handle != &Invalid) {
194*bdd1243dSDimitry Andric     auto &G = getGlobals();
195*bdd1243dSDimitry Andric     SmartScopedLock<true> Lock(G.SymbolsMutex);
196*bdd1243dSDimitry Andric     G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false,
197*bdd1243dSDimitry Andric                                         /*CanClose*/ false,
198*bdd1243dSDimitry Andric                                         /*AllowDuplicates*/ true);
199*bdd1243dSDimitry Andric   }
200*bdd1243dSDimitry Andric   return DynamicLibrary(Handle);
201*bdd1243dSDimitry Andric }
202*bdd1243dSDimitry Andric 
closeLibrary(DynamicLibrary & Lib)203*bdd1243dSDimitry Andric void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) {
204*bdd1243dSDimitry Andric   auto &G = getGlobals();
205*bdd1243dSDimitry Andric   SmartScopedLock<true> Lock(G.SymbolsMutex);
206*bdd1243dSDimitry Andric   if (Lib.isValid()) {
207*bdd1243dSDimitry Andric     G.OpenedTemporaryHandles.CloseLibrary(Lib.Data);
208*bdd1243dSDimitry Andric     Lib.Data = &Invalid;
209*bdd1243dSDimitry Andric   }
210*bdd1243dSDimitry Andric }
211*bdd1243dSDimitry Andric 
getAddressOfSymbol(const char * SymbolName)2120b57cec5SDimitry Andric void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
2130b57cec5SDimitry Andric   if (!isValid())
2140b57cec5SDimitry Andric     return nullptr;
2150b57cec5SDimitry Andric   return HandleSet::DLSym(Data, SymbolName);
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric 
SearchForAddressOfSymbol(const char * SymbolName)2180b57cec5SDimitry Andric void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
2190b57cec5SDimitry Andric   {
220*bdd1243dSDimitry Andric     auto &G = getGlobals();
221*bdd1243dSDimitry Andric     SmartScopedLock<true> Lock(G.SymbolsMutex);
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     // First check symbols added via AddSymbol().
224*bdd1243dSDimitry Andric     StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName);
2250b57cec5SDimitry Andric 
226*bdd1243dSDimitry Andric     if (i != G.ExplicitSymbols.end())
2270b57cec5SDimitry Andric       return i->second;
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric     // Now search the libraries.
230*bdd1243dSDimitry Andric     if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder))
2310b57cec5SDimitry Andric       return Ptr;
232*bdd1243dSDimitry Andric     if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder))
233*bdd1243dSDimitry Andric       return Ptr;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2400b57cec5SDimitry Andric // C API.
2410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2420b57cec5SDimitry Andric 
LLVMLoadLibraryPermanently(const char * Filename)2430b57cec5SDimitry Andric LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
2440b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric 
LLVMSearchForAddressOfSymbol(const char * symbolName)2470b57cec5SDimitry Andric void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
2480b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
LLVMAddSymbol(const char * symbolName,void * symbolValue)2510b57cec5SDimitry Andric void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
2520b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
2530b57cec5SDimitry Andric }
254