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 //
12a19917daSJordy Rose // FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13447762daSMichael J. Spencer //
14447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
15447762daSMichael J. Spencer 
16a19917daSJordy Rose #include "llvm/ADT/StringMap.h"
17a19917daSJordy 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.
25a19917daSJordy 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 
39a19917daSJordy Rose 
40a19917daSJordy Rose static llvm::sys::SmartMutex<true>& getMutex() {
41a19917daSJordy Rose   static llvm::sys::SmartMutex<true> HandlesMutex;
42a19917daSJordy Rose   return HandlesMutex;
43a19917daSJordy Rose }
44a19917daSJordy Rose 
45a19917daSJordy Rose void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
46447762daSMichael J. Spencer                                           void *symbolValue) {
47a19917daSJordy Rose   SmartScopedLock<true> lock(getMutex());
48447762daSMichael J. Spencer   if (ExplicitSymbols == 0)
49a19917daSJordy Rose     ExplicitSymbols = new llvm::StringMap<void*>();
50447762daSMichael J. Spencer   (*ExplicitSymbols)[symbolName] = symbolValue;
51447762daSMichael J. Spencer }
52447762daSMichael J. Spencer 
53*04bc405aSJordy Rose char llvm::sys::DynamicLibrary::Invalid = 0;
54*04bc405aSJordy Rose 
55447762daSMichael J. Spencer #ifdef LLVM_ON_WIN32
56447762daSMichael J. Spencer 
57447762daSMichael J. Spencer #include "Windows/DynamicLibrary.inc"
58447762daSMichael J. Spencer 
59447762daSMichael J. Spencer #else
60447762daSMichael J. Spencer 
61447762daSMichael J. Spencer #if HAVE_DLFCN_H
62447762daSMichael J. Spencer #include <dlfcn.h>
63447762daSMichael J. Spencer using namespace llvm;
64447762daSMichael J. Spencer using namespace llvm::sys;
65447762daSMichael J. Spencer 
66447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
67447762daSMichael J. Spencer //=== WARNING: Implementation here must contain only TRULY operating system
68447762daSMichael J. Spencer //===          independent code.
69447762daSMichael J. Spencer //===----------------------------------------------------------------------===//
70447762daSMichael J. Spencer 
71a19917daSJordy Rose static DenseSet<void *> *OpenedHandles = 0;
72447762daSMichael J. Spencer 
73a19917daSJordy Rose DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
74a19917daSJordy Rose                                                    std::string *errMsg) {
75a19917daSJordy Rose   void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
76a19917daSJordy Rose   if (handle == 0) {
77a19917daSJordy Rose     if (errMsg) *errMsg = dlerror();
78a19917daSJordy Rose     return DynamicLibrary();
79447762daSMichael J. Spencer   }
80447762daSMichael J. Spencer 
81447762daSMichael J. Spencer #ifdef __CYGWIN__
82447762daSMichael J. Spencer   // Cygwin searches symbols only in the main
83447762daSMichael J. Spencer   // with the handle of dlopen(NULL, RTLD_GLOBAL).
84a19917daSJordy Rose   if (filename == NULL)
85a19917daSJordy Rose     handle = RTLD_DEFAULT;
86447762daSMichael J. Spencer #endif
87a19917daSJordy Rose 
88a19917daSJordy Rose   SmartScopedLock<true> lock(getMutex());
89447762daSMichael J. Spencer   if (OpenedHandles == 0)
90a19917daSJordy Rose     OpenedHandles = new DenseSet<void *>();
91a19917daSJordy Rose 
92a19917daSJordy Rose   // If we've already loaded this library, dlclose() the handle in order to
93a19917daSJordy Rose   // keep the internal refcount at +1.
94a19917daSJordy Rose   if (!OpenedHandles->insert(handle).second)
95a19917daSJordy Rose     dlclose(handle);
96a19917daSJordy Rose 
97a19917daSJordy Rose   return DynamicLibrary(handle);
98447762daSMichael J. Spencer }
99a19917daSJordy Rose 
100a19917daSJordy Rose void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
101a19917daSJordy Rose   if (!isValid())
102a19917daSJordy Rose     return NULL;
103a19917daSJordy Rose   return dlsym(Data, symbolName);
104a19917daSJordy Rose }
105a19917daSJordy Rose 
106447762daSMichael J. Spencer #else
107447762daSMichael J. Spencer 
108447762daSMichael J. Spencer using namespace llvm;
109447762daSMichael J. Spencer using namespace llvm::sys;
110447762daSMichael J. Spencer 
111a19917daSJordy Rose DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
112a19917daSJordy Rose                                                    std::string *errMsg) {
113a19917daSJordy Rose   if (errMsg) *errMsg = "dlopen() not supported on this platform";
114a19917daSJordy Rose   return DynamicLibrary();
115447762daSMichael J. Spencer }
116a19917daSJordy Rose 
117a19917daSJordy Rose void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
118a19917daSJordy Rose   return NULL;
119a19917daSJordy Rose }
120a19917daSJordy Rose 
121447762daSMichael J. Spencer #endif
122447762daSMichael J. Spencer 
123447762daSMichael J. Spencer namespace llvm {
124447762daSMichael J. Spencer void *SearchForAddressOfSpecialSymbol(const char* symbolName);
125447762daSMichael J. Spencer }
126447762daSMichael J. Spencer 
127447762daSMichael J. Spencer void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
128a19917daSJordy Rose   SmartScopedLock<true> Lock(getMutex());
129a19917daSJordy Rose 
130447762daSMichael J. Spencer   // First check symbols added via AddSymbol().
131447762daSMichael J. Spencer   if (ExplicitSymbols) {
132a19917daSJordy Rose     StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
133447762daSMichael J. Spencer 
134a19917daSJordy Rose     if (i != ExplicitSymbols->end())
135a19917daSJordy Rose       return i->second;
136447762daSMichael J. Spencer   }
137447762daSMichael J. Spencer 
138447762daSMichael J. Spencer #if HAVE_DLFCN_H
139447762daSMichael J. Spencer   // Now search the libraries.
140447762daSMichael J. Spencer   if (OpenedHandles) {
141a19917daSJordy Rose     for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
142447762daSMichael J. Spencer          E = OpenedHandles->end(); I != E; ++I) {
143447762daSMichael J. Spencer       //lt_ptr ptr = lt_dlsym(*I, symbolName);
144447762daSMichael J. Spencer       void *ptr = dlsym(*I, symbolName);
145447762daSMichael J. Spencer       if (ptr) {
146447762daSMichael J. Spencer         return ptr;
147447762daSMichael J. Spencer       }
148447762daSMichael J. Spencer     }
149447762daSMichael J. Spencer   }
150447762daSMichael J. Spencer #endif
151447762daSMichael J. Spencer 
152447762daSMichael J. Spencer   if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
153447762daSMichael J. Spencer     return Result;
154447762daSMichael J. Spencer 
155447762daSMichael J. Spencer // This macro returns the address of a well-known, explicit symbol
156447762daSMichael J. Spencer #define EXPLICIT_SYMBOL(SYM) \
157447762daSMichael J. Spencer    if (!strcmp(symbolName, #SYM)) return &SYM
158447762daSMichael J. Spencer 
159447762daSMichael J. Spencer // On linux we have a weird situation. The stderr/out/in symbols are both
160447762daSMichael J. Spencer // macros and global variables because of standards requirements. So, we
161447762daSMichael J. Spencer // boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
162447762daSMichael J. Spencer #if defined(__linux__)
163447762daSMichael J. Spencer   {
164447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stderr);
165447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdout);
166447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdin);
167447762daSMichael J. Spencer   }
168447762daSMichael J. Spencer #else
169447762daSMichael J. Spencer   // For everything else, we want to check to make sure the symbol isn't defined
170447762daSMichael J. Spencer   // as a macro before using EXPLICIT_SYMBOL.
171447762daSMichael J. Spencer   {
172447762daSMichael J. Spencer #ifndef stdin
173447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdin);
174447762daSMichael J. Spencer #endif
175447762daSMichael J. Spencer #ifndef stdout
176447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stdout);
177447762daSMichael J. Spencer #endif
178447762daSMichael J. Spencer #ifndef stderr
179447762daSMichael J. Spencer     EXPLICIT_SYMBOL(stderr);
180447762daSMichael J. Spencer #endif
181447762daSMichael J. Spencer   }
182447762daSMichael J. Spencer #endif
183447762daSMichael J. Spencer #undef EXPLICIT_SYMBOL
184447762daSMichael J. Spencer 
185447762daSMichael J. Spencer   return 0;
186447762daSMichael J. Spencer }
187447762daSMichael J. Spencer 
188447762daSMichael J. Spencer #endif // LLVM_ON_WIN32
189