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/DenseSet.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
180b57cec5SDimitry Andric #include "llvm/Config/config.h"
190b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
200b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
210b57cec5SDimitry Andric #include <cstdio>
220b57cec5SDimitry Andric #include <cstring>
230b57cec5SDimitry Andric #include <vector>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric using namespace llvm::sys;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // All methods for HandleSet should be used holding SymbolsMutex.
290b57cec5SDimitry Andric class DynamicLibrary::HandleSet {
300b57cec5SDimitry Andric   typedef std::vector<void *> HandleList;
310b57cec5SDimitry Andric   HandleList Handles;
320b57cec5SDimitry Andric   void *Process;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric public:
350b57cec5SDimitry Andric   static void *DLOpen(const char *Filename, std::string *Err);
360b57cec5SDimitry Andric   static void DLClose(void *Handle);
370b57cec5SDimitry Andric   static void *DLSym(void *Handle, const char *Symbol);
380b57cec5SDimitry Andric 
HandleSet()390b57cec5SDimitry Andric   HandleSet() : Process(nullptr) {}
400b57cec5SDimitry Andric   ~HandleSet();
410b57cec5SDimitry Andric 
Find(void * Handle)42af732203SDimitry Andric   HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
430b57cec5SDimitry Andric 
Contains(void * Handle)440b57cec5SDimitry Andric   bool Contains(void *Handle) {
450b57cec5SDimitry Andric     return Handle == Process || Find(Handle) != Handles.end();
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true)480b57cec5SDimitry Andric   bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
490b57cec5SDimitry Andric #ifdef _WIN32
500b57cec5SDimitry Andric     assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
510b57cec5SDimitry Andric #endif
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric     if (LLVM_LIKELY(!IsProcess)) {
540b57cec5SDimitry Andric       if (Find(Handle) != Handles.end()) {
550b57cec5SDimitry Andric         if (CanClose)
560b57cec5SDimitry Andric           DLClose(Handle);
570b57cec5SDimitry Andric         return false;
580b57cec5SDimitry Andric       }
590b57cec5SDimitry Andric       Handles.push_back(Handle);
600b57cec5SDimitry Andric     } else {
610b57cec5SDimitry Andric #ifndef _WIN32
620b57cec5SDimitry Andric       if (Process) {
630b57cec5SDimitry Andric         if (CanClose)
640b57cec5SDimitry Andric           DLClose(Process);
650b57cec5SDimitry Andric         if (Process == Handle)
660b57cec5SDimitry Andric           return false;
670b57cec5SDimitry Andric       }
680b57cec5SDimitry Andric #endif
690b57cec5SDimitry Andric       Process = Handle;
700b57cec5SDimitry Andric     }
710b57cec5SDimitry Andric     return true;
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)740b57cec5SDimitry Andric   void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
750b57cec5SDimitry Andric     if (Order & SO_LoadOrder) {
760b57cec5SDimitry Andric       for (void *Handle : Handles) {
770b57cec5SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
780b57cec5SDimitry Andric           return Ptr;
790b57cec5SDimitry Andric       }
800b57cec5SDimitry Andric     } else {
810b57cec5SDimitry Andric       for (void *Handle : llvm::reverse(Handles)) {
820b57cec5SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
830b57cec5SDimitry Andric           return Ptr;
840b57cec5SDimitry Andric       }
850b57cec5SDimitry Andric     }
860b57cec5SDimitry Andric     return nullptr;
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)890b57cec5SDimitry Andric   void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
900b57cec5SDimitry Andric     assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
910b57cec5SDimitry Andric            "Invalid Ordering");
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric     if (!Process || (Order & SO_LoadedFirst)) {
940b57cec5SDimitry Andric       if (void *Ptr = LibLookup(Symbol, Order))
950b57cec5SDimitry Andric         return Ptr;
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric     if (Process) {
980b57cec5SDimitry Andric       // Use OS facilities to search the current binary and all loaded libs.
990b57cec5SDimitry Andric       if (void *Ptr = DLSym(Process, Symbol))
1000b57cec5SDimitry Andric         return Ptr;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric       // Search any libs that might have been skipped because of RTLD_LOCAL.
1030b57cec5SDimitry Andric       if (Order & SO_LoadedLast) {
1040b57cec5SDimitry Andric         if (void *Ptr = LibLookup(Symbol, Order))
1050b57cec5SDimitry Andric           return Ptr;
1060b57cec5SDimitry Andric       }
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric     return nullptr;
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric };
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric namespace {
1130b57cec5SDimitry Andric // Collection of symbol name/value pairs to be searched prior to any libraries.
1140b57cec5SDimitry Andric static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
1150b57cec5SDimitry Andric // Collection of known library handles.
1160b57cec5SDimitry Andric static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
1170b57cec5SDimitry Andric // Lock for ExplicitSymbols and OpenedHandles.
1180b57cec5SDimitry Andric static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
119*5f7ddb14SDimitry Andric } // namespace
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric #ifdef _WIN32
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric #include "Windows/DynamicLibrary.inc"
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric #else
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric #include "Unix/DynamicLibrary.inc"
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric #endif
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric char DynamicLibrary::Invalid;
1320b57cec5SDimitry Andric DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
1330b57cec5SDimitry Andric     DynamicLibrary::SO_Linker;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)1360b57cec5SDimitry Andric void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
1370b57cec5SDimitry Andric   return DoSearch(SymbolName); // DynamicLibrary.inc
1380b57cec5SDimitry Andric }
139*5f7ddb14SDimitry Andric } // namespace llvm
1400b57cec5SDimitry Andric 
AddSymbol(StringRef SymbolName,void * SymbolValue)1410b57cec5SDimitry Andric void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
1420b57cec5SDimitry Andric   SmartScopedLock<true> Lock(*SymbolsMutex);
1430b57cec5SDimitry Andric   (*ExplicitSymbols)[SymbolName] = SymbolValue;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
getPermanentLibrary(const char * FileName,std::string * Err)1460b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
1470b57cec5SDimitry Andric                                                    std::string *Err) {
1480b57cec5SDimitry Andric   // Force OpenedHandles to be added into the ManagedStatic list before any
1490b57cec5SDimitry Andric   // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
1500b57cec5SDimitry Andric   HandleSet& HS = *OpenedHandles;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   void *Handle = HandleSet::DLOpen(FileName, Err);
1530b57cec5SDimitry Andric   if (Handle != &Invalid) {
1540b57cec5SDimitry Andric     SmartScopedLock<true> Lock(*SymbolsMutex);
1550b57cec5SDimitry Andric     HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   return DynamicLibrary(Handle);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
addPermanentLibrary(void * Handle,std::string * Err)1610b57cec5SDimitry Andric DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
1620b57cec5SDimitry Andric                                                    std::string *Err) {
1630b57cec5SDimitry Andric   SmartScopedLock<true> Lock(*SymbolsMutex);
1640b57cec5SDimitry Andric   // If we've already loaded this library, tell the caller.
1650b57cec5SDimitry Andric   if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
1660b57cec5SDimitry Andric     *Err = "Library already loaded";
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   return DynamicLibrary(Handle);
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
getAddressOfSymbol(const char * SymbolName)1710b57cec5SDimitry Andric void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
1720b57cec5SDimitry Andric   if (!isValid())
1730b57cec5SDimitry Andric     return nullptr;
1740b57cec5SDimitry Andric   return HandleSet::DLSym(Data, SymbolName);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
SearchForAddressOfSymbol(const char * SymbolName)1770b57cec5SDimitry Andric void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
1780b57cec5SDimitry Andric   {
1790b57cec5SDimitry Andric     SmartScopedLock<true> Lock(*SymbolsMutex);
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric     // First check symbols added via AddSymbol().
1820b57cec5SDimitry Andric     if (ExplicitSymbols.isConstructed()) {
1830b57cec5SDimitry Andric       StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric       if (i != ExplicitSymbols->end())
1860b57cec5SDimitry Andric         return i->second;
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric     // Now search the libraries.
1900b57cec5SDimitry Andric     if (OpenedHandles.isConstructed()) {
1910b57cec5SDimitry Andric       if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
1920b57cec5SDimitry Andric         return Ptr;
1930b57cec5SDimitry Andric     }
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2000b57cec5SDimitry Andric // C API.
2010b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2020b57cec5SDimitry Andric 
LLVMLoadLibraryPermanently(const char * Filename)2030b57cec5SDimitry Andric LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
2040b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
LLVMSearchForAddressOfSymbol(const char * symbolName)2070b57cec5SDimitry Andric void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
2080b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
LLVMAddSymbol(const char * symbolName,void * symbolValue)2110b57cec5SDimitry Andric void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
2120b57cec5SDimitry Andric   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
2130b57cec5SDimitry Andric }
214