12754fe60SDimitry Andric//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//
22754fe60SDimitry Andric//
32754fe60SDimitry Andric//                     The LLVM Compiler Infrastructure
42754fe60SDimitry Andric//
52754fe60SDimitry Andric// This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric// License. See LICENSE.TXT for details.
72754fe60SDimitry Andric//
82754fe60SDimitry Andric//===----------------------------------------------------------------------===//
92754fe60SDimitry Andric//
102754fe60SDimitry Andric// This file provides the Win32 specific implementation of DynamicLibrary.
112754fe60SDimitry Andric//
122754fe60SDimitry Andric//===----------------------------------------------------------------------===//
132754fe60SDimitry Andric
1491bc56edSDimitry Andric#include "WindowsSupport.h"
15*4ba319b5SDimitry Andric#include "llvm/Support/ConvertUTF.h"
16f37b6182SDimitry Andric#include "llvm/Support/raw_ostream.h"
172754fe60SDimitry Andric
18f37b6182SDimitry Andric#include <psapi.h>
192754fe60SDimitry Andric
202754fe60SDimitry Andric//===----------------------------------------------------------------------===//
212754fe60SDimitry Andric//=== WARNING: Implementation here must contain only Win32 specific code
222754fe60SDimitry Andric//===          and must not be UNIX code.
232754fe60SDimitry Andric//===----------------------------------------------------------------------===//
242754fe60SDimitry Andric
252754fe60SDimitry Andric
26f37b6182SDimitry AndricDynamicLibrary::HandleSet::~HandleSet() {
27db17bf38SDimitry Andric  for (void *Handle : llvm::reverse(Handles))
28f37b6182SDimitry Andric    FreeLibrary(HMODULE(Handle));
29f37b6182SDimitry Andric
30f37b6182SDimitry Andric  // 'Process' should not be released on Windows.
31f37b6182SDimitry Andric  assert((!Process || Process==this) && "Bad Handle");
32c4394386SDimitry Andric  // llvm_shutdown called, Return to default
33c4394386SDimitry Andric  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
343dac3a9bSDimitry Andric}
353dac3a9bSDimitry Andric
36f37b6182SDimitry Andricvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
37f37b6182SDimitry Andric  // Create the instance and return it to be the *Process* handle
38f37b6182SDimitry Andric  // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
39f37b6182SDimitry Andric  if (!File)
40f37b6182SDimitry Andric    return &(*OpenedHandles);
412754fe60SDimitry Andric
42f37b6182SDimitry Andric  SmallVector<wchar_t, MAX_PATH> FileUnicode;
43f37b6182SDimitry Andric  if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
44f785676fSDimitry Andric    SetLastError(ec.value());
45f37b6182SDimitry Andric    MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
46f37b6182SDimitry Andric    return &DynamicLibrary::Invalid;
47f785676fSDimitry Andric  }
48f785676fSDimitry Andric
49f37b6182SDimitry Andric  HMODULE Handle = LoadLibraryW(FileUnicode.data());
50f37b6182SDimitry Andric  if (Handle == NULL) {
51f37b6182SDimitry Andric    MakeErrMsg(Err, std::string(File) + ": Can't open");
52f37b6182SDimitry Andric    return &DynamicLibrary::Invalid;
536122f3e6SDimitry Andric  }
546122f3e6SDimitry Andric
55f37b6182SDimitry Andric  return reinterpret_cast<void*>(Handle);
562754fe60SDimitry Andric}
572754fe60SDimitry Andric
58f37b6182SDimitry Andricstatic DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
59f37b6182SDimitry Andric  if (!OpenedHandles.isConstructed())
60f37b6182SDimitry Andric    return nullptr;
61f37b6182SDimitry Andric  DynamicLibrary::HandleSet &Inst = *OpenedHandles;
62f37b6182SDimitry Andric  return Handle == &Inst ? &Inst : nullptr;
637a7e6055SDimitry Andric}
647a7e6055SDimitry Andric
65f37b6182SDimitry Andricvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
66f37b6182SDimitry Andric  if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
67f37b6182SDimitry Andric    HS->Process = nullptr; // Just drop the *Process* handle.
68f37b6182SDimitry Andric  else
69f37b6182SDimitry Andric    FreeLibrary((HMODULE)Handle);
707a7e6055SDimitry Andric}
717a7e6055SDimitry Andric
72f37b6182SDimitry Andricstatic bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
73f37b6182SDimitry Andric  // EnumProcessModules will fail on Windows 64 while some versions of
74f37b6182SDimitry Andric  // MingW-32 don't have EnumProcessModulesEx.
75f37b6182SDimitry Andric  if (
76f37b6182SDimitry Andric#ifdef _WIN64
77f37b6182SDimitry Andric      !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
78f37b6182SDimitry Andric#else
79f37b6182SDimitry Andric      !EnumProcessModules(H, Data, Bytes, &Bytes)
80f37b6182SDimitry Andric#endif
81f37b6182SDimitry Andric     ) {
82f37b6182SDimitry Andric    std::string Err;
83f37b6182SDimitry Andric    if (MakeErrMsg(&Err, "EnumProcessModules failure"))
84f37b6182SDimitry Andric      llvm::errs() << Err << "\n";
85f37b6182SDimitry Andric    return false;
86f37b6182SDimitry Andric  }
87f37b6182SDimitry Andric  return true;
88f37b6182SDimitry Andric}
89f37b6182SDimitry Andric
90f37b6182SDimitry Andricvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
91f37b6182SDimitry Andric  HandleSet* HS = IsOpenedHandlesInstance(Handle);
92f37b6182SDimitry Andric  if (!HS)
93f37b6182SDimitry Andric    return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
94f37b6182SDimitry Andric
95f37b6182SDimitry Andric  // Could have done a dlclose on the *Process* handle
96f37b6182SDimitry Andric  if (!HS->Process)
97f37b6182SDimitry Andric    return nullptr;
98f37b6182SDimitry Andric
99f37b6182SDimitry Andric  // Trials indicate EnumProcessModulesEx is consistantly faster than using
100f37b6182SDimitry Andric  // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
101f37b6182SDimitry Andric  //
102f37b6182SDimitry Andric  // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
103f37b6182SDimitry Andric  // |=========|=============|========================================
104f37b6182SDimitry Andric  // | 37      | 0.0000585 * | 0.0003031      | 0.0000152
105f37b6182SDimitry Andric  // | 1020    | 0.0026310 * | 0.0121598      | 0.0002683
106f37b6182SDimitry Andric  // | 2084    | 0.0149418 * | 0.0369936      | 0.0005610
107f37b6182SDimitry Andric  //
108f37b6182SDimitry Andric  // * Not including the load time of Dbghelp.dll (~.005 sec)
109f37b6182SDimitry Andric  //
110f37b6182SDimitry Andric  // There's still a case to somehow cache the result of EnumProcessModulesEx
111f37b6182SDimitry Andric  // across invocations, but the complication of doing that properly...
112f37b6182SDimitry Andric  // Possibly using LdrRegisterDllNotification to invalidate the cache?
113f37b6182SDimitry Andric
114f37b6182SDimitry Andric  DWORD Bytes = 0;
115f37b6182SDimitry Andric  HMODULE Self = HMODULE(GetCurrentProcess());
116f37b6182SDimitry Andric  if (!GetProcessModules(Self, Bytes))
117f37b6182SDimitry Andric    return nullptr;
118f37b6182SDimitry Andric
119f37b6182SDimitry Andric  // Get the most recent list in case any modules added/removed between calls
120f37b6182SDimitry Andric  // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
121f37b6182SDimitry Andric  // MSDN is pretty clear that if the module list changes during the call to
122f37b6182SDimitry Andric  // EnumProcessModulesEx the results should not be used.
123f37b6182SDimitry Andric  std::vector<HMODULE> Handles;
124f37b6182SDimitry Andric  do {
125f37b6182SDimitry Andric    assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
126f37b6182SDimitry Andric           "Should have at least one module and be aligned");
127f37b6182SDimitry Andric    Handles.resize(Bytes / sizeof(HMODULE));
128f37b6182SDimitry Andric    if (!GetProcessModules(Self, Bytes, Handles.data()))
129f37b6182SDimitry Andric      return nullptr;
130f37b6182SDimitry Andric  } while (Bytes != (Handles.size() * sizeof(HMODULE)));
131f37b6182SDimitry Andric
132f37b6182SDimitry Andric  // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
133f37b6182SDimitry Andric  if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
134f37b6182SDimitry Andric    return (void *) uintptr_t(Ptr);
135f37b6182SDimitry Andric
136f37b6182SDimitry Andric  if (Handles.size() > 1) {
137f37b6182SDimitry Andric    // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
138f37b6182SDimitry Andric    // Doing that here is causing real problems for the JIT where msvc.dll
139f37b6182SDimitry Andric    // and ucrt.dll can define the same symbols. The runtime linker will choose
140f37b6182SDimitry Andric    // symbols from ucrt.dll first, but iterating NOT in reverse here would
141f37b6182SDimitry Andric    // mean that the msvc.dll versions would be returned.
142f37b6182SDimitry Andric
143f37b6182SDimitry Andric    for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
144f37b6182SDimitry Andric      if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
145f37b6182SDimitry Andric        return (void *) uintptr_t(Ptr);
146f37b6182SDimitry Andric    }
147f37b6182SDimitry Andric  }
148f37b6182SDimitry Andric  return nullptr;
149f37b6182SDimitry Andric}
150f37b6182SDimitry Andric
151f37b6182SDimitry Andric
1522754fe60SDimitry Andric// Stack probing routines are in the support library (e.g. libgcc), but we don't
1532754fe60SDimitry Andric// have dynamic linking on windows. Provide a hook.
1542754fe60SDimitry Andric#define EXPLICIT_SYMBOL(SYM)                    \
1552754fe60SDimitry Andric  extern "C" { extern void *SYM; }
1562754fe60SDimitry Andric#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
1572754fe60SDimitry Andric
15839d628a0SDimitry Andric#ifdef _M_IX86
15939d628a0SDimitry Andric// Win32 on x86 implements certain single-precision math functions as macros.
16039d628a0SDimitry Andric// These functions are not exported by the DLL, but will still be needed
16139d628a0SDimitry Andric// for symbol-resolution by the JIT loader. Therefore, this Support libray
16239d628a0SDimitry Andric// provides helper functions with the same implementation.
16339d628a0SDimitry Andric
16439d628a0SDimitry Andric#define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
16539d628a0SDimitry Andric  extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }
16639d628a0SDimitry Andric#define INLINE_DEF_SYMBOL2(TYP, SYM)                                           \
16739d628a0SDimitry Andric  extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }
16839d628a0SDimitry Andric#endif
16939d628a0SDimitry Andric
1702754fe60SDimitry Andric#include "explicit_symbols.inc"
1712754fe60SDimitry Andric
1722754fe60SDimitry Andric#undef EXPLICIT_SYMBOL
1732754fe60SDimitry Andric#undef EXPLICIT_SYMBOL2
17439d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL1
17539d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL2
1762754fe60SDimitry Andric
177f37b6182SDimitry Andricstatic void *DoSearch(const char *SymbolName) {
1782754fe60SDimitry Andric
1792754fe60SDimitry Andric#define EXPLICIT_SYMBOL(SYM)                                                   \
180f37b6182SDimitry Andric  if (!strcmp(SymbolName, #SYM))                                               \
18139d628a0SDimitry Andric    return (void *)&SYM;
1822754fe60SDimitry Andric#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO)                                       \
183f37b6182SDimitry Andric  if (!strcmp(SymbolName, #SYMFROM))                                           \
18439d628a0SDimitry Andric    return (void *)&SYMTO;
18539d628a0SDimitry Andric
18639d628a0SDimitry Andric#ifdef _M_IX86
18739d628a0SDimitry Andric#define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
188f37b6182SDimitry Andric  if (!strcmp(SymbolName, #SYM))                                               \
18939d628a0SDimitry Andric    return (void *)&inline_##SYM;
19039d628a0SDimitry Andric#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
19139d628a0SDimitry Andric#endif
1922754fe60SDimitry Andric
1932754fe60SDimitry Andric  {
1942754fe60SDimitry Andric#include "explicit_symbols.inc"
1952754fe60SDimitry Andric  }
1962754fe60SDimitry Andric
1972754fe60SDimitry Andric#undef EXPLICIT_SYMBOL
1982754fe60SDimitry Andric#undef EXPLICIT_SYMBOL2
19939d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL1
20039d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL2
2012754fe60SDimitry Andric
202f37b6182SDimitry Andric  return nullptr;
2032754fe60SDimitry Andric}
204