Home | History | Annotate | Line # | Download | only in Support
      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/DenseSet.h"
     16 #include "llvm/ADT/STLExtras.h"
     17 #include "llvm/ADT/StringMap.h"
     18 #include "llvm/Config/config.h"
     19 #include "llvm/Support/ManagedStatic.h"
     20 #include "llvm/Support/Mutex.h"
     21 #include <cstdio>
     22 #include <cstring>
     23 #include <vector>
     24 
     25 using namespace llvm;
     26 using namespace llvm::sys;
     27 
     28 // All methods for HandleSet should be used holding SymbolsMutex.
     29 class DynamicLibrary::HandleSet {
     30   typedef std::vector<void *> HandleList;
     31   HandleList Handles;
     32   void *Process;
     33 
     34 public:
     35   static void *DLOpen(const char *Filename, std::string *Err);
     36   static void DLClose(void *Handle);
     37   static void *DLSym(void *Handle, const char *Symbol);
     38 
     39   HandleSet() : Process(nullptr) {}
     40   ~HandleSet();
     41 
     42   HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }
     43 
     44   bool Contains(void *Handle) {
     45     return Handle == Process || Find(Handle) != Handles.end();
     46   }
     47 
     48   bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
     49 #ifdef _WIN32
     50     assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
     51 #endif
     52 
     53     if (LLVM_LIKELY(!IsProcess)) {
     54       if (Find(Handle) != Handles.end()) {
     55         if (CanClose)
     56           DLClose(Handle);
     57         return false;
     58       }
     59       Handles.push_back(Handle);
     60     } else {
     61 #ifndef _WIN32
     62       if (Process) {
     63         if (CanClose)
     64           DLClose(Process);
     65         if (Process == Handle)
     66           return false;
     67       }
     68 #endif
     69       Process = Handle;
     70     }
     71     return true;
     72   }
     73 
     74   void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
     75     if (Order & SO_LoadOrder) {
     76       for (void *Handle : Handles) {
     77         if (void *Ptr = DLSym(Handle, Symbol))
     78           return Ptr;
     79       }
     80     } else {
     81       for (void *Handle : llvm::reverse(Handles)) {
     82         if (void *Ptr = DLSym(Handle, Symbol))
     83           return Ptr;
     84       }
     85     }
     86     return nullptr;
     87   }
     88 
     89   void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
     90     assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
     91            "Invalid Ordering");
     92 
     93     if (!Process || (Order & SO_LoadedFirst)) {
     94       if (void *Ptr = LibLookup(Symbol, Order))
     95         return Ptr;
     96     }
     97     if (Process) {
     98       // Use OS facilities to search the current binary and all loaded libs.
     99       if (void *Ptr = DLSym(Process, Symbol))
    100         return Ptr;
    101 
    102       // Search any libs that might have been skipped because of RTLD_LOCAL.
    103       if (Order & SO_LoadedLast) {
    104         if (void *Ptr = LibLookup(Symbol, Order))
    105           return Ptr;
    106       }
    107     }
    108     return nullptr;
    109   }
    110 };
    111 
    112 namespace {
    113 // Collection of symbol name/value pairs to be searched prior to any libraries.
    114 static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
    115 // Collection of known library handles.
    116 static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
    117 // Lock for ExplicitSymbols and OpenedHandles.
    118 static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
    119 } // namespace
    120 
    121 #ifdef _WIN32
    122 
    123 #include "Windows/DynamicLibrary.inc"
    124 
    125 #else
    126 
    127 #include "Unix/DynamicLibrary.inc"
    128 
    129 #endif
    130 
    131 char DynamicLibrary::Invalid;
    132 DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
    133     DynamicLibrary::SO_Linker;
    134 
    135 namespace llvm {
    136 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
    137   return DoSearch(SymbolName); // DynamicLibrary.inc
    138 }
    139 } // namespace llvm
    140 
    141 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
    142   SmartScopedLock<true> Lock(*SymbolsMutex);
    143   (*ExplicitSymbols)[SymbolName] = SymbolValue;
    144 }
    145 
    146 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
    147                                                    std::string *Err) {
    148   // Force OpenedHandles to be added into the ManagedStatic list before any
    149   // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
    150   HandleSet& HS = *OpenedHandles;
    151 
    152   void *Handle = HandleSet::DLOpen(FileName, Err);
    153   if (Handle != &Invalid) {
    154     SmartScopedLock<true> Lock(*SymbolsMutex);
    155     HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
    156   }
    157 
    158   return DynamicLibrary(Handle);
    159 }
    160 
    161 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
    162                                                    std::string *Err) {
    163   SmartScopedLock<true> Lock(*SymbolsMutex);
    164   // If we've already loaded this library, tell the caller.
    165   if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
    166     *Err = "Library already loaded";
    167 
    168   return DynamicLibrary(Handle);
    169 }
    170 
    171 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
    172   if (!isValid())
    173     return nullptr;
    174   return HandleSet::DLSym(Data, SymbolName);
    175 }
    176 
    177 void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
    178   {
    179     SmartScopedLock<true> Lock(*SymbolsMutex);
    180 
    181     // First check symbols added via AddSymbol().
    182     if (ExplicitSymbols.isConstructed()) {
    183       StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
    184 
    185       if (i != ExplicitSymbols->end())
    186         return i->second;
    187     }
    188 
    189     // Now search the libraries.
    190     if (OpenedHandles.isConstructed()) {
    191       if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
    192         return Ptr;
    193     }
    194   }
    195 
    196   return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
    197 }
    198 
    199 //===----------------------------------------------------------------------===//
    200 // C API.
    201 //===----------------------------------------------------------------------===//
    202 
    203 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
    204   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
    205 }
    206 
    207 void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
    208   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
    209 }
    210 
    211 void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
    212   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
    213 }
    214