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//
12226633Sdim// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13218885Sdim//
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim
16249423Sdim#include "llvm/Support/DynamicLibrary.h"
17249423Sdim#include "llvm/ADT/DenseSet.h"
18226633Sdim#include "llvm/ADT/StringMap.h"
19249423Sdim#include "llvm/Config/config.h"
20218885Sdim#include "llvm/Support/Mutex.h"
21218885Sdim#include <cstdio>
22218885Sdim#include <cstring>
23218885Sdim
24218885Sdim// Collection of symbol name/value pairs to be searched prior to any libraries.
25226633Sdimstatic llvm::StringMap<void *> *ExplicitSymbols = 0;
26218885Sdim
27218885Sdimnamespace {
28218885Sdim
29218885Sdimstruct ExplicitSymbolsDeleter {
30218885Sdim  ~ExplicitSymbolsDeleter() {
31226633Sdim    delete ExplicitSymbols;
32218885Sdim  }
33218885Sdim};
34218885Sdim
35218885Sdim}
36218885Sdim
37218885Sdimstatic ExplicitSymbolsDeleter Dummy;
38218885Sdim
39226633Sdim
40226633Sdimstatic llvm::sys::SmartMutex<true>& getMutex() {
41226633Sdim  static llvm::sys::SmartMutex<true> HandlesMutex;
42226633Sdim  return HandlesMutex;
43226633Sdim}
44226633Sdim
45226633Sdimvoid llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
46218885Sdim                                          void *symbolValue) {
47226633Sdim  SmartScopedLock<true> lock(getMutex());
48218885Sdim  if (ExplicitSymbols == 0)
49249423Sdim    ExplicitSymbols = new StringMap<void*>();
50218885Sdim  (*ExplicitSymbols)[symbolName] = symbolValue;
51218885Sdim}
52218885Sdim
53226633Sdimchar llvm::sys::DynamicLibrary::Invalid = 0;
54226633Sdim
55218885Sdim#ifdef LLVM_ON_WIN32
56218885Sdim
57218885Sdim#include "Windows/DynamicLibrary.inc"
58218885Sdim
59218885Sdim#else
60218885Sdim
61218885Sdim#if HAVE_DLFCN_H
62218885Sdim#include <dlfcn.h>
63218885Sdimusing namespace llvm;
64218885Sdimusing namespace llvm::sys;
65218885Sdim
66218885Sdim//===----------------------------------------------------------------------===//
67218885Sdim//=== WARNING: Implementation here must contain only TRULY operating system
68218885Sdim//===          independent code.
69218885Sdim//===----------------------------------------------------------------------===//
70218885Sdim
71226633Sdimstatic DenseSet<void *> *OpenedHandles = 0;
72218885Sdim
73226633SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
74226633Sdim                                                   std::string *errMsg) {
75226633Sdim  SmartScopedLock<true> lock(getMutex());
76218885Sdim
77226633Sdim  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
78226633Sdim  if (handle == 0) {
79226633Sdim    if (errMsg) *errMsg = dlerror();
80226633Sdim    return DynamicLibrary();
81226633Sdim  }
82218885Sdim
83218885Sdim#ifdef __CYGWIN__
84218885Sdim  // Cygwin searches symbols only in the main
85218885Sdim  // with the handle of dlopen(NULL, RTLD_GLOBAL).
86226633Sdim  if (filename == NULL)
87226633Sdim    handle = RTLD_DEFAULT;
88218885Sdim#endif
89226633Sdim
90218885Sdim  if (OpenedHandles == 0)
91226633Sdim    OpenedHandles = new DenseSet<void *>();
92226633Sdim
93226633Sdim  // If we've already loaded this library, dlclose() the handle in order to
94226633Sdim  // keep the internal refcount at +1.
95226633Sdim  if (!OpenedHandles->insert(handle).second)
96226633Sdim    dlclose(handle);
97226633Sdim
98226633Sdim  return DynamicLibrary(handle);
99218885Sdim}
100226633Sdim
101226633Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
102226633Sdim  if (!isValid())
103226633Sdim    return NULL;
104226633Sdim  return dlsym(Data, symbolName);
105226633Sdim}
106226633Sdim
107218885Sdim#else
108218885Sdim
109218885Sdimusing namespace llvm;
110218885Sdimusing namespace llvm::sys;
111218885Sdim
112226633SdimDynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
113226633Sdim                                                   std::string *errMsg) {
114226633Sdim  if (errMsg) *errMsg = "dlopen() not supported on this platform";
115226633Sdim  return DynamicLibrary();
116218885Sdim}
117226633Sdim
118226633Sdimvoid *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
119226633Sdim  return NULL;
120226633Sdim}
121226633Sdim
122218885Sdim#endif
123218885Sdim
124218885Sdimnamespace llvm {
125218885Sdimvoid *SearchForAddressOfSpecialSymbol(const char* symbolName);
126218885Sdim}
127218885Sdim
128226633Sdimvoid* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
129226633Sdim  SmartScopedLock<true> Lock(getMutex());
130226633Sdim
131218885Sdim  // First check symbols added via AddSymbol().
132218885Sdim  if (ExplicitSymbols) {
133226633Sdim    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
134218885Sdim
135226633Sdim    if (i != ExplicitSymbols->end())
136226633Sdim      return i->second;
137218885Sdim  }
138218885Sdim
139218885Sdim#if HAVE_DLFCN_H
140218885Sdim  // Now search the libraries.
141218885Sdim  if (OpenedHandles) {
142226633Sdim    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
143218885Sdim         E = OpenedHandles->end(); I != E; ++I) {
144218885Sdim      //lt_ptr ptr = lt_dlsym(*I, symbolName);
145218885Sdim      void *ptr = dlsym(*I, symbolName);
146218885Sdim      if (ptr) {
147218885Sdim        return ptr;
148218885Sdim      }
149218885Sdim    }
150218885Sdim  }
151218885Sdim#endif
152218885Sdim
153218885Sdim  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
154218885Sdim    return Result;
155218885Sdim
156218885Sdim// This macro returns the address of a well-known, explicit symbol
157218885Sdim#define EXPLICIT_SYMBOL(SYM) \
158218885Sdim   if (!strcmp(symbolName, #SYM)) return &SYM
159218885Sdim
160218885Sdim// On linux we have a weird situation. The stderr/out/in symbols are both
161218885Sdim// macros and global variables because of standards requirements. So, we
162218885Sdim// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
163243830Sdim#if defined(__linux__) and !defined(__ANDROID__)
164218885Sdim  {
165218885Sdim    EXPLICIT_SYMBOL(stderr);
166218885Sdim    EXPLICIT_SYMBOL(stdout);
167218885Sdim    EXPLICIT_SYMBOL(stdin);
168218885Sdim  }
169218885Sdim#else
170218885Sdim  // For everything else, we want to check to make sure the symbol isn't defined
171218885Sdim  // as a macro before using EXPLICIT_SYMBOL.
172218885Sdim  {
173218885Sdim#ifndef stdin
174218885Sdim    EXPLICIT_SYMBOL(stdin);
175218885Sdim#endif
176218885Sdim#ifndef stdout
177218885Sdim    EXPLICIT_SYMBOL(stdout);
178218885Sdim#endif
179218885Sdim#ifndef stderr
180218885Sdim    EXPLICIT_SYMBOL(stderr);
181218885Sdim#endif
182218885Sdim  }
183218885Sdim#endif
184218885Sdim#undef EXPLICIT_SYMBOL
185218885Sdim
186218885Sdim  return 0;
187218885Sdim}
188218885Sdim
189218885Sdim#endif // LLVM_ON_WIN32
190