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