text: //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  //  This file implements the operating system DynamicLibrary concept.
  //
  //===----------------------------------------------------------------------===//
  
  #include "llvm/Support/DynamicLibrary.h"
  #include "llvm-c/Support.h"
  #include "llvm/ADT/DenseSet.h"
  #include "llvm/ADT/STLExtras.h"
  #include "llvm/ADT/StringMap.h"
  #include "llvm/Config/config.h"
  #include "llvm/Support/ManagedStatic.h"
  #include "llvm/Support/Mutex.h"
  #include <cstdio>
  #include <cstring>
  #include <vector>
  
  using namespace llvm;
  using namespace llvm::sys;
  
  // All methods for HandleSet should be used holding SymbolsMutex.
  class DynamicLibrary::HandleSet {
    typedef std::vector<void *> HandleList;
    HandleList Handles;
    void *Process;
  
  public:
    static void *DLOpen(const char *Filename, std::string *Err);
    static void DLClose(void *Handle);
    static void *DLSym(void *Handle, const char *Symbol);
  
    HandleSet() : Process(nullptr) {}
    ~HandleSet();
  
    HandleList::iterator Find(void *Handle) {
      return std::find(Handles.begin(), Handles.end(), Handle);
    }
  
    bool Contains(void *Handle) {
      return Handle == Process || Find(Handle) != Handles.end();
    }
  
    bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
  #ifdef _WIN32
      assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
  #endif
  
      if (LLVM_LIKELY(!IsProcess)) {
        if (Find(Handle) != Handles.end()) {
          if (CanClose)
            DLClose(Handle);
          return false;
        }
        Handles.push_back(Handle);
      } else {
  #ifndef _WIN32
        if (Process) {
          if (CanClose)
            DLClose(Process);
          if (Process == Handle)
            return false;
        }
  #endif
        Process = Handle;
      }
      return true;
    }
  
    void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
      if (Order & SO_LoadOrder) {
        for (void *Handle : Handles) {
          if (void *Ptr = DLSym(Handle, Symbol))
            return Ptr;
        }
      } else {
        for (void *Handle : llvm::reverse(Handles)) {
          if (void *Ptr = DLSym(Handle, Symbol))
            return Ptr;
        }
      }
      return nullptr;
    }
  
    void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) {
      assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) &&
             "Invalid Ordering");
  
      if (!Process || (Order & SO_LoadedFirst)) {
        if (void *Ptr = LibLookup(Symbol, Order))
          return Ptr;
      }
      if (Process) {
        // Use OS facilities to search the current binary and all loaded libs.
        if (void *Ptr = DLSym(Process, Symbol))
          return Ptr;
  
        // Search any libs that might have been skipped because of RTLD_LOCAL.
        if (Order & SO_LoadedLast) {
          if (void *Ptr = LibLookup(Symbol, Order))
            return Ptr;
        }
      }
      return nullptr;
    }
  };
  
  namespace {
  // Collection of symbol name/value pairs to be searched prior to any libraries.
  static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols;
  // Collection of known library handles.
  static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
  // Lock for ExplicitSymbols and OpenedHandles.
  static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
  }
  
  #ifdef _WIN32
  
  #include "Windows/DynamicLibrary.inc"
  
  #else
  
  #include "Unix/DynamicLibrary.inc"
  
  #endif
  
  char DynamicLibrary::Invalid;
  DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder =
      DynamicLibrary::SO_Linker;
  
  namespace llvm {
  void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
    return DoSearch(SymbolName); // DynamicLibrary.inc
  }
  }
  
  void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
    SmartScopedLock<true> Lock(*SymbolsMutex);
    (*ExplicitSymbols)[SymbolName] = SymbolValue;
  }
  
  DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
                                                     std::string *Err) {
    // Force OpenedHandles to be added into the ManagedStatic list before any
    // ManagedStatic can be added from static constructors in HandleSet::DLOpen.
    HandleSet& HS = *OpenedHandles;
  
    void *Handle = HandleSet::DLOpen(FileName, Err);
    if (Handle != &Invalid) {
      SmartScopedLock<true> Lock(*SymbolsMutex);
      HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
    }
  
    return DynamicLibrary(Handle);
  }
  
  DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
                                                     std::string *Err) {
    SmartScopedLock<true> Lock(*SymbolsMutex);
    // If we've already loaded this library, tell the caller.
    if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
      *Err = "Library already loaded";
  
    return DynamicLibrary(Handle);
  }
  
  void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
    if (!isValid())
      return nullptr;
    return HandleSet::DLSym(Data, SymbolName);
  }
  
  void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
    {
      SmartScopedLock<true> Lock(*SymbolsMutex);
  
      // First check symbols added via AddSymbol().
      if (ExplicitSymbols.isConstructed()) {
        StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName);
  
        if (i != ExplicitSymbols->end())
          return i->second;
      }
  
      // Now search the libraries.
      if (OpenedHandles.isConstructed()) {
        if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder))
          return Ptr;
      }
    }
  
    return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
  }
  
  //===----------------------------------------------------------------------===//
  // C API.
  //===----------------------------------------------------------------------===//
  
  LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
    return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
  }
  
  void *LLVMSearchForAddressOfSymbol(const char *symbolName) {
    return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  }
  
  void LLVMAddSymbol(const char *symbolName, void *symbolValue) {
    return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
  }
  