Coverage Report

Created: 2024-01-17 10:31

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