123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file provides the Win32 specific implementation of DynamicLibrary.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Support/Windows/WindowsSupport.h"
- #include "llvm/Support/ConvertUTF.h"
- #include "llvm/Support/raw_ostream.h"
- #include <psapi.h>
- //===----------------------------------------------------------------------===//
- //=== WARNING: Implementation here must contain only Win32 specific code
- //=== and must not be UNIX code.
- //===----------------------------------------------------------------------===//
- DynamicLibrary::HandleSet::~HandleSet() {
- for (void *Handle : llvm::reverse(Handles))
- FreeLibrary(HMODULE(Handle));
- // 'Process' should not be released on Windows.
- assert((!Process || Process==this) && "Bad Handle");
- // llvm_shutdown called, Return to default
- DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
- }
- void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
- // Create the instance and return it to be the *Process* handle
- // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
- if (!File)
- return &(*OpenedHandles);
- SmallVector<wchar_t, MAX_PATH> FileUnicode;
- if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
- SetLastError(ec.value());
- MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
- return &DynamicLibrary::Invalid;
- }
- HMODULE Handle = LoadLibraryW(FileUnicode.data());
- if (Handle == NULL) {
- MakeErrMsg(Err, std::string(File) + ": Can't open");
- return &DynamicLibrary::Invalid;
- }
- return reinterpret_cast<void*>(Handle);
- }
- static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
- if (!OpenedHandles.isConstructed())
- return nullptr;
- DynamicLibrary::HandleSet &Inst = *OpenedHandles;
- return Handle == &Inst ? &Inst : nullptr;
- }
- void DynamicLibrary::HandleSet::DLClose(void *Handle) {
- if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
- HS->Process = nullptr; // Just drop the *Process* handle.
- else
- FreeLibrary((HMODULE)Handle);
- }
- static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
- // EnumProcessModules will fail on Windows 64 while some versions of
- // MingW-32 don't have EnumProcessModulesEx.
- if (
- #ifdef _WIN64
- !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
- #else
- !EnumProcessModules(H, Data, Bytes, &Bytes)
- #endif
- ) {
- std::string Err;
- if (MakeErrMsg(&Err, "EnumProcessModules failure"))
- llvm::errs() << Err << "\n";
- return false;
- }
- return true;
- }
- void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
- HandleSet* HS = IsOpenedHandlesInstance(Handle);
- if (!HS)
- return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
- // Could have done a dlclose on the *Process* handle
- if (!HS->Process)
- return nullptr;
- // Trials indicate EnumProcessModulesEx is consistantly faster than using
- // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
- //
- // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
- // |=========|=============|========================================
- // | 37 | 0.0000585 * | 0.0003031 | 0.0000152
- // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683
- // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610
- //
- // * Not including the load time of Dbghelp.dll (~.005 sec)
- //
- // There's still a case to somehow cache the result of EnumProcessModulesEx
- // across invocations, but the complication of doing that properly...
- // Possibly using LdrRegisterDllNotification to invalidate the cache?
- DWORD Bytes = 0;
- HMODULE Self = HMODULE(GetCurrentProcess());
- if (!GetProcessModules(Self, Bytes))
- return nullptr;
- // Get the most recent list in case any modules added/removed between calls
- // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
- // MSDN is pretty clear that if the module list changes during the call to
- // EnumProcessModulesEx the results should not be used.
- std::vector<HMODULE> Handles;
- do {
- assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
- "Should have at least one module and be aligned");
- Handles.resize(Bytes / sizeof(HMODULE));
- if (!GetProcessModules(Self, Bytes, Handles.data()))
- return nullptr;
- } while (Bytes != (Handles.size() * sizeof(HMODULE)));
- // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
- if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
- return (void *) uintptr_t(Ptr);
- if (Handles.size() > 1) {
- // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
- // Doing that here is causing real problems for the JIT where msvc.dll
- // and ucrt.dll can define the same symbols. The runtime linker will choose
- // symbols from ucrt.dll first, but iterating NOT in reverse here would
- // mean that the msvc.dll versions would be returned.
- for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
- if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
- return (void *) uintptr_t(Ptr);
- }
- }
- return nullptr;
- }
- // Stack probing routines are in the support library (e.g. libgcc), but we don't
- // have dynamic linking on windows. Provide a hook.
- #define EXPLICIT_SYMBOL(SYM) \
- extern "C" { extern void *SYM; }
- #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
- #ifdef _M_IX86
- // Win32 on x86 implements certain single-precision math functions as macros.
- // These functions are not exported by the DLL, but will still be needed
- // for symbol-resolution by the JIT loader. Therefore, this Support libray
- // provides helper functions with the same implementation.
- #define INLINE_DEF_SYMBOL1(TYP, SYM) \
- extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }
- #define INLINE_DEF_SYMBOL2(TYP, SYM) \
- extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }
- #endif
- #include "explicit_symbols.inc"
- #undef EXPLICIT_SYMBOL
- #undef EXPLICIT_SYMBOL2
- #undef INLINE_DEF_SYMBOL1
- #undef INLINE_DEF_SYMBOL2
- static void *DoSearch(const char *SymbolName) {
- #define EXPLICIT_SYMBOL(SYM) \
- if (!strcmp(SymbolName, #SYM)) \
- return (void *)&SYM;
- #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \
- if (!strcmp(SymbolName, #SYMFROM)) \
- return (void *)&SYMTO;
- #ifdef _M_IX86
- #define INLINE_DEF_SYMBOL1(TYP, SYM) \
- if (!strcmp(SymbolName, #SYM)) \
- return (void *)&inline_##SYM;
- #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
- #endif
- {
- #include "explicit_symbols.inc"
- }
- #undef EXPLICIT_SYMBOL
- #undef EXPLICIT_SYMBOL2
- #undef INLINE_DEF_SYMBOL1
- #undef INLINE_DEF_SYMBOL2
- return nullptr;
- }
|