diff options
Diffstat (limited to 'lib/Support/DynamicLibrary.cpp')
| -rw-r--r-- | lib/Support/DynamicLibrary.cpp | 237 | 
1 files changed, 116 insertions, 121 deletions
diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp index 22fb3f2cb9c93..1541a5726302e 100644 --- a/lib/Support/DynamicLibrary.cpp +++ b/lib/Support/DynamicLibrary.cpp @@ -20,169 +20,164 @@  #include "llvm/Support/Mutex.h"  #include <cstdio>  #include <cstring> +#include <vector> -// Collection of symbol name/value pairs to be searched prior to any libraries. -static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols; -static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex; - -void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName, -                                          void *symbolValue) { -  SmartScopedLock<true> lock(*SymbolsMutex); -  (*ExplicitSymbols)[symbolName] = symbolValue; -} - -char llvm::sys::DynamicLibrary::Invalid = 0; - -#ifdef LLVM_ON_WIN32 - -#include "Windows/DynamicLibrary.inc" - -#else - -#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) -#include <dlfcn.h>  using namespace llvm;  using namespace llvm::sys; -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//===          independent code. -//===----------------------------------------------------------------------===// +// All methods for HandleSet should be used holding SymbolsMutex. +class DynamicLibrary::HandleSet { +  typedef std::vector<void *> HandleList; +  HandleList Handles; +  void *Process; -static llvm::ManagedStatic<DenseSet<void *> > OpenedHandles; +public: +  static void *DLOpen(const char *Filename, std::string *Err); +  static void DLClose(void *Handle); +  static void *DLSym(void *Handle, const char *Symbol); -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, -                                                   std::string *errMsg) { -  SmartScopedLock<true> lock(*SymbolsMutex); +  HandleSet() : Process(nullptr) {} +  ~HandleSet(); -  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL); -  if (!handle) { -    if (errMsg) *errMsg = dlerror(); -    return DynamicLibrary(); +  HandleList::iterator Find(void *Handle) { +    return std::find(Handles.begin(), Handles.end(), Handle);    } -#ifdef __CYGWIN__ -  // Cygwin searches symbols only in the main -  // with the handle of dlopen(NULL, RTLD_GLOBAL). -  if (!filename) -    handle = RTLD_DEFAULT; -#endif +  bool Contains(void *Handle) { +    return Handle == Process || Find(Handle) != Handles.end(); +  } -  // If we've already loaded this library, dlclose() the handle in order to -  // keep the internal refcount at +1. -  if (!OpenedHandles->insert(handle).second) -    dlclose(handle); +  bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { +#ifdef LLVM_ON_WIN32 +    assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); +#endif -  return DynamicLibrary(handle); -} +    if (LLVM_LIKELY(!IsProcess)) { +      if (Find(Handle) != Handles.end()) { +        if (CanClose) +          DLClose(Handle); +        return false; +      } +      Handles.push_back(Handle); +    } else { +#ifndef LLVM_ON_WIN32 +      if (Process) { +        if (CanClose) +          DLClose(Process); +        if (Process == Handle) +          return false; +      } +#endif +      Process = Handle; +    } +    return true; +  } -DynamicLibrary DynamicLibrary::addPermanentLibrary(void *handle, -                                                   std::string *errMsg) { -  SmartScopedLock<true> lock(*SymbolsMutex); -  // If we've already loaded this library, tell the caller. -  if (!OpenedHandles->insert(handle).second) { -    if (errMsg) *errMsg = "Library already loaded"; -    return DynamicLibrary(); +  void *Lookup(const char *Symbol) { +    // Process handle gets first try. +    if (Process) { +      if (void *Ptr = DLSym(Process, Symbol)) +        return Ptr; +#ifndef NDEBUG +      for (void *Handle : Handles) +        assert(!DLSym(Handle, Symbol) && "Symbol exists in non process handle"); +#endif +    } else { +      // Iterate in reverse, so newer libraries/symbols override older. +      for (auto &&I = Handles.rbegin(), E = Handles.rend(); I != E; ++I) { +        if (void *Ptr = DLSym(*I, Symbol)) +          return Ptr; +      } +    } +    return nullptr;    } +}; -  return DynamicLibrary(handle); +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;  } -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { -  if (!isValid()) -    return nullptr; -  return dlsym(Data, symbolName); -} +#ifdef LLVM_ON_WIN32 + +#include "Windows/DynamicLibrary.inc"  #else -using namespace llvm; -using namespace llvm::sys; +#include "Unix/DynamicLibrary.inc" + +#endif -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, -                                                   std::string *errMsg) { -  if (errMsg) *errMsg = "dlopen() not supported on this platform"; -  return DynamicLibrary(); +char DynamicLibrary::Invalid; + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { +  return DoSearch(SymbolName); // DynamicLibrary.inc +}  } -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { -  return NULL; +void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { +  SmartScopedLock<true> Lock(*SymbolsMutex); +  (*ExplicitSymbols)[SymbolName] = SymbolValue;  } -#endif +DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, +                                                   std::string *Err) { +  SmartScopedLock<true> Lock(*SymbolsMutex); +  void *Handle = HandleSet::DLOpen(FileName, Err); +  if (Handle != &Invalid) +    OpenedHandles->AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); -namespace llvm { -void *SearchForAddressOfSpecialSymbol(const char* symbolName); +  return DynamicLibrary(Handle);  } -void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { +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"; -  // First check symbols added via AddSymbol(). -  if (ExplicitSymbols.isConstructed()) { -    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); +  return DynamicLibrary(Handle); +} -    if (i != ExplicitSymbols->end()) -      return i->second; -  } +void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { +  if (!isValid()) +    return nullptr; +  return HandleSet::DLSym(Data, SymbolName); +} -#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) -  // Now search the libraries. -  if (OpenedHandles.isConstructed()) { -    for (DenseSet<void *>::iterator I = OpenedHandles->begin(), -         E = OpenedHandles->end(); I != E; ++I) { -      //lt_ptr ptr = lt_dlsym(*I, symbolName); -      void *ptr = dlsym(*I, symbolName); -      if (ptr) { -        return ptr; -      } -    } -  } -#endif +void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { +  { +    SmartScopedLock<true> Lock(*SymbolsMutex); -  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) -    return Result; +    // First check symbols added via AddSymbol(). +    if (ExplicitSymbols.isConstructed()) { +      StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName); -// This macro returns the address of a well-known, explicit symbol -#define EXPLICIT_SYMBOL(SYM) \ -   if (!strcmp(symbolName, #SYM)) return &SYM +      if (i != ExplicitSymbols->end()) +        return i->second; +    } -// On linux we have a weird situation. The stderr/out/in symbols are both -// macros and global variables because of standards requirements. So, we -// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. -#if defined(__linux__) and !defined(__ANDROID__) -  { -    EXPLICIT_SYMBOL(stderr); -    EXPLICIT_SYMBOL(stdout); -    EXPLICIT_SYMBOL(stdin); -  } -#else -  // For everything else, we want to check to make sure the symbol isn't defined -  // as a macro before using EXPLICIT_SYMBOL. -  { -#ifndef stdin -    EXPLICIT_SYMBOL(stdin); -#endif -#ifndef stdout -    EXPLICIT_SYMBOL(stdout); -#endif -#ifndef stderr -    EXPLICIT_SYMBOL(stderr); -#endif +    // Now search the libraries. +    if (OpenedHandles.isConstructed()) { +      if (void *Ptr = OpenedHandles->Lookup(SymbolName)) +        return Ptr; +    }    } -#endif -#undef EXPLICIT_SYMBOL -  return nullptr; +  return llvm::SearchForAddressOfSpecialSymbol(SymbolName);  } -#endif // LLVM_ON_WIN32 -  //===----------------------------------------------------------------------===//  // C API.  //===----------------------------------------------------------------------===// -LLVMBool LLVMLoadLibraryPermanently(const char* Filename) { +LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {    return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);  }  | 
