1447762daSMichael J. Spencer //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2447762daSMichael J. Spencer //
3447762daSMichael J. Spencer //                     The LLVM Compiler Infrastructure
4447762daSMichael J. Spencer //
5447762daSMichael J. Spencer // This file is distributed under the University of Illinois Open Source
6447762daSMichael J. Spencer // License. See LICENSE.TXT for details.
7447762daSMichael J. Spencer //
8447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
9447762daSMichael J. Spencer //
10cfe341f5SHans Wennborg //  This file implements the operating system DynamicLibrary concept.
11447762daSMichael J. Spencer //
12447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
13447762daSMichael J. Spencer 
14447762daSMichael J. Spencer #include "llvm/Support/DynamicLibrary.h"
158a8cd2baSChandler Carruth #include "llvm-c/Support.h"
16ed0881b2SChandler Carruth #include "llvm/ADT/DenseSet.h"
17*5fdd2cbaSFrederich Munch #include "llvm/ADT/STLExtras.h"
18ed0881b2SChandler Carruth #include "llvm/ADT/StringMap.h"
19447762daSMichael J. Spencer #include "llvm/Config/config.h"
208a8cd2baSChandler Carruth #include "llvm/Support/ManagedStatic.h"
21ed0881b2SChandler Carruth #include "llvm/Support/Mutex.h"
22447762daSMichael J. Spencer #include <cstdio>
23447762daSMichael J. Spencer #include <cstring>
24c1db8cf9SFrederich Munch #include <vector>
25447762daSMichael J. Spencer 
26c1db8cf9SFrederich Munch using namespace llvm;
27c1db8cf9SFrederich Munch using namespace llvm::sys;
28fd96d5e1SFrederich Munch 
29c1db8cf9SFrederich Munch // All methods for HandleSet should be used holding SymbolsMutex.
30c1db8cf9SFrederich Munch class DynamicLibrary::HandleSet {
31c1db8cf9SFrederich Munch   typedef std::vector<void *> HandleList;
32c1db8cf9SFrederich Munch   HandleList Handles;
33c1db8cf9SFrederich Munch   void *Process;
34c1db8cf9SFrederich Munch 
35c1db8cf9SFrederich Munch public:
36c1db8cf9SFrederich Munch   static void *DLOpen(const char *Filename, std::string *Err);
37c1db8cf9SFrederich Munch   static void DLClose(void *Handle);
38c1db8cf9SFrederich Munch   static void *DLSym(void *Handle, const char *Symbol);
39c1db8cf9SFrederich Munch 
40c1db8cf9SFrederich Munch   HandleSet() : Process(nullptr) {}
41c1db8cf9SFrederich Munch   ~HandleSet();
42c1db8cf9SFrederich Munch 
43c1db8cf9SFrederich Munch   HandleList::iterator Find(void *Handle) {
44c1db8cf9SFrederich Munch     return std::find(Handles.begin(), Handles.end(), Handle);
4570c377a3SFrederich Munch   }
46b8c236a6SFrederich Munch 
47c1db8cf9SFrederich Munch   bool Contains(void *Handle) {
48c1db8cf9SFrederich Munch     return Handle == Process || Find(Handle) != Handles.end();
49c1db8cf9SFrederich Munch   }
50c1db8cf9SFrederich Munch 
51c1db8cf9SFrederich Munch   bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
52c1db8cf9SFrederich Munch #ifdef LLVM_ON_WIN32
53c1db8cf9SFrederich Munch     assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
54c1db8cf9SFrederich Munch #endif
55c1db8cf9SFrederich Munch 
56c1db8cf9SFrederich Munch     if (LLVM_LIKELY(!IsProcess)) {
57c1db8cf9SFrederich Munch       if (Find(Handle) != Handles.end()) {
58c1db8cf9SFrederich Munch         if (CanClose)
59c1db8cf9SFrederich Munch           DLClose(Handle);
60c1db8cf9SFrederich Munch         return false;
61c1db8cf9SFrederich Munch       }
62c1db8cf9SFrederich Munch       Handles.push_back(Handle);
63c1db8cf9SFrederich Munch     } else {
64c1db8cf9SFrederich Munch #ifndef LLVM_ON_WIN32
65c1db8cf9SFrederich Munch       if (Process) {
66c1db8cf9SFrederich Munch         if (CanClose)
67c1db8cf9SFrederich Munch           DLClose(Process);
68c1db8cf9SFrederich Munch         if (Process == Handle)
69c1db8cf9SFrederich Munch           return false;
70c1db8cf9SFrederich Munch       }
71c1db8cf9SFrederich Munch #endif
72c1db8cf9SFrederich Munch       Process = Handle;
73c1db8cf9SFrederich Munch     }
74c1db8cf9SFrederich Munch     return true;
75c1db8cf9SFrederich Munch   }
76c1db8cf9SFrederich Munch 
77*5fdd2cbaSFrederich Munch   void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
78*5fdd2cbaSFrederich Munch     if (Order & SO_LoadOrder) {
79*5fdd2cbaSFrederich Munch       for (void *Handle : Handles) {
80*5fdd2cbaSFrederich Munch         if (void *Ptr = DLSym(Handle, Symbol))
81*5fdd2cbaSFrederich Munch           return Ptr;
82*5fdd2cbaSFrederich Munch       }
83*5fdd2cbaSFrederich Munch     } else {
84*5fdd2cbaSFrederich Munch       for (void *Handle : llvm::reverse(Handles)) {
85*5fdd2cbaSFrederich Munch         if (void *Ptr = DLSym(Handle, Symbol))
86*5fdd2cbaSFrederich Munch           return Ptr;
87*5fdd2cbaSFrederich Munch       }
88*5fdd2cbaSFrederich Munch     }
89*5fdd2cbaSFrederich Munch     return nullptr;
90*5fdd2cbaSFrederich Munch   }
91*5fdd2cbaSFrederich Munch 
92*5fdd2cbaSFrederich Munch   void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
93*5fdd2cbaSFrederich Munch     assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
94*5fdd2cbaSFrederich Munch            "Invalid Ordering");
95*5fdd2cbaSFrederich Munch 
96*5fdd2cbaSFrederich Munch     if (!Process || (Order & SO_LoadedFirst)) {
97*5fdd2cbaSFrederich Munch       if (void *Ptr = LibLookup(Symbol, Order))
98*5fdd2cbaSFrederich Munch         return Ptr;
99*5fdd2cbaSFrederich Munch     }
100c1db8cf9SFrederich Munch     if (Process) {
101*5fdd2cbaSFrederich Munch       // Use OS facilities to search the current binary and all loaded libs.
102c1db8cf9SFrederich Munch       if (void *Ptr = DLSym(Process, Symbol))
103c1db8cf9SFrederich Munch         return Ptr;
104*5fdd2cbaSFrederich Munch 
105*5fdd2cbaSFrederich Munch       // Search any libs that might have been skipped because of RTLD_LOCAL.
106*5fdd2cbaSFrederich Munch       if (Order & SO_LoadedLast) {
107*5fdd2cbaSFrederich Munch         if (void *Ptr = LibLookup(Symbol, Order))
108c1db8cf9SFrederich Munch           return Ptr;
109c1db8cf9SFrederich Munch       }
110c1db8cf9SFrederich Munch     }
111c1db8cf9SFrederich Munch     return nullptr;
112c1db8cf9SFrederich Munch   }
113c1db8cf9SFrederich Munch };
114c1db8cf9SFrederich Munch 
115c1db8cf9SFrederich Munch namespace {
116c1db8cf9SFrederich Munch // Collection of symbol name/value pairs to be searched prior to any libraries.
117c1db8cf9SFrederich Munch static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
118c1db8cf9SFrederich Munch // Collection of known library handles.
119c1db8cf9SFrederich Munch static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
120c1db8cf9SFrederich Munch // Lock for ExplicitSymbols and OpenedHandles.
121c1db8cf9SFrederich Munch static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
122c1db8cf9SFrederich Munch }
123fd96d5e1SFrederich Munch 
124447762daSMichael J. Spencer #ifdef LLVM_ON_WIN32
125447762daSMichael J. Spencer 
126447762daSMichael J. Spencer #include "Windows/DynamicLibrary.inc"
127447762daSMichael J. Spencer 
128447762daSMichael J. Spencer #else
129447762daSMichael J. Spencer 
130c1db8cf9SFrederich Munch #include "Unix/DynamicLibrary.inc"
131a19917daSJordy Rose 
132447762daSMichael J. Spencer #endif
133447762daSMichael J. Spencer 
134c1db8cf9SFrederich Munch char DynamicLibrary::Invalid;
135*5fdd2cbaSFrederich Munch DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
136*5fdd2cbaSFrederich Munch     DynamicLibrary::SO_Linker;
137c1db8cf9SFrederich Munch 
138447762daSMichael J. Spencer namespace llvm {
139c1db8cf9SFrederich Munch void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
140c1db8cf9SFrederich Munch   return DoSearch(SymbolName); // DynamicLibrary.inc
141c1db8cf9SFrederich Munch }
142447762daSMichael J. Spencer }
143447762daSMichael J. Spencer 
144c1db8cf9SFrederich Munch void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
145c1db8cf9SFrederich Munch   SmartScopedLock<true> Lock(*SymbolsMutex);
146c1db8cf9SFrederich Munch   (*ExplicitSymbols)[SymbolName] = SymbolValue;
147c1db8cf9SFrederich Munch }
148c1db8cf9SFrederich Munch 
149c1db8cf9SFrederich Munch DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
150c1db8cf9SFrederich Munch                                                    std::string *Err) {
1518c3735e5SFrederich Munch   // Force OpenedHandles to be added into the ManagedStatic list before any
1528c3735e5SFrederich Munch   // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
1538c3735e5SFrederich Munch   HandleSet& HS = *OpenedHandles;
1548c3735e5SFrederich Munch 
155c1db8cf9SFrederich Munch   void *Handle = HandleSet::DLOpen(FileName, Err);
1568c3735e5SFrederich Munch   if (Handle != &Invalid) {
1578c3735e5SFrederich Munch     SmartScopedLock<true> Lock(*SymbolsMutex);
1588c3735e5SFrederich Munch     HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
1598c3735e5SFrederich Munch   }
160c1db8cf9SFrederich Munch 
161c1db8cf9SFrederich Munch   return DynamicLibrary(Handle);
162c1db8cf9SFrederich Munch }
163c1db8cf9SFrederich Munch 
164c1db8cf9SFrederich Munch DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
165c1db8cf9SFrederich Munch                                                    std::string *Err) {
166c1db8cf9SFrederich Munch   SmartScopedLock<true> Lock(*SymbolsMutex);
167c1db8cf9SFrederich Munch   // If we've already loaded this library, tell the caller.
168c1db8cf9SFrederich Munch   if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
169c1db8cf9SFrederich Munch     *Err = "Library already loaded";
170c1db8cf9SFrederich Munch 
171c1db8cf9SFrederich Munch   return DynamicLibrary(Handle);
172c1db8cf9SFrederich Munch }
173c1db8cf9SFrederich Munch 
174c1db8cf9SFrederich Munch void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
175c1db8cf9SFrederich Munch   if (!isValid())
176c1db8cf9SFrederich Munch     return nullptr;
177c1db8cf9SFrederich Munch   return HandleSet::DLSym(Data, SymbolName);
178c1db8cf9SFrederich Munch }
179c1db8cf9SFrederich Munch 
180c1db8cf9SFrederich Munch void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
181c1db8cf9SFrederich Munch   {
18257093e88SFilip Pizlo     SmartScopedLock<true> Lock(*SymbolsMutex);
183a19917daSJordy Rose 
184447762daSMichael J. Spencer     // First check symbols added via AddSymbol().
18557093e88SFilip Pizlo     if (ExplicitSymbols.isConstructed()) {
186c1db8cf9SFrederich Munch       StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
187447762daSMichael J. Spencer 
188a19917daSJordy Rose       if (i != ExplicitSymbols->end())
189a19917daSJordy Rose         return i->second;
190447762daSMichael J. Spencer     }
191447762daSMichael J. Spencer 
192447762daSMichael J. Spencer     // Now search the libraries.
19359e5a644SVassil Vassilev     if (OpenedHandles.isConstructed()) {
194*5fdd2cbaSFrederich Munch       if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
195c1db8cf9SFrederich Munch         return Ptr;
196447762daSMichael J. Spencer     }
197447762daSMichael J. Spencer   }
198447762daSMichael J. Spencer 
199c1db8cf9SFrederich Munch   return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
200c1db8cf9SFrederich Munch }
20134ddbf1aSPeter Zotov 
20234ddbf1aSPeter Zotov //===----------------------------------------------------------------------===//
20334ddbf1aSPeter Zotov // C API.
20434ddbf1aSPeter Zotov //===----------------------------------------------------------------------===//
20534ddbf1aSPeter Zotov 
20634ddbf1aSPeter Zotov LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
207671fe2eeSPeter Zotov   return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
20834ddbf1aSPeter Zotov }
209af79f3dbSEli Bendersky 
210af79f3dbSEli Bendersky void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
211af79f3dbSEli Bendersky   return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
212af79f3dbSEli Bendersky }
213af79f3dbSEli Bendersky 
214af79f3dbSEli Bendersky void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
215af79f3dbSEli Bendersky   return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
216af79f3dbSEli Bendersky }
217