1447762daSMichael J. Spencer //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2447762daSMichael J. Spencer //
3447762daSMichael J. Spencer //                     The LLVM Compiler Infrastructure
4447762daSMichael J. Spencer //
5447762daSMichael J. Spencer // This file is distributed under the University of Illinois Open Source
6447762daSMichael J. Spencer // License. See LICENSE.TXT for details.
7447762daSMichael J. Spencer //
8447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
9447762daSMichael J. Spencer //
10447762daSMichael J. Spencer //  This header file implements the operating system DynamicLibrary concept.
11447762daSMichael J. Spencer //
12*a19917daSJordy Rose // FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13447762daSMichael J. Spencer //
14447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
15447762daSMichael J. Spencer 
16*a19917daSJordy Rose #include "llvm/ADT/StringMap.h"
17*a19917daSJordy Rose #include "llvm/ADT/DenseSet.h"
18447762daSMichael J. Spencer #include "llvm/Support/DynamicLibrary.h"
19447762daSMichael J. Spencer #include "llvm/Support/Mutex.h"
20447762daSMichael J. Spencer #include "llvm/Config/config.h"
21447762daSMichael J. Spencer #include <cstdio>
22447762daSMichael J. Spencer #include <cstring>
23447762daSMichael J. Spencer 
24447762daSMichael J. Spencer // Collection of symbol name/value pairs to be searched prior to any libraries.
25*a19917daSJordy Rose static llvm::StringMap<void *> *ExplicitSymbols = 0;
26447762daSMichael J. Spencer 
27447762daSMichael J. Spencer namespace {
28447762daSMichael J. Spencer 
29447762daSMichael J. Spencer struct ExplicitSymbolsDeleter {
30447762daSMichael J. Spencer   ~ExplicitSymbolsDeleter() {
31447762daSMichael J. Spencer     delete ExplicitSymbols;
32447762daSMichael J. Spencer   }
33447762daSMichael J. Spencer };
34447762daSMichael J. Spencer 
35447762daSMichael J. Spencer }
36447762daSMichael J. Spencer 
37447762daSMichael J. Spencer static ExplicitSymbolsDeleter Dummy;
38447762daSMichael J. Spencer 
39*a19917daSJordy Rose 
40*a19917daSJordy Rose static llvm::sys::SmartMutex<true>& getMutex() {
41*a19917daSJordy Rose   static llvm::sys::SmartMutex<true> HandlesMutex;
42*a19917daSJordy Rose   return HandlesMutex;
43*a19917daSJordy Rose }
44*a19917daSJordy Rose 
45*a19917daSJordy Rose void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
46447762daSMichael J. Spencer                                           void *symbolValue) {
47*a19917daSJordy Rose   SmartScopedLock<true> lock(getMutex());
48447762daSMichael J. Spencer   if (ExplicitSymbols == 0)
49*a19917daSJordy Rose     ExplicitSymbols = new llvm::StringMap<void*>();
50447762daSMichael J. Spencer   (*ExplicitSymbols)[symbolName] = symbolValue;
51447762daSMichael J. Spencer }
52447762daSMichael J. Spencer 
53447762daSMichael J. Spencer #ifdef LLVM_ON_WIN32
54447762daSMichael J. Spencer 
55447762daSMichael J. Spencer #include "Windows/DynamicLibrary.inc"
56447762daSMichael J. Spencer 
57447762daSMichael J. Spencer #else
58447762daSMichael J. Spencer 
59447762daSMichael J. Spencer #if HAVE_DLFCN_H
60447762daSMichael J. Spencer #include <dlfcn.h>
61447762daSMichael J. Spencer using namespace llvm;
62447762daSMichael J. Spencer using namespace llvm::sys;
63447762daSMichael J. Spencer 
64447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
65447762daSMichael J. Spencer //=== WARNING: Implementation here must contain only TRULY operating system
66447762daSMichael J. Spencer //===          independent code.
67447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
68447762daSMichael J. Spencer 
69*a19917daSJordy Rose static DenseSet<void *> *OpenedHandles = 0;
70447762daSMichael J. Spencer 
71*a19917daSJordy Rose DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
72*a19917daSJordy Rose                                                    std::string *errMsg) {
73*a19917daSJordy Rose   void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
74*a19917daSJordy Rose   if (handle == 0) {
75*a19917daSJordy Rose     if (errMsg) *errMsg = dlerror();
76*a19917daSJordy Rose     return DynamicLibrary();
77447762daSMichael J. Spencer   }
78447762daSMichael J. Spencer 
79447762daSMichael J. Spencer #ifdef __CYGWIN__
80447762daSMichael J. Spencer   // Cygwin searches symbols only in the main
81447762daSMichael J. Spencer   // with the handle of dlopen(NULL, RTLD_GLOBAL).
82*a19917daSJordy Rose   if (filename == NULL)
83*a19917daSJordy Rose     handle = RTLD_DEFAULT;
84447762daSMichael J. Spencer #endif
85*a19917daSJordy Rose 
86*a19917daSJordy Rose   SmartScopedLock<true> lock(getMutex());
87447762daSMichael J. Spencer   if (OpenedHandles == 0)
88*a19917daSJordy Rose     OpenedHandles = new DenseSet<void *>();
89*a19917daSJordy Rose 
90*a19917daSJordy Rose   // If we've already loaded this library, dlclose() the handle in order to
91*a19917daSJordy Rose   // keep the internal refcount at +1.
92*a19917daSJordy Rose   if (!OpenedHandles->insert(handle).second)
93*a19917daSJordy Rose     dlclose(handle);
94*a19917daSJordy Rose 
95*a19917daSJordy Rose   return DynamicLibrary(handle);
96447762daSMichael J. Spencer }
97*a19917daSJordy Rose 
98*a19917daSJordy Rose void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
99*a19917daSJordy Rose   if (!isValid())
100*a19917daSJordy Rose     return NULL;
101*a19917daSJordy Rose   return dlsym(Data, symbolName);
102*a19917daSJordy Rose }
103*a19917daSJordy Rose 
104447762daSMichael J. Spencer #else
105447762daSMichael J. Spencer 
106447762daSMichael J. Spencer using namespace llvm;
107447762daSMichael J. Spencer using namespace llvm::sys;
108447762daSMichael J. Spencer 
109*a19917daSJordy Rose DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
110*a19917daSJordy Rose                                                    std::string *errMsg) {
111*a19917daSJordy Rose   if (errMsg) *errMsg = "dlopen() not supported on this platform";
112*a19917daSJordy Rose   return DynamicLibrary();
113447762daSMichael J. Spencer }
114*a19917daSJordy Rose 
115*a19917daSJordy Rose void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
116*a19917daSJordy Rose   return NULL;
117*a19917daSJordy Rose }
118*a19917daSJordy Rose 
119447762daSMichael J. Spencer #endif
120447762daSMichael J. Spencer 
121447762daSMichael J. Spencer namespace llvm {
122447762daSMichael J. Spencer void *SearchForAddressOfSpecialSymbol(const char* symbolName);
123447762daSMichael J. Spencer }
124447762daSMichael J. Spencer 
125447762daSMichael J. Spencer void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
126*a19917daSJordy Rose   SmartScopedLock<true> Lock(getMutex());
127*a19917daSJordy Rose 
128447762daSMichael J. Spencer   // First check symbols added via AddSymbol().
129447762daSMichael J. Spencer   if (ExplicitSymbols) {
130*a19917daSJordy Rose     StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
131447762daSMichael J. Spencer 
132*a19917daSJordy Rose     if (i != ExplicitSymbols->end())
133*a19917daSJordy Rose       return i->second;
134447762daSMichael J. Spencer   }
135447762daSMichael J. Spencer 
136447762daSMichael J. Spencer #if HAVE_DLFCN_H
137447762daSMichael J. Spencer   // Now search the libraries.
138447762daSMichael J. Spencer   if (OpenedHandles) {
139*a19917daSJordy Rose     for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
140447762daSMichael J. Spencer          E = OpenedHandles->end(); I != E; ++I) {
141447762daSMichael J. Spencer       //lt_ptr ptr = lt_dlsym(*I, symbolName);
142447762daSMichael J. Spencer       void *ptr = dlsym(*I, symbolName);
143447762daSMichael J. Spencer       if (ptr) {
144447762daSMichael J. Spencer         return ptr;
145447762daSMichael J. Spencer       }
146447762daSMichael J. Spencer     }
147447762daSMichael J. Spencer   }
148447762daSMichael J. Spencer #endif
149447762daSMichael J. Spencer 
150447762daSMichael J. Spencer   if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
151447762daSMichael J. Spencer     return Result;
152447762daSMichael J. Spencer 
153447762daSMichael J. Spencer // This macro returns the address of a well-known, explicit symbol
154447762daSMichael J. Spencer #define EXPLICIT_SYMBOL(SYM) \
155447762daSMichael J. Spencer    if (!strcmp(symbolName, #SYM)) return &SYM
156447762daSMichael J. Spencer 
157447762daSMichael J. Spencer // On linux we have a weird situation. The stderr/out/in symbols are both
158447762daSMichael J. Spencer // macros and global variables because of standards requirements. So, we
159447762daSMichael J. Spencer // boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
160447762daSMichael J. Spencer #if defined(__linux__)
161447762daSMichael J. Spencer   {
162447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stderr);
163447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdout);
164447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdin);
165447762daSMichael J. Spencer   }
166447762daSMichael J. Spencer #else
167447762daSMichael J. Spencer   // For everything else, we want to check to make sure the symbol isn't defined
168447762daSMichael J. Spencer   // as a macro before using EXPLICIT_SYMBOL.
169447762daSMichael J. Spencer   {
170447762daSMichael J. Spencer #ifndef stdin
171447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdin);
172447762daSMichael J. Spencer #endif
173447762daSMichael J. Spencer #ifndef stdout
174447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdout);
175447762daSMichael J. Spencer #endif
176447762daSMichael J. Spencer #ifndef stderr
177447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stderr);
178447762daSMichael J. Spencer #endif
179447762daSMichael J. Spencer   }
180447762daSMichael J. Spencer #endif
181447762daSMichael J. Spencer #undef EXPLICIT_SYMBOL
182447762daSMichael J. Spencer 
183447762daSMichael J. Spencer   return 0;
184447762daSMichael J. Spencer }
185447762daSMichael J. Spencer 
186447762daSMichael J. Spencer #endif // LLVM_ON_WIN32
187