1447762daSMichael J. Spencer//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//
2447762daSMichael J. Spencer//
32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6447762daSMichael J. Spencer//
7447762daSMichael J. Spencer//===----------------------------------------------------------------------===//
8447762daSMichael J. Spencer//
9447762daSMichael J. Spencer// This file provides the Win32 specific implementation of DynamicLibrary.
10447762daSMichael J. Spencer//
11447762daSMichael J. Spencer//===----------------------------------------------------------------------===//
12447762daSMichael J. Spencer
13*01f9abbbSHans Wennborg#include "llvm/Support/Windows/WindowsSupport.h"
14b44d7a0dSZachary Turner#include "llvm/Support/ConvertUTF.h"
15c1db8cf9SFrederich Munch#include "llvm/Support/raw_ostream.h"
16447762daSMichael J. Spencer
17c1db8cf9SFrederich Munch#include <psapi.h>
18b8c236a6SFrederich Munch
19447762daSMichael J. Spencer//===----------------------------------------------------------------------===//
20447762daSMichael J. Spencer//=== WARNING: Implementation here must contain only Win32 specific code
21447762daSMichael J. Spencer//===          and must not be UNIX code.
22447762daSMichael J. Spencer//===----------------------------------------------------------------------===//
23447762daSMichael J. Spencer
24447762daSMichael J. Spencer
25c1db8cf9SFrederich MunchDynamicLibrary::HandleSet::~HandleSet() {
26ad125800SFrederich Munch  for (void *Handle : llvm::reverse(Handles))
27c1db8cf9SFrederich Munch    FreeLibrary(HMODULE(Handle));
28c1db8cf9SFrederich Munch
29c1db8cf9SFrederich Munch  // 'Process' should not be released on Windows.
30c1db8cf9SFrederich Munch  assert((!Process || Process==this) && "Bad Handle");
315fdd2cbaSFrederich Munch  // llvm_shutdown called, Return to default
325fdd2cbaSFrederich Munch  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
33bebb27b0SLeny Kholodov}
34bebb27b0SLeny Kholodov
35c1db8cf9SFrederich Munchvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
36c1db8cf9SFrederich Munch  // Create the instance and return it to be the *Process* handle
37c1db8cf9SFrederich Munch  // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
38c1db8cf9SFrederich Munch  if (!File)
39c1db8cf9SFrederich Munch    return &(*OpenedHandles);
40447762daSMichael J. Spencer
41c1db8cf9SFrederich Munch  SmallVector<wchar_t, MAX_PATH> FileUnicode;
42c1db8cf9SFrederich Munch  if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
4361eae2e3SDavid Majnemer    SetLastError(ec.value());
44c1db8cf9SFrederich Munch    MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
45c1db8cf9SFrederich Munch    return &DynamicLibrary::Invalid;
4661eae2e3SDavid Majnemer  }
4761eae2e3SDavid Majnemer
48c1db8cf9SFrederich Munch  HMODULE Handle = LoadLibraryW(FileUnicode.data());
49c1db8cf9SFrederich Munch  if (Handle == NULL) {
50c1db8cf9SFrederich Munch    MakeErrMsg(Err, std::string(File) + ": Can't open");
51c1db8cf9SFrederich Munch    return &DynamicLibrary::Invalid;
52a19917daSJordy Rose  }
53a19917daSJordy Rose
54c1db8cf9SFrederich Munch  return reinterpret_cast<void*>(Handle);
55447762daSMichael J. Spencer}
56447762daSMichael J. Spencer
57c1db8cf9SFrederich Munchstatic DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
58c1db8cf9SFrederich Munch  if (!OpenedHandles.isConstructed())
59c1db8cf9SFrederich Munch    return nullptr;
60c1db8cf9SFrederich Munch  DynamicLibrary::HandleSet &Inst = *OpenedHandles;
61c1db8cf9SFrederich Munch  return Handle == &Inst ? &Inst : nullptr;
627f1c255dSVassil Vassilev}
637f1c255dSVassil Vassilev
64c1db8cf9SFrederich Munchvoid DynamicLibrary::HandleSet::DLClose(void *Handle) {
65c1db8cf9SFrederich Munch  if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
66c1db8cf9SFrederich Munch    HS->Process = nullptr; // Just drop the *Process* handle.
67c1db8cf9SFrederich Munch  else
68c1db8cf9SFrederich Munch    FreeLibrary((HMODULE)Handle);
697f1c255dSVassil Vassilev}
707f1c255dSVassil Vassilev
71c1db8cf9SFrederich Munchstatic bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
72c1db8cf9SFrederich Munch  // EnumProcessModules will fail on Windows 64 while some versions of
73c1db8cf9SFrederich Munch  // MingW-32 don't have EnumProcessModulesEx.
74c1db8cf9SFrederich Munch  if (
75c1db8cf9SFrederich Munch#ifdef _WIN64
76c1db8cf9SFrederich Munch      !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
77c1db8cf9SFrederich Munch#else
78c1db8cf9SFrederich Munch      !EnumProcessModules(H, Data, Bytes, &Bytes)
79c1db8cf9SFrederich Munch#endif
80c1db8cf9SFrederich Munch     ) {
81c1db8cf9SFrederich Munch    std::string Err;
82c1db8cf9SFrederich Munch    if (MakeErrMsg(&Err, "EnumProcessModules failure"))
83c1db8cf9SFrederich Munch      llvm::errs() << Err << "\n";
84c1db8cf9SFrederich Munch    return false;
85c1db8cf9SFrederich Munch  }
86c1db8cf9SFrederich Munch  return true;
87c1db8cf9SFrederich Munch}
88c1db8cf9SFrederich Munch
89c1db8cf9SFrederich Munchvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
90c1db8cf9SFrederich Munch  HandleSet* HS = IsOpenedHandlesInstance(Handle);
91c1db8cf9SFrederich Munch  if (!HS)
92c1db8cf9SFrederich Munch    return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
93c1db8cf9SFrederich Munch
94c1db8cf9SFrederich Munch  // Could have done a dlclose on the *Process* handle
95c1db8cf9SFrederich Munch  if (!HS->Process)
96c1db8cf9SFrederich Munch    return nullptr;
97c1db8cf9SFrederich Munch
98c1db8cf9SFrederich Munch  // Trials indicate EnumProcessModulesEx is consistantly faster than using
99c1db8cf9SFrederich Munch  // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
100c1db8cf9SFrederich Munch  //
101c1db8cf9SFrederich Munch  // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
102c1db8cf9SFrederich Munch  // |=========|=============|========================================
103c1db8cf9SFrederich Munch  // | 37      | 0.0000585 * | 0.0003031      | 0.0000152
104c1db8cf9SFrederich Munch  // | 1020    | 0.0026310 * | 0.0121598      | 0.0002683
105c1db8cf9SFrederich Munch  // | 2084    | 0.0149418 * | 0.0369936      | 0.0005610
106c1db8cf9SFrederich Munch  //
107c1db8cf9SFrederich Munch  // * Not including the load time of Dbghelp.dll (~.005 sec)
108c1db8cf9SFrederich Munch  //
109c1db8cf9SFrederich Munch  // There's still a case to somehow cache the result of EnumProcessModulesEx
110c1db8cf9SFrederich Munch  // across invocations, but the complication of doing that properly...
111c1db8cf9SFrederich Munch  // Possibly using LdrRegisterDllNotification to invalidate the cache?
112c1db8cf9SFrederich Munch
113c1db8cf9SFrederich Munch  DWORD Bytes = 0;
114c1db8cf9SFrederich Munch  HMODULE Self = HMODULE(GetCurrentProcess());
115c1db8cf9SFrederich Munch  if (!GetProcessModules(Self, Bytes))
116c1db8cf9SFrederich Munch    return nullptr;
117c1db8cf9SFrederich Munch
118c1db8cf9SFrederich Munch  // Get the most recent list in case any modules added/removed between calls
119c1db8cf9SFrederich Munch  // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
120c1db8cf9SFrederich Munch  // MSDN is pretty clear that if the module list changes during the call to
121c1db8cf9SFrederich Munch  // EnumProcessModulesEx the results should not be used.
122c1db8cf9SFrederich Munch  std::vector<HMODULE> Handles;
123c1db8cf9SFrederich Munch  do {
124c1db8cf9SFrederich Munch    assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
125c1db8cf9SFrederich Munch           "Should have at least one module and be aligned");
126c1db8cf9SFrederich Munch    Handles.resize(Bytes / sizeof(HMODULE));
127c1db8cf9SFrederich Munch    if (!GetProcessModules(Self, Bytes, Handles.data()))
128c1db8cf9SFrederich Munch      return nullptr;
129c1db8cf9SFrederich Munch  } while (Bytes != (Handles.size() * sizeof(HMODULE)));
130c1db8cf9SFrederich Munch
131c1db8cf9SFrederich Munch  // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
132c1db8cf9SFrederich Munch  if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
133c1db8cf9SFrederich Munch    return (void *) uintptr_t(Ptr);
134c1db8cf9SFrederich Munch
135c1db8cf9SFrederich Munch  if (Handles.size() > 1) {
136c1db8cf9SFrederich Munch    // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
137c1db8cf9SFrederich Munch    // Doing that here is causing real problems for the JIT where msvc.dll
138c1db8cf9SFrederich Munch    // and ucrt.dll can define the same symbols. The runtime linker will choose
139c1db8cf9SFrederich Munch    // symbols from ucrt.dll first, but iterating NOT in reverse here would
140c1db8cf9SFrederich Munch    // mean that the msvc.dll versions would be returned.
141c1db8cf9SFrederich Munch
142c1db8cf9SFrederich Munch    for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
143c1db8cf9SFrederich Munch      if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
144c1db8cf9SFrederich Munch        return (void *) uintptr_t(Ptr);
145c1db8cf9SFrederich Munch    }
146c1db8cf9SFrederich Munch  }
147c1db8cf9SFrederich Munch  return nullptr;
148c1db8cf9SFrederich Munch}
149c1db8cf9SFrederich Munch
150c1db8cf9SFrederich Munch
151447762daSMichael J. Spencer// Stack probing routines are in the support library (e.g. libgcc), but we don't
152447762daSMichael J. Spencer// have dynamic linking on windows. Provide a hook.
153447762daSMichael J. Spencer#define EXPLICIT_SYMBOL(SYM)                    \
154447762daSMichael J. Spencer  extern "C" { extern void *SYM; }
15503a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
156447762daSMichael J. Spencer
1579aeb0479SReid Kleckner#ifdef _M_IX86
1589aeb0479SReid Kleckner// Win32 on x86 implements certain single-precision math functions as macros.
1599aeb0479SReid Kleckner// These functions are not exported by the DLL, but will still be needed
1609aeb0479SReid Kleckner// for symbol-resolution by the JIT loader. Therefore, this Support libray
1619aeb0479SReid Kleckner// provides helper functions with the same implementation.
1629aeb0479SReid Kleckner
1639aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
1649aeb0479SReid Kleckner  extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }
1659aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL2(TYP, SYM)                                           \
1669aeb0479SReid Kleckner  extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }
1679aeb0479SReid Kleckner#endif
1689aeb0479SReid Kleckner
16903a541f5SNAKAMURA Takumi#include "explicit_symbols.inc"
17003a541f5SNAKAMURA Takumi
17103a541f5SNAKAMURA Takumi#undef EXPLICIT_SYMBOL
17203a541f5SNAKAMURA Takumi#undef EXPLICIT_SYMBOL2
1739aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL1
1749aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL2
175447762daSMichael J. Spencer
176c1db8cf9SFrederich Munchstatic void *DoSearch(const char *SymbolName) {
177447762daSMichael J. Spencer
17803a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL(SYM)                                                   \
179c1db8cf9SFrederich Munch  if (!strcmp(SymbolName, #SYM))                                               \
1809aeb0479SReid Kleckner    return (void *)&SYM;
18103a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO)                                       \
182c1db8cf9SFrederich Munch  if (!strcmp(SymbolName, #SYMFROM))                                           \
1839aeb0479SReid Kleckner    return (void *)&SYMTO;
1849aeb0479SReid Kleckner
1859aeb0479SReid Kleckner#ifdef _M_IX86
1869aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
187c1db8cf9SFrederich Munch  if (!strcmp(SymbolName, #SYM))                                               \
1889aeb0479SReid Kleckner    return (void *)&inline_##SYM;
1899aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
1909aeb0479SReid Kleckner#endif
191447762daSMichael J. Spencer
192447762daSMichael J. Spencer  {
19303a541f5SNAKAMURA Takumi#include "explicit_symbols.inc"
19403a541f5SNAKAMURA Takumi  }
19503a541f5SNAKAMURA Takumi
196447762daSMichael J. Spencer#undef EXPLICIT_SYMBOL
197447762daSMichael J. Spencer#undef EXPLICIT_SYMBOL2
1989aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL1
1999aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL2
200447762daSMichael J. Spencer
201c1db8cf9SFrederich Munch  return nullptr;
202447762daSMichael J. Spencer}
203