1//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This header file implements the operating system DynamicLibrary concept.
11//
12// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/Support/DynamicLibrary.h"
17#include "llvm/ADT/DenseSet.h"
18#include "llvm/ADT/StringMap.h"
19#include "llvm/Config/config.h"
20#include "llvm/Support/Mutex.h"
21#include <cstdio>
22#include <cstring>
23
24// Collection of symbol name/value pairs to be searched prior to any libraries.
25static llvm::StringMap<void *> *ExplicitSymbols = 0;
26
27namespace {
28
29struct ExplicitSymbolsDeleter {
30  ~ExplicitSymbolsDeleter() {
31    delete ExplicitSymbols;
32  }
33};
34
35}
36
37static ExplicitSymbolsDeleter Dummy;
38
39
40static llvm::sys::SmartMutex<true>& getMutex() {
41  static llvm::sys::SmartMutex<true> HandlesMutex;
42  return HandlesMutex;
43}
44
45void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
46                                          void *symbolValue) {
47  SmartScopedLock<true> lock(getMutex());
48  if (ExplicitSymbols == 0)
49    ExplicitSymbols = new StringMap<void*>();
50  (*ExplicitSymbols)[symbolName] = symbolValue;
51}
52
53char llvm::sys::DynamicLibrary::Invalid = 0;
54
55#ifdef LLVM_ON_WIN32
56
57#include "Windows/DynamicLibrary.inc"
58
59#else
60
61#if HAVE_DLFCN_H
62#include <dlfcn.h>
63using namespace llvm;
64using namespace llvm::sys;
65
66//===----------------------------------------------------------------------===//
67//=== WARNING: Implementation here must contain only TRULY operating system
68//===          independent code.
69//===----------------------------------------------------------------------===//
70
71static DenseSet<void *> *OpenedHandles = 0;
72
73DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
74                                                   std::string *errMsg) {
75  SmartScopedLock<true> lock(getMutex());
76
77  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
78  if (handle == 0) {
79    if (errMsg) *errMsg = dlerror();
80    return DynamicLibrary();
81  }
82
83#ifdef __CYGWIN__
84  // Cygwin searches symbols only in the main
85  // with the handle of dlopen(NULL, RTLD_GLOBAL).
86  if (filename == NULL)
87    handle = RTLD_DEFAULT;
88#endif
89
90  if (OpenedHandles == 0)
91    OpenedHandles = new DenseSet<void *>();
92
93  // If we've already loaded this library, dlclose() the handle in order to
94  // keep the internal refcount at +1.
95  if (!OpenedHandles->insert(handle).second)
96    dlclose(handle);
97
98  return DynamicLibrary(handle);
99}
100
101void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
102  if (!isValid())
103    return NULL;
104  return dlsym(Data, symbolName);
105}
106
107#else
108
109using namespace llvm;
110using namespace llvm::sys;
111
112DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
113                                                   std::string *errMsg) {
114  if (errMsg) *errMsg = "dlopen() not supported on this platform";
115  return DynamicLibrary();
116}
117
118void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
119  return NULL;
120}
121
122#endif
123
124namespace llvm {
125void *SearchForAddressOfSpecialSymbol(const char* symbolName);
126}
127
128void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
129  SmartScopedLock<true> Lock(getMutex());
130
131  // First check symbols added via AddSymbol().
132  if (ExplicitSymbols) {
133    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
134
135    if (i != ExplicitSymbols->end())
136      return i->second;
137  }
138
139#if HAVE_DLFCN_H
140  // Now search the libraries.
141  if (OpenedHandles) {
142    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
143         E = OpenedHandles->end(); I != E; ++I) {
144      //lt_ptr ptr = lt_dlsym(*I, symbolName);
145      void *ptr = dlsym(*I, symbolName);
146      if (ptr) {
147        return ptr;
148      }
149    }
150  }
151#endif
152
153  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
154    return Result;
155
156// This macro returns the address of a well-known, explicit symbol
157#define EXPLICIT_SYMBOL(SYM) \
158   if (!strcmp(symbolName, #SYM)) return &SYM
159
160// On linux we have a weird situation. The stderr/out/in symbols are both
161// macros and global variables because of standards requirements. So, we
162// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
163#if defined(__linux__) and !defined(__ANDROID__)
164  {
165    EXPLICIT_SYMBOL(stderr);
166    EXPLICIT_SYMBOL(stdout);
167    EXPLICIT_SYMBOL(stdin);
168  }
169#else
170  // For everything else, we want to check to make sure the symbol isn't defined
171  // as a macro before using EXPLICIT_SYMBOL.
172  {
173#ifndef stdin
174    EXPLICIT_SYMBOL(stdin);
175#endif
176#ifndef stdout
177    EXPLICIT_SYMBOL(stdout);
178#endif
179#ifndef stderr
180    EXPLICIT_SYMBOL(stderr);
181#endif
182  }
183#endif
184#undef EXPLICIT_SYMBOL
185
186  return 0;
187}
188
189#endif // LLVM_ON_WIN32
190