12754fe60SDimitry Andric //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric //                     The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
1091bc56edSDimitry Andric //  This file implements the operating system DynamicLibrary concept.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric 
142754fe60SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
1591bc56edSDimitry Andric #include "llvm-c/Support.h"
16139f7f9bSDimitry Andric #include "llvm/ADT/DenseSet.h"
17c4394386SDimitry Andric #include "llvm/ADT/STLExtras.h"
18139f7f9bSDimitry Andric #include "llvm/ADT/StringMap.h"
192754fe60SDimitry Andric #include "llvm/Config/config.h"
2091bc56edSDimitry Andric #include "llvm/Support/ManagedStatic.h"
21139f7f9bSDimitry Andric #include "llvm/Support/Mutex.h"
222754fe60SDimitry Andric #include <cstdio>
232754fe60SDimitry Andric #include <cstring>
24f37b6182SDimitry Andric #include <vector>
252754fe60SDimitry Andric 
26f37b6182SDimitry Andric using namespace llvm;
27f37b6182SDimitry Andric using namespace llvm::sys;
286122f3e6SDimitry Andric 
29f37b6182SDimitry Andric // All methods for HandleSet should be used holding SymbolsMutex.
30f37b6182SDimitry Andric class DynamicLibrary::HandleSet {
31f37b6182SDimitry Andric   typedef std::vector<void *> HandleList;
32f37b6182SDimitry Andric   HandleList Handles;
33f37b6182SDimitry Andric   void *Process;
34f37b6182SDimitry Andric 
35f37b6182SDimitry Andric public:
36f37b6182SDimitry Andric   static void *DLOpen(const char *Filename, std::string *Err);
37f37b6182SDimitry Andric   static void DLClose(void *Handle);
38f37b6182SDimitry Andric   static void *DLSym(void *Handle, const char *Symbol);
39f37b6182SDimitry Andric 
HandleSet()40f37b6182SDimitry Andric   HandleSet() : Process(nullptr) {}
41f37b6182SDimitry Andric   ~HandleSet();
42f37b6182SDimitry Andric 
Find(void * Handle)43f37b6182SDimitry Andric   HandleList::iterator Find(void *Handle) {
44f37b6182SDimitry Andric     return std::find(Handles.begin(), Handles.end(), Handle);
452754fe60SDimitry Andric   }
462754fe60SDimitry Andric 
Contains(void * Handle)47f37b6182SDimitry Andric   bool Contains(void *Handle) {
48f37b6182SDimitry Andric     return Handle == Process || Find(Handle) != Handles.end();
49f37b6182SDimitry Andric   }
50f37b6182SDimitry Andric 
AddLibrary(void * Handle,bool IsProcess=false,bool CanClose=true)51f37b6182SDimitry Andric   bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
52*4ba319b5SDimitry Andric #ifdef _WIN32
53f37b6182SDimitry Andric     assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
54f37b6182SDimitry Andric #endif
55f37b6182SDimitry Andric 
56f37b6182SDimitry Andric     if (LLVM_LIKELY(!IsProcess)) {
57f37b6182SDimitry Andric       if (Find(Handle) != Handles.end()) {
58f37b6182SDimitry Andric         if (CanClose)
59f37b6182SDimitry Andric           DLClose(Handle);
60f37b6182SDimitry Andric         return false;
61f37b6182SDimitry Andric       }
62f37b6182SDimitry Andric       Handles.push_back(Handle);
63f37b6182SDimitry Andric     } else {
64*4ba319b5SDimitry Andric #ifndef _WIN32
65f37b6182SDimitry Andric       if (Process) {
66f37b6182SDimitry Andric         if (CanClose)
67f37b6182SDimitry Andric           DLClose(Process);
68f37b6182SDimitry Andric         if (Process == Handle)
69f37b6182SDimitry Andric           return false;
70f37b6182SDimitry Andric       }
71f37b6182SDimitry Andric #endif
72f37b6182SDimitry Andric       Process = Handle;
73f37b6182SDimitry Andric     }
74f37b6182SDimitry Andric     return true;
75f37b6182SDimitry Andric   }
76f37b6182SDimitry Andric 
LibLookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)77c4394386SDimitry Andric   void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
78c4394386SDimitry Andric     if (Order & SO_LoadOrder) {
79c4394386SDimitry Andric       for (void *Handle : Handles) {
80c4394386SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
81c4394386SDimitry Andric           return Ptr;
82c4394386SDimitry Andric       }
83c4394386SDimitry Andric     } else {
84c4394386SDimitry Andric       for (void *Handle : llvm::reverse(Handles)) {
85c4394386SDimitry Andric         if (void *Ptr = DLSym(Handle, Symbol))
86c4394386SDimitry Andric           return Ptr;
87c4394386SDimitry Andric       }
88c4394386SDimitry Andric     }
89c4394386SDimitry Andric     return nullptr;
90c4394386SDimitry Andric   }
91c4394386SDimitry Andric 
Lookup(const char * Symbol,DynamicLibrary::SearchOrdering Order)92c4394386SDimitry Andric   void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
93c4394386SDimitry Andric     assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
94c4394386SDimitry Andric            "Invalid Ordering");
95c4394386SDimitry Andric 
96c4394386SDimitry Andric     if (!Process || (Order & SO_LoadedFirst)) {
97c4394386SDimitry Andric       if (void *Ptr = LibLookup(Symbol, Order))
98c4394386SDimitry Andric         return Ptr;
99c4394386SDimitry Andric     }
100f37b6182SDimitry Andric     if (Process) {
101c4394386SDimitry Andric       // Use OS facilities to search the current binary and all loaded libs.
102f37b6182SDimitry Andric       if (void *Ptr = DLSym(Process, Symbol))
103f37b6182SDimitry Andric         return Ptr;
104c4394386SDimitry Andric 
105c4394386SDimitry Andric       // Search any libs that might have been skipped because of RTLD_LOCAL.
106c4394386SDimitry Andric       if (Order & SO_LoadedLast) {
107c4394386SDimitry Andric         if (void *Ptr = LibLookup(Symbol, Order))
108f37b6182SDimitry Andric           return Ptr;
109f37b6182SDimitry Andric       }
110f37b6182SDimitry Andric     }
111f37b6182SDimitry Andric     return nullptr;
112f37b6182SDimitry Andric   }
113f37b6182SDimitry Andric };
114f37b6182SDimitry Andric 
115f37b6182SDimitry Andric namespace {
116f37b6182SDimitry Andric // Collection of symbol name/value pairs to be searched prior to any libraries.
117f37b6182SDimitry Andric static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
118f37b6182SDimitry Andric // Collection of known library handles.
119f37b6182SDimitry Andric static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
120f37b6182SDimitry Andric // Lock for ExplicitSymbols and OpenedHandles.
121f37b6182SDimitry Andric static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
122f37b6182SDimitry Andric }
1236122f3e6SDimitry Andric 
124*4ba319b5SDimitry Andric #ifdef _WIN32
1252754fe60SDimitry Andric 
1262754fe60SDimitry Andric #include "Windows/DynamicLibrary.inc"
1272754fe60SDimitry Andric 
1282754fe60SDimitry Andric #else
1292754fe60SDimitry Andric 
130f37b6182SDimitry Andric #include "Unix/DynamicLibrary.inc"
1316122f3e6SDimitry Andric 
1322754fe60SDimitry Andric #endif
1332754fe60SDimitry Andric 
134f37b6182SDimitry Andric char DynamicLibrary::Invalid;
135c4394386SDimitry Andric DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
136c4394386SDimitry Andric     DynamicLibrary::SO_Linker;
137f37b6182SDimitry Andric 
1382754fe60SDimitry Andric namespace llvm {
SearchForAddressOfSpecialSymbol(const char * SymbolName)139f37b6182SDimitry Andric void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
140f37b6182SDimitry Andric   return DoSearch(SymbolName); // DynamicLibrary.inc
141f37b6182SDimitry Andric }
1422754fe60SDimitry Andric }
1432754fe60SDimitry Andric 
AddSymbol(StringRef SymbolName,void * SymbolValue)144f37b6182SDimitry Andric void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
145f37b6182SDimitry Andric   SmartScopedLock<true> Lock(*SymbolsMutex);
146f37b6182SDimitry Andric   (*ExplicitSymbols)[SymbolName] = SymbolValue;
147f37b6182SDimitry Andric }
148f37b6182SDimitry Andric 
getPermanentLibrary(const char * FileName,std::string * Err)149f37b6182SDimitry Andric DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
150f37b6182SDimitry Andric                                                    std::string *Err) {
151302affcbSDimitry Andric   // Force OpenedHandles to be added into the ManagedStatic list before any
152302affcbSDimitry Andric   // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
153302affcbSDimitry Andric   HandleSet& HS = *OpenedHandles;
154302affcbSDimitry Andric 
155f37b6182SDimitry Andric   void *Handle = HandleSet::DLOpen(FileName, Err);
156302affcbSDimitry Andric   if (Handle != &Invalid) {
157302affcbSDimitry Andric     SmartScopedLock<true> Lock(*SymbolsMutex);
158302affcbSDimitry Andric     HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
159302affcbSDimitry Andric   }
160f37b6182SDimitry Andric 
161f37b6182SDimitry Andric   return DynamicLibrary(Handle);
162f37b6182SDimitry Andric }
163f37b6182SDimitry Andric 
addPermanentLibrary(void * Handle,std::string * Err)164f37b6182SDimitry Andric DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
165f37b6182SDimitry Andric                                                    std::string *Err) {
166f37b6182SDimitry Andric   SmartScopedLock<true> Lock(*SymbolsMutex);
167f37b6182SDimitry Andric   // If we've already loaded this library, tell the caller.
168f37b6182SDimitry Andric   if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
169f37b6182SDimitry Andric     *Err = "Library already loaded";
170f37b6182SDimitry Andric 
171f37b6182SDimitry Andric   return DynamicLibrary(Handle);
172f37b6182SDimitry Andric }
173f37b6182SDimitry Andric 
getAddressOfSymbol(const char * SymbolName)174f37b6182SDimitry Andric void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
175f37b6182SDimitry Andric   if (!isValid())
176f37b6182SDimitry Andric     return nullptr;
177f37b6182SDimitry Andric   return HandleSet::DLSym(Data, SymbolName);
178f37b6182SDimitry Andric }
179f37b6182SDimitry Andric 
SearchForAddressOfSymbol(const char * SymbolName)180f37b6182SDimitry Andric void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
181f37b6182SDimitry Andric   {
182f785676fSDimitry Andric     SmartScopedLock<true> Lock(*SymbolsMutex);
1836122f3e6SDimitry Andric 
1842754fe60SDimitry Andric     // First check symbols added via AddSymbol().
185f785676fSDimitry Andric     if (ExplicitSymbols.isConstructed()) {
186f37b6182SDimitry Andric       StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
1872754fe60SDimitry Andric 
1886122f3e6SDimitry Andric       if (i != ExplicitSymbols->end())
1896122f3e6SDimitry Andric         return i->second;
1902754fe60SDimitry Andric     }
1912754fe60SDimitry Andric 
1922754fe60SDimitry Andric     // Now search the libraries.
1937a7e6055SDimitry Andric     if (OpenedHandles.isConstructed()) {
194c4394386SDimitry Andric       if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
195f37b6182SDimitry Andric         return Ptr;
1962754fe60SDimitry Andric     }
1972754fe60SDimitry Andric   }
1982754fe60SDimitry Andric 
199f37b6182SDimitry Andric   return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
200f37b6182SDimitry Andric }
201f785676fSDimitry Andric 
202f785676fSDimitry Andric //===----------------------------------------------------------------------===//
203f785676fSDimitry Andric // C API.
204f785676fSDimitry Andric //===----------------------------------------------------------------------===//
205f785676fSDimitry Andric 
LLVMLoadLibraryPermanently(const char * Filename)206f785676fSDimitry Andric LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
207f785676fSDimitry Andric   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
208f785676fSDimitry Andric }
20997bc6c73SDimitry Andric 
LLVMSearchForAddressOfSymbol(const char * symbolName)21097bc6c73SDimitry Andric void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
21197bc6c73SDimitry Andric   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
21297bc6c73SDimitry Andric }
21397bc6c73SDimitry Andric 
LLVMAddSymbol(const char * symbolName,void * symbolValue)21497bc6c73SDimitry Andric void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
21597bc6c73SDimitry Andric   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
21697bc6c73SDimitry Andric }
217