1218885Sdim//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10276479Sdim//  This file implements the operating system DynamicLibrary concept.
11218885Sdim//
12226633Sdim// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13218885Sdim//
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim
16249423Sdim#include "llvm/Support/DynamicLibrary.h"
17276479Sdim#include "llvm-c/Support.h"
18249423Sdim#include "llvm/ADT/DenseSet.h"
19226633Sdim#include "llvm/ADT/StringMap.h"
20249423Sdim#include "llvm/Config/config.h"
21276479Sdim#include "llvm/Support/ManagedStatic.h"
22218885Sdim#include "llvm/Support/Mutex.h"
23218885Sdim#include <cstdio>
24218885Sdim#include <cstring>
25218885Sdim
26218885Sdim// Collection of symbol name/value pairs to be searched prior to any libraries.
27261991Sdimstatic llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols;
28261991Sdimstatic llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex;
29218885Sdim
30226633Sdimvoid llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
31218885Sdim                                          void *symbolValue) {
32261991Sdim  SmartScopedLock<true> lock(*SymbolsMutex);
33218885Sdim  (*ExplicitSymbols)[symbolName] = symbolValue;
34218885Sdim}
35218885Sdim
36226633Sdimchar llvm::sys::DynamicLibrary::Invalid = 0;
37226633Sdim
38218885Sdim#ifdef LLVM_ON_WIN32
39218885Sdim
40218885Sdim#include "Windows/DynamicLibrary.inc"
41218885Sdim
42218885Sdim#else
43218885Sdim
44218885Sdim#if HAVE_DLFCN_H
45218885Sdim#include <dlfcn.h>
46218885Sdimusing namespace llvm;
47218885Sdimusing namespace llvm::sys;
48218885Sdim
49218885Sdim//===----------------------------------------------------------------------===//
50218885Sdim//=== WARNING: Implementation here must contain only TRULY operating system
51218885Sdim//===          independent code.
52218885Sdim//===----------------------------------------------------------------------===//
53218885Sdim
54276479Sdimstatic DenseSet<void *> *OpenedHandles = nullptr;
55218885Sdim
56226633SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
57226633Sdim                                                   std::string *errMsg) {
58261991Sdim  SmartScopedLock<true> lock(*SymbolsMutex);
59218885Sdim
60226633Sdim  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
61276479Sdim  if (!handle) {
62226633Sdim    if (errMsg) *errMsg = dlerror();
63226633Sdim    return DynamicLibrary();
64226633Sdim  }
65218885Sdim
66218885Sdim#ifdef __CYGWIN__
67218885Sdim  // Cygwin searches symbols only in the main
68218885Sdim  // with the handle of dlopen(NULL, RTLD_GLOBAL).
69276479Sdim  if (!filename)
70226633Sdim    handle = RTLD_DEFAULT;
71218885Sdim#endif
72226633Sdim
73276479Sdim  if (!OpenedHandles)
74226633Sdim    OpenedHandles = new DenseSet<void *>();
75226633Sdim
76226633Sdim  // If we've already loaded this library, dlclose() the handle in order to
77226633Sdim  // keep the internal refcount at +1.
78226633Sdim  if (!OpenedHandles->insert(handle).second)
79226633Sdim    dlclose(handle);
80226633Sdim
81226633Sdim  return DynamicLibrary(handle);
82218885Sdim}
83226633Sdim
84226633Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
85226633Sdim  if (!isValid())
86276479Sdim    return nullptr;
87226633Sdim  return dlsym(Data, symbolName);
88226633Sdim}
89226633Sdim
90218885Sdim#else
91218885Sdim
92218885Sdimusing namespace llvm;
93218885Sdimusing namespace llvm::sys;
94218885Sdim
95226633SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
96226633Sdim                                                   std::string *errMsg) {
97226633Sdim  if (errMsg) *errMsg = "dlopen() not supported on this platform";
98226633Sdim  return DynamicLibrary();
99218885Sdim}
100226633Sdim
101226633Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
102226633Sdim  return NULL;
103226633Sdim}
104226633Sdim
105218885Sdim#endif
106218885Sdim
107218885Sdimnamespace llvm {
108218885Sdimvoid *SearchForAddressOfSpecialSymbol(const char* symbolName);
109218885Sdim}
110218885Sdim
111226633Sdimvoid* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
112261991Sdim  SmartScopedLock<true> Lock(*SymbolsMutex);
113226633Sdim
114218885Sdim  // First check symbols added via AddSymbol().
115261991Sdim  if (ExplicitSymbols.isConstructed()) {
116226633Sdim    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
117218885Sdim
118226633Sdim    if (i != ExplicitSymbols->end())
119226633Sdim      return i->second;
120218885Sdim  }
121218885Sdim
122218885Sdim#if HAVE_DLFCN_H
123218885Sdim  // Now search the libraries.
124218885Sdim  if (OpenedHandles) {
125226633Sdim    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
126218885Sdim         E = OpenedHandles->end(); I != E; ++I) {
127218885Sdim      //lt_ptr ptr = lt_dlsym(*I, symbolName);
128218885Sdim      void *ptr = dlsym(*I, symbolName);
129218885Sdim      if (ptr) {
130218885Sdim        return ptr;
131218885Sdim      }
132218885Sdim    }
133218885Sdim  }
134218885Sdim#endif
135218885Sdim
136218885Sdim  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
137218885Sdim    return Result;
138218885Sdim
139218885Sdim// This macro returns the address of a well-known, explicit symbol
140218885Sdim#define EXPLICIT_SYMBOL(SYM) \
141218885Sdim   if (!strcmp(symbolName, #SYM)) return &SYM
142218885Sdim
143218885Sdim// On linux we have a weird situation. The stderr/out/in symbols are both
144218885Sdim// macros and global variables because of standards requirements. So, we
145218885Sdim// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
146243830Sdim#if defined(__linux__) and !defined(__ANDROID__)
147218885Sdim  {
148218885Sdim    EXPLICIT_SYMBOL(stderr);
149218885Sdim    EXPLICIT_SYMBOL(stdout);
150218885Sdim    EXPLICIT_SYMBOL(stdin);
151218885Sdim  }
152218885Sdim#else
153218885Sdim  // For everything else, we want to check to make sure the symbol isn't defined
154218885Sdim  // as a macro before using EXPLICIT_SYMBOL.
155218885Sdim  {
156218885Sdim#ifndef stdin
157218885Sdim    EXPLICIT_SYMBOL(stdin);
158218885Sdim#endif
159218885Sdim#ifndef stdout
160218885Sdim    EXPLICIT_SYMBOL(stdout);
161218885Sdim#endif
162218885Sdim#ifndef stderr
163218885Sdim    EXPLICIT_SYMBOL(stderr);
164218885Sdim#endif
165218885Sdim  }
166218885Sdim#endif
167218885Sdim#undef EXPLICIT_SYMBOL
168218885Sdim
169276479Sdim  return nullptr;
170218885Sdim}
171218885Sdim
172218885Sdim#endif // LLVM_ON_WIN32
173261991Sdim
174261991Sdim//===----------------------------------------------------------------------===//
175261991Sdim// C API.
176261991Sdim//===----------------------------------------------------------------------===//
177261991Sdim
178261991SdimLLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
179261991Sdim  return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
180261991Sdim}
181288943Sdim
182288943Sdimvoid *LLVMSearchForAddressOfSymbol(const char *symbolName) {
183288943Sdim  return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
184288943Sdim}
185288943Sdim
186288943Sdimvoid LLVMAddSymbol(const char *symbolName, void *symbolValue) {
187288943Sdim  return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue);
188288943Sdim}
189288943Sdim
190