Path: blob/main/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp
35232 views
//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the operating system DynamicLibrary concept.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Support/DynamicLibrary.h"13#include "llvm-c/Support.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/StringMap.h"16#include "llvm/Config/config.h"17#include "llvm/Support/Mutex.h"18#include <vector>1920using namespace llvm;21using namespace llvm::sys;2223// All methods for HandleSet should be used holding SymbolsMutex.24class DynamicLibrary::HandleSet {25typedef std::vector<void *> HandleList;26HandleList Handles;27void *Process = nullptr;2829public:30static void *DLOpen(const char *Filename, std::string *Err);31static void DLClose(void *Handle);32static void *DLSym(void *Handle, const char *Symbol);3334HandleSet() = default;35~HandleSet();3637HandleList::iterator Find(void *Handle) { return find(Handles, Handle); }3839bool Contains(void *Handle) {40return Handle == Process || Find(Handle) != Handles.end();41}4243bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true,44bool AllowDuplicates = false) {45#ifdef _WIN3246assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");47#endif48assert((!AllowDuplicates || !CanClose) &&49"CanClose must be false if AllowDuplicates is true.");5051if (LLVM_LIKELY(!IsProcess)) {52if (!AllowDuplicates && Find(Handle) != Handles.end()) {53if (CanClose)54DLClose(Handle);55return false;56}57Handles.push_back(Handle);58} else {59#ifndef _WIN3260if (Process) {61if (CanClose)62DLClose(Process);63if (Process == Handle)64return false;65}66#endif67Process = Handle;68}69return true;70}7172void CloseLibrary(void *Handle) {73DLClose(Handle);74HandleList::iterator it = Find(Handle);75if (it != Handles.end()) {76Handles.erase(it);77}78}7980void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {81if (Order & SO_LoadOrder) {82for (void *Handle : Handles) {83if (void *Ptr = DLSym(Handle, Symbol))84return Ptr;85}86} else {87for (void *Handle : llvm::reverse(Handles)) {88if (void *Ptr = DLSym(Handle, Symbol))89return Ptr;90}91}92return nullptr;93}9495void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {96assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&97"Invalid Ordering");9899if (!Process || (Order & SO_LoadedFirst)) {100if (void *Ptr = LibLookup(Symbol, Order))101return Ptr;102}103if (Process) {104// Use OS facilities to search the current binary and all loaded libs.105if (void *Ptr = DLSym(Process, Symbol))106return Ptr;107108// Search any libs that might have been skipped because of RTLD_LOCAL.109if (Order & SO_LoadedLast) {110if (void *Ptr = LibLookup(Symbol, Order))111return Ptr;112}113}114return nullptr;115}116};117118namespace {119120struct Globals {121// Collection of symbol name/value pairs to be searched prior to any122// libraries.123llvm::StringMap<void *> ExplicitSymbols;124// Collections of known library handles.125DynamicLibrary::HandleSet OpenedHandles;126DynamicLibrary::HandleSet OpenedTemporaryHandles;127// Lock for ExplicitSymbols, OpenedHandles, and OpenedTemporaryHandles.128llvm::sys::SmartMutex<true> SymbolsMutex;129};130131Globals &getGlobals() {132static Globals G;133return G;134}135136} // namespace137138#ifdef _WIN32139140#include "Windows/DynamicLibrary.inc"141142#else143144#include "Unix/DynamicLibrary.inc"145146#endif147148char DynamicLibrary::Invalid;149DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =150DynamicLibrary::SO_Linker;151152namespace llvm {153void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {154return DoSearch(SymbolName); // DynamicLibrary.inc155}156} // namespace llvm157158void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {159auto &G = getGlobals();160SmartScopedLock<true> Lock(G.SymbolsMutex);161G.ExplicitSymbols[SymbolName] = SymbolValue;162}163164DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,165std::string *Err) {166auto &G = getGlobals();167void *Handle = HandleSet::DLOpen(FileName, Err);168if (Handle != &Invalid) {169SmartScopedLock<true> Lock(G.SymbolsMutex);170G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);171}172173return DynamicLibrary(Handle);174}175176DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,177std::string *Err) {178auto &G = getGlobals();179SmartScopedLock<true> Lock(G.SymbolsMutex);180// If we've already loaded this library, tell the caller.181if (!G.OpenedHandles.AddLibrary(Handle, /*IsProcess*/ false,182/*CanClose*/ false))183*Err = "Library already loaded";184185return DynamicLibrary(Handle);186}187188DynamicLibrary DynamicLibrary::getLibrary(const char *FileName,189std::string *Err) {190assert(FileName && "Use getPermanentLibrary() for opening process handle");191void *Handle = HandleSet::DLOpen(FileName, Err);192if (Handle != &Invalid) {193auto &G = getGlobals();194SmartScopedLock<true> Lock(G.SymbolsMutex);195G.OpenedTemporaryHandles.AddLibrary(Handle, /*IsProcess*/ false,196/*CanClose*/ false,197/*AllowDuplicates*/ true);198}199return DynamicLibrary(Handle);200}201202void DynamicLibrary::closeLibrary(DynamicLibrary &Lib) {203auto &G = getGlobals();204SmartScopedLock<true> Lock(G.SymbolsMutex);205if (Lib.isValid()) {206G.OpenedTemporaryHandles.CloseLibrary(Lib.Data);207Lib.Data = &Invalid;208}209}210211void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {212if (!isValid())213return nullptr;214return HandleSet::DLSym(Data, SymbolName);215}216217void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {218{219auto &G = getGlobals();220SmartScopedLock<true> Lock(G.SymbolsMutex);221222// First check symbols added via AddSymbol().223StringMap<void *>::iterator i = G.ExplicitSymbols.find(SymbolName);224225if (i != G.ExplicitSymbols.end())226return i->second;227228// Now search the libraries.229if (void *Ptr = G.OpenedHandles.Lookup(SymbolName, SearchOrder))230return Ptr;231if (void *Ptr = G.OpenedTemporaryHandles.Lookup(SymbolName, SearchOrder))232return Ptr;233}234235return llvm::SearchForAddressOfSpecialSymbol(SymbolName);236}237238//===----------------------------------------------------------------------===//239// C API.240//===----------------------------------------------------------------------===//241242LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {243return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);244}245246void *LLVMSearchForAddressOfSymbol(const char *symbolName) {247return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);248}249250void LLVMAddSymbol(const char *symbolName, void *symbolValue) {251return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);252}253254255