llvm.org GIT mirror llvm / 545de00
Refactor DynamicLibrary so searching for a symbol will have a defined order and libraries are properly unloaded when llvm_shutdown is called. Summary: This was mostly affecting usage of the JIT, where storing the library handles in a set made iteration unordered/undefined. This lead to disagreement between the JIT and native code as to what the address and implementation of particularly on Windows with stdlib functions: JIT: putenv_s("TEST", "VALUE") // called msvcrt.dll, putenv_s JIT: getenv("TEST") -> "VALUE" // called msvcrt.dll, getenv Native: getenv("TEST") -> NULL // called ucrt.dll, getenv Also fixed is the issue of DynamicLibrary::getPermanentLibrary(0,0) on Windows not giving priority to the process' symbols as it did on Unix. Reviewers: chapuni, v.g.vassilev, lhames Reviewed By: lhames Subscribers: danalbert, srhines, mgorny, vsk, llvm-commits Differential Revision: https://reviews.llvm.org/D30107 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301153 91177308-0d34-0410-b5e6-96231b3b80d8 Frederich Munch 2 years ago
11 changed file(s) with 604 addition(s) and 308 deletion(s). Raw diff Collapse all Expand all
5757 void *getAddressOfSymbol(const char *symbolName);
5858
5959 /// This function permanently loads the dynamic library at the given path.
60 /// The library will only be unloaded when the program terminates.
60 /// The library will only be unloaded when llvm_shutdown() is called.
6161 /// This returns a valid DynamicLibrary instance on success and an invalid
6262 /// instance on failure (see isValid()). \p *errMsg will only be modified
6363 /// if the library fails to load.
7070 /// Registers an externally loaded library. The library will be unloaded
7171 /// when the program terminates.
7272 ///
73 /// It is safe to call this function multiple times for the same library.
73 /// It is safe to call this function multiple times for the same library,
74 /// though ownership is only taken if there was no error.
7475 ///
7576 /// \returns An empty \p DynamicLibrary if the library was already loaded.
7677 static DynamicLibrary addPermanentLibrary(void *handle,
105106 /// libraries.
106107 /// @brief Add searchable symbol/value pair.
107108 static void AddSymbol(StringRef symbolName, void *symbolValue);
109
110 class HandleSet;
108111 };
109112
110113 } // End sys namespace
129129 Process.cpp
130130 Program.cpp
131131 RWMutex.cpp
132 SearchForAddressOfSpecialSymbol.cpp
133132 Signals.cpp
134133 TargetRegistry.cpp
135134 ThreadLocal.cpp
1919 #include "llvm/Support/Mutex.h"
2020 #include
2121 #include
22 #include
2223
24 using namespace llvm;
25 using namespace llvm::sys;
26
27 // All methods for HandleSet should be used holding SymbolsMutex.
28 class DynamicLibrary::HandleSet {
29 typedef std::vector HandleList;
30 HandleList Handles;
31 void *Process;
32
33 public:
34 static void *DLOpen(const char *Filename, std::string *Err);
35 static void DLClose(void *Handle);
36 static void *DLSym(void *Handle, const char *Symbol);
37
38 HandleSet() : Process(nullptr) {}
39 ~HandleSet();
40
41 HandleList::iterator Find(void *Handle) {
42 return std::find(Handles.begin(), Handles.end(), Handle);
43 }
44
45 bool Contains(void *Handle) {
46 return Handle == Process || Find(Handle) != Handles.end();
47 }
48
49 bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
50 #ifdef LLVM_ON_WIN32
51 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
52 #endif
53
54 if (LLVM_LIKELY(!IsProcess)) {
55 if (Find(Handle) != Handles.end()) {
56 if (CanClose)
57 DLClose(Handle);
58 return false;
59 }
60 Handles.push_back(Handle);
61 } else {
62 #ifndef LLVM_ON_WIN32
63 if (Process) {
64 if (CanClose)
65 DLClose(Process);
66 if (Process == Handle)
67 return false;
68 }
69 #endif
70 Process = Handle;
71 }
72 return true;
73 }
74
75 void *Lookup(const char *Symbol) {
76 // Process handle gets first try.
77 if (Process) {
78 if (void *Ptr = DLSym(Process, Symbol))
79 return Ptr;
80 #ifndef NDEBUG
81 for (void *Handle : Handles)
82 assert(!DLSym(Handle, Symbol) && "Symbol exists in non process handle");
83 #endif
84 } else {
85 // Iterate in reverse, so newer libraries/symbols override older.
86 for (auto &&I = Handles.rbegin(), E = Handles.rend(); I != E; ++I) {
87 if (void *Ptr = DLSym(*I, Symbol))
88 return Ptr;
89 }
90 }
91 return nullptr;
92 }
93 };
94
95 namespace {
2396 // Collection of symbol name/value pairs to be searched prior to any libraries.
24 static llvm::ManagedStatic > ExplicitSymbols;
25 static llvm::ManagedStatic > SymbolsMutex;
26
27 void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
28 void *symbolValue) {
29 SmartScopedLock lock(*SymbolsMutex);
30 (*ExplicitSymbols)[symbolName] = symbolValue;
97 static llvm::ManagedStatic> ExplicitSymbols;
98 // Collection of known library handles.
99 static llvm::ManagedStatic OpenedHandles;
100 // Lock for ExplicitSymbols and OpenedHandles.
101 static llvm::ManagedStatic> SymbolsMutex;
31102 }
32
33 char llvm::sys::DynamicLibrary::Invalid = 0;
34103
35104 #ifdef LLVM_ON_WIN32
36105
38107
39108 #else
40109
41 #if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
42 #include
43 using namespace llvm;
44 using namespace llvm::sys;
45
46 //===----------------------------------------------------------------------===//
47 //=== WARNING: Implementation here must contain only TRULY operating system
48 //=== independent code.
49 //===----------------------------------------------------------------------===//
50
51 static llvm::ManagedStatic > OpenedHandles;
52
53 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
54 std::string *errMsg) {
55 SmartScopedLock lock(*SymbolsMutex);
56
57 void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
58 if (!handle) {
59 if (errMsg) *errMsg = dlerror();
60 return DynamicLibrary();
61 }
62
63 #ifdef __CYGWIN__
64 // Cygwin searches symbols only in the main
65 // with the handle of dlopen(NULL, RTLD_GLOBAL).
66 if (!filename)
67 handle = RTLD_DEFAULT;
68 #endif
69
70 // If we've already loaded this library, dlclose() the handle in order to
71 // keep the internal refcount at +1.
72 if (!OpenedHandles->insert(handle).second)
73 dlclose(handle);
74
75 return DynamicLibrary(handle);
76 }
77
78 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *handle,
79 std::string *errMsg) {
80 SmartScopedLock lock(*SymbolsMutex);
81 // If we've already loaded this library, tell the caller.
82 if (!OpenedHandles->insert(handle).second) {
83 if (errMsg) *errMsg = "Library already loaded";
84 return DynamicLibrary();
85 }
86
87 return DynamicLibrary(handle);
88 }
89
90 void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
91 if (!isValid())
92 return nullptr;
93 return dlsym(Data, symbolName);
94 }
95
96 #else
97
98 using namespace llvm;
99 using namespace llvm::sys;
100
101 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
102 std::string *errMsg) {
103 if (errMsg) *errMsg = "dlopen() not supported on this platform";
104 return DynamicLibrary();
105 }
106
107 void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
108 return NULL;
109 }
110 #include "Unix/DynamicLibrary.inc"
110111
111112 #endif
112113
114 char DynamicLibrary::Invalid;
115
113116 namespace llvm {
114 void *SearchForAddressOfSpecialSymbol(const char* symbolName);
117 void *SearchForAddressOfSpecialSymbol(const char *SymbolName) {
118 return DoSearch(SymbolName); // DynamicLibrary.inc
119 }
115120 }
116121
117 void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
122 void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) {
118123 SmartScopedLock Lock(*SymbolsMutex);
124 (*ExplicitSymbols)[SymbolName] = SymbolValue;
125 }
119126
120 // First check symbols added via AddSymbol().
121 if (ExplicitSymbols.isConstructed()) {
122 StringMap::iterator i = ExplicitSymbols->find(symbolName);
127 DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName,
128 std::string *Err) {
129 SmartScopedLock Lock(*SymbolsMutex);
130 void *Handle = HandleSet::DLOpen(FileName, Err);
131 if (Handle != &Invalid)
132 OpenedHandles->AddLibrary(Handle, /*IsProcess*/ FileName == nullptr);
123133
124 if (i != ExplicitSymbols->end())
125 return i->second;
134 return DynamicLibrary(Handle);
135 }
136
137 DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle,
138 std::string *Err) {
139 SmartScopedLock Lock(*SymbolsMutex);
140 // If we've already loaded this library, tell the caller.
141 if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false))
142 *Err = "Library already loaded";
143
144 return DynamicLibrary(Handle);
145 }
146
147 void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) {
148 if (!isValid())
149 return nullptr;
150 return HandleSet::DLSym(Data, SymbolName);
151 }
152
153 void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) {
154 {
155 SmartScopedLock Lock(*SymbolsMutex);
156
157 // First check symbols added via AddSymbol().
158 if (ExplicitSymbols.isConstructed()) {
159 StringMap::iterator i = ExplicitSymbols->find(SymbolName);
160
161 if (i != ExplicitSymbols->end())
162 return i->second;
163 }
164
165 // Now search the libraries.
166 if (OpenedHandles.isConstructed()) {
167 if (void *Ptr = OpenedHandles->Lookup(SymbolName))
168 return Ptr;
169 }
126170 }
127171
128 #if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
129 // Now search the libraries.
130 if (OpenedHandles.isConstructed()) {
131 for (DenseSet::iterator I = OpenedHandles->begin(),
132 E = OpenedHandles->end(); I != E; ++I) {
133 //lt_ptr ptr = lt_dlsym(*I, symbolName);
134 void *ptr = dlsym(*I, symbolName);
135 if (ptr) {
136 return ptr;
137 }
138 }
139 }
140 #endif
141
142 if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
143 return Result;
144
145 // This macro returns the address of a well-known, explicit symbol
146 #define EXPLICIT_SYMBOL(SYM) \
147 if (!strcmp(symbolName, #SYM)) return &SYM
148
149 // On linux we have a weird situation. The stderr/out/in symbols are both
150 // macros and global variables because of standards requirements. So, we
151 // boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
152 #if defined(__linux__) and !defined(__ANDROID__)
153 {
154 EXPLICIT_SYMBOL(stderr);
155 EXPLICIT_SYMBOL(stdout);
156 EXPLICIT_SYMBOL(stdin);
157 }
158 #else
159 // For everything else, we want to check to make sure the symbol isn't defined
160 // as a macro before using EXPLICIT_SYMBOL.
161 {
162 #ifndef stdin
163 EXPLICIT_SYMBOL(stdin);
164 #endif
165 #ifndef stdout
166 EXPLICIT_SYMBOL(stdout);
167 #endif
168 #ifndef stderr
169 EXPLICIT_SYMBOL(stderr);
170 #endif
171 }
172 #endif
173 #undef EXPLICIT_SYMBOL
174
175 return nullptr;
172 return llvm::SearchForAddressOfSpecialSymbol(SymbolName);
176173 }
177
178 #endif // LLVM_ON_WIN32
179174
180175 //===----------------------------------------------------------------------===//
181176 // C API.
182177 //===----------------------------------------------------------------------===//
183178
184 LLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
179 LLVMBool LLVMLoadLibraryPermanently(const char *Filename) {
185180 return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
186181 }
187182
+0
-58
lib/Support/SearchForAddressOfSpecialSymbol.cpp less more
None //===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file pulls the addresses of certain symbols out of the linker. It must
10 // include as few header files as possible because it declares the symbols as
11 // void*, which would conflict with the actual symbol type if any header
12 // declared it.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include
17
18 // Must declare the symbols in the global namespace.
19 static void *DoSearch(const char* symbolName) {
20 #define EXPLICIT_SYMBOL(SYM) \
21 extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM
22
23 // If this is darwin, it has some funky issues, try to solve them here. Some
24 // important symbols are marked 'private external' which doesn't allow
25 // SearchForAddressOfSymbol to find them. As such, we special case them here,
26 // there is only a small handful of them.
27
28 #ifdef __APPLE__
29 {
30 // __eprintf is sometimes used for assert() handling on x86.
31 //
32 // FIXME: Currently disabled when using Clang, as we don't always have our
33 // runtime support libraries available.
34 #ifndef __clang__
35 #ifdef __i386__
36 EXPLICIT_SYMBOL(__eprintf);
37 #endif
38 #endif
39 }
40 #endif
41
42 #ifdef __CYGWIN__
43 {
44 EXPLICIT_SYMBOL(_alloca);
45 EXPLICIT_SYMBOL(__main);
46 }
47 #endif
48
49 #undef EXPLICIT_SYMBOL
50 return nullptr;
51 }
52
53 namespace llvm {
54 void *SearchForAddressOfSpecialSymbol(const char* symbolName) {
55 return DoSearch(symbolName);
56 }
57 } // namespace llvm
0 //===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides the UNIX specific implementation of DynamicLibrary.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
14 #include
15
16 DynamicLibrary::HandleSet::~HandleSet() {
17 for (void *Handle : Handles)
18 ::dlclose(Handle);
19 if (Process)
20 ::dlclose(Process);
21 }
22
23 void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
24 void *Handle = ::dlopen(File, RTLD_LAZY|RTLD_GLOBAL);
25 if (!Handle) {
26 if (Err) *Err = ::dlerror();
27 return &DynamicLibrary::Invalid;
28 }
29
30 #ifdef __CYGWIN__
31 // Cygwin searches symbols only in the main
32 // with the handle of dlopen(NULL, RTLD_GLOBAL).
33 if (!Filename)
34 Handle = RTLD_DEFAULT;
35 #endif
36
37 return Handle;
38 }
39
40 void DynamicLibrary::HandleSet::DLClose(void *Handle) {
41 ::dlclose(Handle);
42 }
43
44 void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
45 return ::dlsym(Handle, Symbol);
46 }
47
48 #else // !HAVE_DLOPEN
49
50 DynamicLibrary::HandleSet::~HandleSet() {}
51
52 void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
53 if (Err) *Err = "dlopen() not supported on this platform";
54 return &Invalid;
55 }
56
57 void DynamicLibrary::HandleSet::DLClose(void *Handle) {
58 }
59
60 void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
61 return nullptr;
62 }
63
64 #endif
65
66 // Must declare the symbols in the global namespace.
67 static void *DoSearch(const char* SymbolName) {
68 #define EXPLICIT_SYMBOL(SYM) \
69 extern void *SYM; if (!strcmp(SymbolName, #SYM)) return &SYM
70
71 // If this is darwin, it has some funky issues, try to solve them here. Some
72 // important symbols are marked 'private external' which doesn't allow
73 // SearchForAddressOfSymbol to find them. As such, we special case them here,
74 // there is only a small handful of them.
75
76 #ifdef __APPLE__
77 {
78 // __eprintf is sometimes used for assert() handling on x86.
79 //
80 // FIXME: Currently disabled when using Clang, as we don't always have our
81 // runtime support libraries available.
82 #ifndef __clang__
83 #ifdef __i386__
84 EXPLICIT_SYMBOL(__eprintf);
85 #endif
86 #endif
87 }
88 #endif
89
90 #ifdef __CYGWIN__
91 {
92 EXPLICIT_SYMBOL(_alloca);
93 EXPLICIT_SYMBOL(__main);
94 }
95 #endif
96
97 #undef EXPLICIT_SYMBOL
98
99 // This macro returns the address of a well-known, explicit symbol
100 #define EXPLICIT_SYMBOL(SYM) \
101 if (!strcmp(SymbolName, #SYM)) return &SYM
102
103 // On linux we have a weird situation. The stderr/out/in symbols are both
104 // macros and global variables because of standards requirements. So, we
105 // boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
106 #if defined(__linux__) and !defined(__ANDROID__)
107 {
108 EXPLICIT_SYMBOL(stderr);
109 EXPLICIT_SYMBOL(stdout);
110 EXPLICIT_SYMBOL(stdin);
111 }
112 #else
113 // For everything else, we want to check to make sure the symbol isn't defined
114 // as a macro before using EXPLICIT_SYMBOL.
115 {
116 #ifndef stdin
117 EXPLICIT_SYMBOL(stdin);
118 #endif
119 #ifndef stdout
120 EXPLICIT_SYMBOL(stdout);
121 #endif
122 #ifndef stderr
123 EXPLICIT_SYMBOL(stderr);
124 #endif
125 }
126 #endif
127 #undef EXPLICIT_SYMBOL
128
129 return nullptr;
130 }
1515 #ifdef __MINGW32__
1616 #include
1717 #else
18 #include <dbghelp.h>
18 #include <Psapi.h>
1919 #endif
2020
2121 #ifdef _MSC_VER
2222 #include
2323 #endif
2424
25 namespace llvm {
26
2725 //===----------------------------------------------------------------------===//
2826 //=== WARNING: Implementation here must contain only Win32 specific code
2927 //=== and must not be UNIX code.
3028 //===----------------------------------------------------------------------===//
3129
32 typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
33 static fpEnumerateLoadedModules fEnumerateLoadedModules;
34 static llvm::ManagedStatic > OpenedHandles;
35
36 static bool loadDebugHelp(void) {
37 HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
38 if (hLib) {
39 fEnumerateLoadedModules = (fpEnumerateLoadedModules)
40 ::GetProcAddress(hLib, "EnumerateLoadedModules64");
41 }
42 return fEnumerateLoadedModules != 0;
43 }
44
45 static BOOL CALLBACK
46 ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase,
47 ULONG ModuleSize, PVOID UserContext) {
48 OpenedHandles->insert((HMODULE)ModuleBase);
49 return TRUE;
50 }
51
52 sys::DynamicLibrary
53 sys::DynamicLibrary::getPermanentLibrary(const char *filename,
54 std::string *errMsg) {
55 SmartScopedLock lock(*SymbolsMutex);
56
57 if (!filename) {
58 // When no file is specified, enumerate all DLLs and EXEs in the process.
59 if (!fEnumerateLoadedModules) {
60 if (!loadDebugHelp()) {
61 assert(false && "These APIs should always be available");
62 return DynamicLibrary();
63 }
30
31 DynamicLibrary::HandleSet::~HandleSet() {
32 for (void *Handle : Handles)
33 FreeLibrary(HMODULE(Handle));
34
35 // 'Process' should not be released on Windows.
36 assert((!Process || Process==this) && "Bad Handle");
37 }
38
39 void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
40 // Create the instance and return it to be the *Process* handle
41 // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
42 if (!File)
43 return &(*OpenedHandles);
44
45 SmallVector FileUnicode;
46 if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
47 SetLastError(ec.value());
48 MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
49 return &DynamicLibrary::Invalid;
50 }
51
52 HMODULE Handle = LoadLibraryW(FileUnicode.data());
53 if (Handle == NULL) {
54 MakeErrMsg(Err, std::string(File) + ": Can't open");
55 return &DynamicLibrary::Invalid;
56 }
57
58 return reinterpret_cast(Handle);
59 }
60
61 static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
62 if (!OpenedHandles.isConstructed())
63 return false;
64 DynamicLibrary::HandleSet &Inst = *OpenedHandles;
65 return Handle == &Inst ? &Inst : nullptr;
66 }
67
68 void DynamicLibrary::HandleSet::DLClose(void *Handle) {
69 if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
70 HS->Process = nullptr; // Just drop the *Process* handle.
71 else
72 FreeLibrary((HMODULE)Handle);
73 }
74
75 static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
76 #ifdef _WIN64
77 const DWORD Flags = LIST_MODULES_64BIT;
78 #else
79 const DWORD Flags = LIST_MODULES_32BIT;
80 #endif
81
82 if (!EnumProcessModulesEx(H, Data, Bytes, &Bytes, Flags)) {
83 std::string Err;
84 if (MakeErrMsg(&Err, "EnumProcessModulesEx failure"))
85 llvm::errs() << Err << "\n";
86 return false;
87 }
88 return true;
89 }
90
91 void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
92 HandleSet* HS = IsOpenedHandlesInstance(Handle);
93 if (!HS)
94 return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
95
96 // Could have done a dlclose on the *Process* handle
97 if (!HS->Process)
98 return nullptr;
99
100 // Trials indicate EnumProcessModulesEx is consistantly faster than using
101 // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
102 //
103 // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
104 // |=========|=============|========================================
105 // | 37 | 0.0000585 * | 0.0003031 | 0.0000152
106 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683
107 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610
108 //
109 // * Not including the load time of Dbghelp.dll (~.005 sec)
110 //
111 // There's still a case to somehow cache the result of EnumProcessModulesEx
112 // across invocations, but the complication of doing that properly...
113 // Possibly using LdrRegisterDllNotification to invalidate the cache?
114
115 DWORD Bytes = 0;
116 HMODULE Self = HMODULE(GetCurrentProcess());
117 if (!GetProcessModules(Self, Bytes))
118 return nullptr;
119
120 // Get the most recent list in case any modules added/removed between calls
121 // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
122 // MSDN is pretty clear that if the module list changes during the call to
123 // EnumProcessModulesEx the results should not be used.
124 std::vector Handles;
125 do {
126 assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
127 "Should have at least one module and be aligned");
128 Handles.resize(Bytes / sizeof(HMODULE));
129 if (!GetProcessModules(Self, Bytes, Handles.data()))
130 return nullptr;
131 } while (Bytes != (Handles.size() * sizeof(HMODULE)));
132
133 // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
134 if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
135 return (void *) uintptr_t(Ptr);
136
137 if (Handles.size() > 1) {
138 // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
139 // Doing that here is causing real problems for the JIT where msvc.dll
140 // and ucrt.dll can define the same symbols. The runtime linker will choose
141 // symbols from ucrt.dll first, but iterating NOT in reverse here would
142 // mean that the msvc.dll versions would be returned.
143
144 for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
145 if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
146 return (void *) uintptr_t(Ptr);
64147 }
65
66 fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0);
67 // Dummy library that represents "search all handles".
68 // This is mostly to ensure that the return value still shows up as "valid".
69 return DynamicLibrary(&OpenedHandles);
70 }
71
72 SmallVector filenameUnicode;
73 if (std::error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) {
74 SetLastError(ec.value());
75 MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16");
76 return DynamicLibrary();
77 }
78
79 HMODULE a_handle = LoadLibraryW(filenameUnicode.data());
80
81 if (a_handle == 0) {
82 MakeErrMsg(errMsg, std::string(filename) + ": Can't open");
83 return DynamicLibrary();
84 }
85
86 // If we've already loaded this library, FreeLibrary() the handle in order to
87 // keep the internal refcount at +1.
88 if (!OpenedHandles->insert(a_handle).second)
89 FreeLibrary(a_handle);
90
91 return DynamicLibrary(a_handle);
92 }
93
94 sys::DynamicLibrary
95 sys::DynamicLibrary::addPermanentLibrary(void *handle, std::string *errMsg) {
96 SmartScopedLock lock(*SymbolsMutex);
97 // If we've already loaded this library, tell the caller.
98 if (!OpenedHandles->insert((HMODULE)handle).second) {
99 MakeErrMsg(errMsg, "Library already loaded");
100 return DynamicLibrary();
101 }
102
103 return DynamicLibrary(handle);
104 }
148 }
149 return nullptr;
150 }
151
105152
106153 // Stack probing routines are in the support library (e.g. libgcc), but we don't
107154 // have dynamic linking on windows. Provide a hook.
128175 #undef INLINE_DEF_SYMBOL1
129176 #undef INLINE_DEF_SYMBOL2
130177
131 void *sys::DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
132 SmartScopedLock Lock(*SymbolsMutex);
133
134 // First check symbols added via AddSymbol().
135 if (ExplicitSymbols.isConstructed()) {
136 StringMap::iterator i = ExplicitSymbols->find(symbolName);
137
138 if (i != ExplicitSymbols->end())
139 return i->second;
140 }
141
142 // Now search the libraries.
143 if (OpenedHandles.isConstructed()) {
144 for (DenseSet::iterator I = OpenedHandles->begin(),
145 E = OpenedHandles->end(); I != E; ++I) {
146 FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName);
147 if (ptr) {
148 return (void *)(intptr_t)ptr;
149 }
150 }
151 }
178 static void *DoSearch(const char *SymbolName) {
152179
153180 #define EXPLICIT_SYMBOL(SYM) \
154 if (!strcmp(symbolName, #SYM)) \
181 if (!strcmp(SymbolName, #SYM)) \
155182 return (void *)&SYM;
156183 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \
157 if (!strcmp(symbolName, #SYMFROM)) \
184 if (!strcmp(SymbolName, #SYMFROM)) \
158185 return (void *)&SYMTO;
159186
160187 #ifdef _M_IX86
161188 #define INLINE_DEF_SYMBOL1(TYP, SYM) \
162 if (!strcmp(symbolName, #SYM)) \
189 if (!strcmp(SymbolName, #SYM)) \
163190 return (void *)&inline_##SYM;
164191 #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
165192 #endif
173200 #undef INLINE_DEF_SYMBOL1
174201 #undef INLINE_DEF_SYMBOL2
175202
176 return 0;
177 }
178
179 void *sys::DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
180 if (!isValid())
181 return NULL;
182 if (Data == &OpenedHandles)
183 return SearchForAddressOfSymbol(symbolName);
184 return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName);
185 }
186
187 }
203 return nullptr;
204 }
6666
6767 # ManagedStatic.cpp uses .
6868 target_link_libraries(SupportTests ${LLVM_PTHREAD_LIB})
69
70 add_subdirectory(DynamicLibrary)
0 set(LLVM_LINK_COMPONENTS Support)
1
2 add_llvm_unittest(DynamicLibraryTests DynamicLibraryTest.cpp)
3
4 export_executable_symbols(DynamicLibraryTests)
5
6 add_library(PipSqueak SHARED PipSqueak.cxx)
7
8 set_output_directory(PipSqueak
9 BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
10 LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
11 )
12
13 set_target_properties(PipSqueak
14 PROPERTIES PREFIX ""
15 SUFFIX ".so"
16 )
17
18 add_dependencies(DynamicLibraryTests PipSqueak)
0 //===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Config/config.h"
10 #include "llvm/Support/DynamicLibrary.h"
11 #include "llvm/Support/FileSystem.h"
12 #include "llvm/Support/ManagedStatic.h"
13 #include "llvm/Support/Path.h"
14 #include "gtest/gtest.h"
15
16 #include "PipSqueak.h"
17 #include
18
19 using namespace llvm;
20 using namespace llvm::sys;
21
22 extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "ProcessCall"; }
23
24 std::string LibPath() {
25 std::string Path =
26 fs::getMainExecutable("DynamicLibraryTests", (void *)&TestA);
27 llvm::SmallString<256> Buf(path::parent_path(Path));
28 path::append(Buf, "PipSqueak.so");
29 return Buf.str();
30 }
31
32 #if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN))
33
34 typedef void (*SetStrings)(std::string &GStr, std::string &LStr);
35 typedef const char *(*GetString)();
36
37 template static T FuncPtr(void *Ptr) {
38 union {
39 T F;
40 void *P;
41 } Tmp;
42 Tmp.P = Ptr;
43 return Tmp.F;
44 }
45 template static void* PtrFunc(T *Func) {
46 union {
47 T *F;
48 void *P;
49 } Tmp;
50 Tmp.F = Func;
51 return Tmp.P;
52 }
53
54 static const char *OverloadTestA() { return "OverloadCall"; }
55
56 std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; }
57
58 TEST(DynamicLibrary, Overload) {
59 {
60 std::string Err;
61 llvm_shutdown_obj Shutdown;
62 DynamicLibrary DL =
63 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
64 EXPECT_TRUE(DL.isValid());
65 EXPECT_TRUE(Err.empty());
66
67 GetString GS = FuncPtr(DL.getAddressOfSymbol("TestA"));
68 EXPECT_TRUE(GS != nullptr && GS != &TestA);
69 EXPECT_EQ(StdString(GS()), "LibCall");
70
71 GS = FuncPtr(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
72 EXPECT_TRUE(GS != nullptr && GS != &TestA);
73 EXPECT_EQ(StdString(GS()), "LibCall");
74
75 DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err);
76 EXPECT_TRUE(DL.isValid());
77 EXPECT_TRUE(Err.empty());
78
79 GS = FuncPtr(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
80 EXPECT_TRUE(GS != nullptr && GS == &TestA);
81 EXPECT_EQ(StdString(GS()), "ProcessCall");
82
83 GS = FuncPtr(DL.getAddressOfSymbol("TestA"));
84 EXPECT_TRUE(GS != nullptr && GS == &TestA);
85 EXPECT_EQ(StdString(GS()), "ProcessCall");
86
87 DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA));
88 GS = FuncPtr(DL.getAddressOfSymbol("TestA"));
89 EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA);
90
91 GS = FuncPtr(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
92 EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA);
93 EXPECT_EQ(StdString(GS()), "OverloadCall");
94 }
95 EXPECT_TRUE(FuncPtr(DynamicLibrary::SearchForAddressOfSymbol(
96 "TestA")) == nullptr);
97 }
98
99 TEST(DynamicLibrary, Shutdown) {
100 std::string A, B;
101 {
102 std::string Err;
103 llvm_shutdown_obj Shutdown;
104 DynamicLibrary DL =
105 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
106 EXPECT_TRUE(DL.isValid());
107 EXPECT_TRUE(Err.empty());
108
109 SetStrings SS = FuncPtr(
110 DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
111 EXPECT_TRUE(SS != nullptr);
112
113 SS(A, B);
114 EXPECT_EQ(B, "Local::Local");
115 }
116 EXPECT_EQ(A, "Global::~Global");
117 EXPECT_EQ(B, "Local::~Local");
118 EXPECT_TRUE(FuncPtr(DynamicLibrary::SearchForAddressOfSymbol(
119 "SetStrings")) == nullptr);
120 }
121
122 #else
123
124 TEST(DynamicLibrary, Unsupported) {
125 std::string Err;
126 DynamicLibrary DL =
127 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
128 EXPECT_FALSE(DL.isValid());
129 EXPECT_EQ(Err, "dlopen() not supported on this platform");
130 }
131
132 #endif
0 //===- llvm/unittest/Support/DynamicLibrary/PipSqueak.cxx -----------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "PipSqueak.h"
10 #include
11
12 struct Global {
13 std::string *Str;
14 Global() : Str(nullptr) {}
15 ~Global() {
16 if (Str)
17 *Str = "Global::~Global";
18 }
19 };
20
21 struct Local {
22 std::string &Str;
23 Local(std::string &S) : Str(S) { Str = "Local::Local"; }
24 ~Local() { Str = "Local::~Local"; }
25 };
26
27 static Global Glb;
28
29 extern "C" PIPSQUEAK_EXPORT void SetStrings(std::string &GStr,
30 std::string &LStr) {
31 static Local Lcl(LStr);
32 Glb.Str = &GStr;
33 }
34
35 extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "LibCall"; }
0 //===- llvm/unittest/Support/DynamicLibrary/PipSqueak.h -------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_PIPSQUEAK_H
10 #define LLVM_PIPSQUEAK_H
11
12 #ifdef _WIN32
13 #define PIPSQUEAK_EXPORT __declspec(dllexport)
14 #else
15 #define PIPSQUEAK_EXPORT
16 #endif
17
18 #endif