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//
10218885Sdim//  This header file implements the operating system DynamicLibrary concept.
11218885Sdim//
12226890Sdim// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13218885Sdim//
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim
16252723Sdim#include "llvm/Support/DynamicLibrary.h"
17263509Sdim#include "llvm/Support/ManagedStatic.h"
18252723Sdim#include "llvm/ADT/DenseSet.h"
19226890Sdim#include "llvm/ADT/StringMap.h"
20252723Sdim#include "llvm/Config/config.h"
21218885Sdim#include "llvm/Support/Mutex.h"
22263509Sdim#include "llvm-c/Support.h"
23218885Sdim#include <cstdio>
24218885Sdim#include <cstring>
25218885Sdim
26218885Sdim// Collection of symbol name/value pairs to be searched prior to any libraries.
27263509Sdimstatic llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols;
28263509Sdimstatic llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex;
29218885Sdim
30226890Sdimvoid llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
31218885Sdim                                          void *symbolValue) {
32263509Sdim  SmartScopedLock<true> lock(*SymbolsMutex);
33218885Sdim  (*ExplicitSymbols)[symbolName] = symbolValue;
34218885Sdim}
35218885Sdim
36226890Sdimchar llvm::sys::DynamicLibrary::Invalid = 0;
37226890Sdim
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
54226890Sdimstatic DenseSet<void *> *OpenedHandles = 0;
55218885Sdim
56226890SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
57226890Sdim                                                   std::string *errMsg) {
58263509Sdim  SmartScopedLock<true> lock(*SymbolsMutex);
59218885Sdim
60226890Sdim  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
61226890Sdim  if (handle == 0) {
62226890Sdim    if (errMsg) *errMsg = dlerror();
63226890Sdim    return DynamicLibrary();
64226890Sdim  }
65218885Sdim
66218885Sdim#ifdef __CYGWIN__
67218885Sdim  // Cygwin searches symbols only in the main
68218885Sdim  // with the handle of dlopen(NULL, RTLD_GLOBAL).
69226890Sdim  if (filename == NULL)
70226890Sdim    handle = RTLD_DEFAULT;
71218885Sdim#endif
72226890Sdim
73218885Sdim  if (OpenedHandles == 0)
74226890Sdim    OpenedHandles = new DenseSet<void *>();
75226890Sdim
76226890Sdim  // If we've already loaded this library, dlclose() the handle in order to
77226890Sdim  // keep the internal refcount at +1.
78226890Sdim  if (!OpenedHandles->insert(handle).second)
79226890Sdim    dlclose(handle);
80226890Sdim
81226890Sdim  return DynamicLibrary(handle);
82218885Sdim}
83226890Sdim
84226890Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
85226890Sdim  if (!isValid())
86226890Sdim    return NULL;
87226890Sdim  return dlsym(Data, symbolName);
88226890Sdim}
89226890Sdim
90218885Sdim#else
91218885Sdim
92218885Sdimusing namespace llvm;
93218885Sdimusing namespace llvm::sys;
94218885Sdim
95226890SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
96226890Sdim                                                   std::string *errMsg) {
97226890Sdim  if (errMsg) *errMsg = "dlopen() not supported on this platform";
98226890Sdim  return DynamicLibrary();
99218885Sdim}
100226890Sdim
101226890Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
102226890Sdim  return NULL;
103226890Sdim}
104226890Sdim
105218885Sdim#endif
106218885Sdim
107218885Sdimnamespace llvm {
108218885Sdimvoid *SearchForAddressOfSpecialSymbol(const char* symbolName);
109218885Sdim}
110218885Sdim
111226890Sdimvoid* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
112263509Sdim  SmartScopedLock<true> Lock(*SymbolsMutex);
113226890Sdim
114218885Sdim  // First check symbols added via AddSymbol().
115263509Sdim  if (ExplicitSymbols.isConstructed()) {
116226890Sdim    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
117218885Sdim
118226890Sdim    if (i != ExplicitSymbols->end())
119226890Sdim      return i->second;
120218885Sdim  }
121218885Sdim
122218885Sdim#if HAVE_DLFCN_H
123218885Sdim  // Now search the libraries.
124218885Sdim  if (OpenedHandles) {
125226890Sdim    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.
146245431Sdim#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
169218885Sdim  return 0;
170218885Sdim}
171218885Sdim
172218885Sdim#endif // LLVM_ON_WIN32
173263509Sdim
174263509Sdim//===----------------------------------------------------------------------===//
175263509Sdim// C API.
176263509Sdim//===----------------------------------------------------------------------===//
177263509Sdim
178263509SdimLLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
179263509Sdim  return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
180263509Sdim}
181