diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm/lib/Support/Windows | |
parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) |
Move all sources from the llvm project into contrib/llvm-project.
This uses the new layout of the upstream repository, which was recently
migrated to GitHub, and converted into a "monorepo". That is, most of
the earlier separate sub-projects with their own branches and tags were
consolidated into one top-level directory, and are now branched and
tagged together.
Updating the vendor area to match this layout is next.
Notes
Notes:
svn path=/head/; revision=355940
Diffstat (limited to 'contrib/llvm/lib/Support/Windows')
-rw-r--r-- | contrib/llvm/lib/Support/Windows/COM.inc | 36 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/DynamicLibrary.inc | 202 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Host.inc | 33 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Memory.inc | 200 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Mutex.inc | 56 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Path.inc | 1515 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Process.inc | 485 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Program.inc | 523 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/RWMutex.inc | 128 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Signals.inc | 874 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/ThreadLocal.inc | 51 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Threading.inc | 124 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Watchdog.inc | 23 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/WindowsSupport.h | 234 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/explicit_symbols.inc | 102 |
15 files changed, 0 insertions, 4586 deletions
diff --git a/contrib/llvm/lib/Support/Windows/COM.inc b/contrib/llvm/lib/Support/Windows/COM.inc deleted file mode 100644 index 002182bc3939..000000000000 --- a/contrib/llvm/lib/Support/Windows/COM.inc +++ /dev/null @@ -1,36 +0,0 @@ -//==- llvm/Support/Windows/COM.inc - Windows COM 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 implements the Windows portion of COM support. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Windows code. -//===----------------------------------------------------------------------===// - -#include <objbase.h> - -namespace llvm { -namespace sys { - -InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, - bool SpeedOverMemory) { - DWORD Coinit = 0; - if (Threading == COMThreadingMode::SingleThreaded) - Coinit |= COINIT_APARTMENTTHREADED; - else - Coinit |= COINIT_MULTITHREADED; - if (SpeedOverMemory) - Coinit |= COINIT_SPEED_OVER_MEMORY; - ::CoInitializeEx(nullptr, Coinit); -} - -InitializeCOMRAII::~InitializeCOMRAII() { ::CoUninitialize(); } -} -} diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc deleted file mode 100644 index 71b206c4cf9e..000000000000 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ /dev/null @@ -1,202 +0,0 @@ -//===- 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 "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; -} diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc deleted file mode 100644 index 21b947f26df3..000000000000 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ /dev/null @@ -1,33 +0,0 @@ -//===- llvm/Support/Win32/Host.inc ------------------------------*- 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 implements the Win32 Host support. -// -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" -#include <cstdio> -#include <string> - -using namespace llvm; - -static std::string updateTripleOSVersion(std::string Triple) { - return Triple; -} - -std::string sys::getDefaultTargetTriple() { - const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; - - // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. -#if defined(LLVM_TARGET_TRIPLE_ENV) - if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) - Triple = EnvTriple; -#endif - - return Triple; -} diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc deleted file mode 100644 index a67f9c7d0f35..000000000000 --- a/contrib/llvm/lib/Support/Windows/Memory.inc +++ /dev/null @@ -1,200 +0,0 @@ -//===- Win32/Memory.cpp - Win32 Memory 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 various Memory -// management utilities -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/WindowsError.h" - -// The Windows.h header must be the last one included. -#include "WindowsSupport.h" - -namespace { - -DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { - // Contrary to what you might expect, the Windows page protection flags - // are not a bitwise combination of RWX values - case llvm::sys::Memory::MF_READ: - return PAGE_READONLY; - case llvm::sys::Memory::MF_WRITE: - // Note: PAGE_WRITE is not supported by VirtualProtect - return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: - return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE_READ; - case llvm::sys::Memory::MF_READ | - llvm::sys::Memory::MF_WRITE | - llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE_READWRITE; - case llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE; - default: - llvm_unreachable("Illegal memory protection flag specified!"); - } - // Provide a default return value as required by some compilers. - return PAGE_NOACCESS; -} - -// While we'd be happy to allocate single pages, the Windows allocation -// granularity may be larger than a single page (in practice, it is 64K) -// so mapping less than that will create an unreachable fragment of memory. -size_t getAllocationGranularity() { - SYSTEM_INFO Info; - ::GetSystemInfo(&Info); - if (Info.dwPageSize > Info.dwAllocationGranularity) - return Info.dwPageSize; - else - return Info.dwAllocationGranularity; -} - -// Large/huge memory pages need explicit process permissions in order to be -// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 -// Also large pages need to be manually enabled on your OS. If all this is -// sucessfull, we return the minimal large memory page size. -static size_t enableProcessLargePages() { - HANDLE Token = 0; - size_t LargePageMin = GetLargePageMinimum(); - if (LargePageMin) - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - &Token); - if (!Token) - return 0; - LUID Luid; - if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { - CloseHandle(Token); - return 0; - } - TOKEN_PRIVILEGES TP{}; - TP.PrivilegeCount = 1; - TP.Privileges[0].Luid = Luid; - TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { - CloseHandle(Token); - return 0; - } - DWORD E = GetLastError(); - CloseHandle(Token); - if (E == ERROR_SUCCESS) - return LargePageMin; - return 0; -} - -} // namespace - -namespace llvm { -namespace sys { - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, - const MemoryBlock *const NearBlock, - unsigned Flags, - std::error_code &EC) { - EC = std::error_code(); - if (NumBytes == 0) - return MemoryBlock(); - - static size_t DefaultGranularity = getAllocationGranularity(); - static size_t LargePageGranularity = enableProcessLargePages(); - - DWORD AllocType = MEM_RESERVE | MEM_COMMIT; - bool HugePages = false; - size_t Granularity = DefaultGranularity; - - if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { - AllocType |= MEM_LARGE_PAGES; - HugePages = true; - Granularity = LargePageGranularity; - } - - size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; - - uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + - NearBlock->allocatedSize() - : 0; - - // If the requested address is not aligned to the allocation granularity, - // round up to get beyond NearBlock. VirtualAlloc would have rounded down. - if (Start && Start % Granularity != 0) - Start += Granularity - Start % Granularity; - - DWORD Protect = getWindowsProtectionFlags(Flags); - - size_t AllocSize = NumBlocks * Granularity; - void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), - AllocSize, AllocType, Protect); - if (PA == NULL) { - if (NearBlock || HugePages) { - // Try again without the NearBlock hint and without large memory pages - return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); - } - EC = mapWindowsError(::GetLastError()); - return MemoryBlock(); - } - - MemoryBlock Result; - Result.Address = PA; - Result.AllocatedSize = AllocSize; - Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); - - if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(Result.Address, AllocSize); - - return Result; -} - - std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { - if (M.Address == 0 || M.AllocatedSize == 0) - return std::error_code(); - - if (!VirtualFree(M.Address, 0, MEM_RELEASE)) - return mapWindowsError(::GetLastError()); - - M.Address = 0; - M.AllocatedSize = 0; - - return std::error_code(); -} - - std::error_code Memory::protectMappedMemory(const MemoryBlock &M, - unsigned Flags) { - if (M.Address == 0 || M.AllocatedSize == 0) - return std::error_code(); - - DWORD Protect = getWindowsProtectionFlags(Flags); - - DWORD OldFlags; - if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) - return mapWindowsError(::GetLastError()); - - if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); - - return std::error_code(); -} - -/// InvalidateInstructionCache - Before the JIT can run a block of code -/// that has been emitted it must invalidate the instruction cache on some -/// platforms. -void Memory::InvalidateInstructionCache( - const void *Addr, size_t Len) { - FlushInstructionCache(GetCurrentProcess(), Addr, Len); -} - -} // namespace sys -} // namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/Mutex.inc b/contrib/llvm/lib/Support/Windows/Mutex.inc deleted file mode 100644 index b55b14febf2c..000000000000 --- a/contrib/llvm/lib/Support/Windows/Mutex.inc +++ /dev/null @@ -1,56 +0,0 @@ -//===- llvm/Support/Win32/Mutex.inc - Win32 Mutex 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 implements the Win32 specific (non-pthread) Mutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" -#include "llvm/Support/Mutex.h" - -namespace llvm { - -sys::MutexImpl::MutexImpl(bool /*recursive*/) -{ - data_ = new CRITICAL_SECTION; - InitializeCriticalSection((LPCRITICAL_SECTION)data_); -} - -sys::MutexImpl::~MutexImpl() -{ - DeleteCriticalSection((LPCRITICAL_SECTION)data_); - delete (LPCRITICAL_SECTION)data_; - data_ = 0; -} - -bool -sys::MutexImpl::acquire() -{ - EnterCriticalSection((LPCRITICAL_SECTION)data_); - return true; -} - -bool -sys::MutexImpl::release() -{ - LeaveCriticalSection((LPCRITICAL_SECTION)data_); - return true; -} - -bool -sys::MutexImpl::tryacquire() -{ - return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); -} - -} diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc deleted file mode 100644 index 5704930aeecc..000000000000 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ /dev/null @@ -1,1515 +0,0 @@ -//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- 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 implements the Windows specific implementation of the Path API. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Windows code that -//=== is guaranteed to work on *all* Windows variants. -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/WindowsError.h" -#include <fcntl.h> -#include <io.h> -#include <sys/stat.h> -#include <sys/types.h> - -// These two headers must be included last, and make sure shlobj is required -// after Windows.h to make sure it picks up our definition of _WIN32_WINNT -#include "WindowsSupport.h" -#include <shellapi.h> -#include <shlobj.h> - -#undef max - -// MinGW doesn't define this. -#ifndef _ERRNO_T_DEFINED -#define _ERRNO_T_DEFINED -typedef int errno_t; -#endif - -#ifdef _MSC_VER -# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. -# pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree -#endif - -using namespace llvm; - -using llvm::sys::windows::UTF8ToUTF16; -using llvm::sys::windows::CurCPToUTF16; -using llvm::sys::windows::UTF16ToUTF8; -using llvm::sys::path::widenPath; - -static bool is_separator(const wchar_t value) { - switch (value) { - case L'\\': - case L'/': - return true; - default: - return false; - } -} - -namespace llvm { -namespace sys { -namespace path { - -// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the -// path is longer than CreateDirectory can tolerate, make it absolute and -// prefixed by '\\?\'. -std::error_code widenPath(const Twine &Path8, - SmallVectorImpl<wchar_t> &Path16) { - const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. - - // Several operations would convert Path8 to SmallString; more efficient to - // do it once up front. - SmallString<128> Path8Str; - Path8.toVector(Path8Str); - - // If we made this path absolute, how much longer would it get? - size_t CurPathLen; - if (llvm::sys::path::is_absolute(Twine(Path8Str))) - CurPathLen = 0; // No contribution from current_path needed. - else { - CurPathLen = ::GetCurrentDirectoryW(0, NULL); - if (CurPathLen == 0) - return mapWindowsError(::GetLastError()); - } - - // Would the absolute path be longer than our limit? - if ((Path8Str.size() + CurPathLen) >= MaxDirLen && - !Path8Str.startswith("\\\\?\\")) { - SmallString<2*MAX_PATH> FullPath("\\\\?\\"); - if (CurPathLen) { - SmallString<80> CurPath; - if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) - return EC; - FullPath.append(CurPath); - } - // Traverse the requested path, canonicalizing . and .. (because the \\?\ - // prefix is documented to treat them as real components). Ignore - // separators, which can be returned from the iterator if the path has a - // drive name. We don't need to call native() on the result since append() - // always attaches preferred_separator. - for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), - E = llvm::sys::path::end(Path8Str); - I != E; ++I) { - if (I->size() == 1 && is_separator((*I)[0])) - continue; - if (I->size() == 1 && *I == ".") - continue; - if (I->size() == 2 && *I == "..") - llvm::sys::path::remove_filename(FullPath); - else - llvm::sys::path::append(FullPath, *I); - } - return UTF8ToUTF16(FullPath, Path16); - } - - // Just use the caller's original path. - return UTF8ToUTF16(Path8Str, Path16); -} -} // end namespace path - -namespace fs { - -const file_t kInvalidFile = INVALID_HANDLE_VALUE; - -std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - SmallVector<wchar_t, MAX_PATH> PathName; - DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); - - // A zero return value indicates a failure other than insufficient space. - if (Size == 0) - return ""; - - // Insufficient space is determined by a return value equal to the size of - // the buffer passed in. - if (Size == PathName.capacity()) - return ""; - - // On success, GetModuleFileNameW returns the number of characters written to - // the buffer not including the NULL terminator. - PathName.set_size(Size); - - // Convert the result from UTF-16 to UTF-8. - SmallVector<char, MAX_PATH> PathNameUTF8; - if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) - return ""; - - return std::string(PathNameUTF8.data()); -} - -UniqueID file_status::getUniqueID() const { - // The file is uniquely identified by the volume serial number along - // with the 64-bit file identifier. - uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | - static_cast<uint64_t>(FileIndexLow); - - return UniqueID(VolumeSerialNumber, FileID); -} - -ErrorOr<space_info> disk_space(const Twine &Path) { - ULARGE_INTEGER Avail, Total, Free; - if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) - return mapWindowsError(::GetLastError()); - space_info SpaceInfo; - SpaceInfo.capacity = - (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart; - SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart; - SpaceInfo.available = - (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart; - return SpaceInfo; -} - -TimePoint<> basic_file_status::getLastAccessedTime() const { - FILETIME Time; - Time.dwLowDateTime = LastAccessedTimeLow; - Time.dwHighDateTime = LastAccessedTimeHigh; - return toTimePoint(Time); -} - -TimePoint<> basic_file_status::getLastModificationTime() const { - FILETIME Time; - Time.dwLowDateTime = LastWriteTimeLow; - Time.dwHighDateTime = LastWriteTimeHigh; - return toTimePoint(Time); -} - -uint32_t file_status::getLinkCount() const { - return NumLinks; -} - -std::error_code current_path(SmallVectorImpl<char> &result) { - SmallVector<wchar_t, MAX_PATH> cur_path; - DWORD len = MAX_PATH; - - do { - cur_path.reserve(len); - len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return mapWindowsError(::GetLastError()); - - // If there's insufficient space, the len returned is larger than the len - // given. - } while (len > cur_path.capacity()); - - // On success, GetCurrentDirectoryW returns the number of characters not - // including the null-terminator. - cur_path.set_size(len); - return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); -} - -std::error_code set_current_path(const Twine &path) { - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_path; - if (std::error_code ec = widenPath(path, wide_path)) - return ec; - - if (!::SetCurrentDirectoryW(wide_path.begin())) - return mapWindowsError(::GetLastError()); - - return std::error_code(); -} - -std::error_code create_directory(const Twine &path, bool IgnoreExisting, - perms Perms) { - SmallVector<wchar_t, 128> path_utf16; - - if (std::error_code ec = widenPath(path, path_utf16)) - return ec; - - if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { - DWORD LastError = ::GetLastError(); - if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) - return mapWindowsError(LastError); - } - - return std::error_code(); -} - -// We can't use symbolic links for windows. -std::error_code create_link(const Twine &to, const Twine &from) { - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (std::error_code ec = widenPath(from, wide_from)) - return ec; - if (std::error_code ec = widenPath(to, wide_to)) - return ec; - - if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) - return mapWindowsError(::GetLastError()); - - return std::error_code(); -} - -std::error_code create_hard_link(const Twine &to, const Twine &from) { - return create_link(to, from); -} - -std::error_code remove(const Twine &path, bool IgnoreNonExisting) { - SmallVector<wchar_t, 128> path_utf16; - - if (std::error_code ec = widenPath(path, path_utf16)) - return ec; - - // We don't know whether this is a file or a directory, and remove() can - // accept both. The usual way to delete a file or directory is to use one of - // the DeleteFile or RemoveDirectory functions, but that requires you to know - // which one it is. We could stat() the file to determine that, but that would - // cost us additional system calls, which can be slow in a directory - // containing a large number of files. So instead we call CreateFile directly. - // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the - // file to be deleted once it is closed. We also use the flags - // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and - // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). - ScopedFileHandle h(::CreateFileW( - c_str(path_utf16), DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, - NULL)); - if (!h) { - std::error_code EC = mapWindowsError(::GetLastError()); - if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) - return EC; - } - - return std::error_code(); -} - -static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, - bool &Result) { - SmallVector<wchar_t, 128> VolumePath; - size_t Len = 128; - while (true) { - VolumePath.resize(Len); - BOOL Success = - ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); - - if (Success) - break; - - DWORD Err = ::GetLastError(); - if (Err != ERROR_INSUFFICIENT_BUFFER) - return mapWindowsError(Err); - - Len *= 2; - } - // If the output buffer has exactly enough space for the path name, but not - // the null terminator, it will leave the output unterminated. Push a null - // terminator onto the end to ensure that this never happens. - VolumePath.push_back(L'\0'); - VolumePath.set_size(wcslen(VolumePath.data())); - const wchar_t *P = VolumePath.data(); - - UINT Type = ::GetDriveTypeW(P); - switch (Type) { - case DRIVE_FIXED: - Result = true; - return std::error_code(); - case DRIVE_REMOTE: - case DRIVE_CDROM: - case DRIVE_RAMDISK: - case DRIVE_REMOVABLE: - Result = false; - return std::error_code(); - default: - return make_error_code(errc::no_such_file_or_directory); - } - llvm_unreachable("Unreachable!"); -} - -std::error_code is_local(const Twine &path, bool &result) { - if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) - return make_error_code(errc::no_such_file_or_directory); - - SmallString<128> Storage; - StringRef P = path.toStringRef(Storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> WidePath; - if (std::error_code ec = widenPath(P, WidePath)) - return ec; - return is_local_internal(WidePath, result); -} - -static std::error_code realPathFromHandle(HANDLE H, - SmallVectorImpl<wchar_t> &Buffer) { - DWORD CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); - if (CountChars > Buffer.capacity()) { - // The buffer wasn't big enough, try again. In this case the return value - // *does* indicate the size of the null terminator. - Buffer.reserve(CountChars); - CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); - } - if (CountChars == 0) - return mapWindowsError(GetLastError()); - Buffer.set_size(CountChars); - return std::error_code(); -} - -static std::error_code realPathFromHandle(HANDLE H, - SmallVectorImpl<char> &RealPath) { - RealPath.clear(); - SmallVector<wchar_t, MAX_PATH> Buffer; - if (std::error_code EC = realPathFromHandle(H, Buffer)) - return EC; - - const wchar_t *Data = Buffer.data(); - DWORD CountChars = Buffer.size(); - if (CountChars >= 4) { - if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { - CountChars -= 4; - Data += 4; - } - } - - // Convert the result from UTF-16 to UTF-8. - return UTF16ToUTF8(Data, CountChars, RealPath); -} - -std::error_code is_local(int FD, bool &Result) { - SmallVector<wchar_t, 128> FinalPath; - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - - if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) - return EC; - - return is_local_internal(FinalPath, Result); -} - -static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { - FILE_DISPOSITION_INFO Disposition; - Disposition.DeleteFile = Delete; - if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, - sizeof(Disposition))) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, - bool ReplaceIfExists) { - SmallVector<wchar_t, 0> ToWide; - if (auto EC = widenPath(To, ToWide)) - return EC; - - std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + - (ToWide.size() * sizeof(wchar_t))); - FILE_RENAME_INFO &RenameInfo = - *reinterpret_cast<FILE_RENAME_INFO *>(RenameInfoBuf.data()); - RenameInfo.ReplaceIfExists = ReplaceIfExists; - RenameInfo.RootDirectory = 0; - RenameInfo.FileNameLength = ToWide.size() * sizeof(wchar_t); - std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); - - SetLastError(ERROR_SUCCESS); - if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, - RenameInfoBuf.size())) { - unsigned Error = GetLastError(); - if (Error == ERROR_SUCCESS) - Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. - return mapWindowsError(Error); - } - - return std::error_code(); -} - -static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { - SmallVector<wchar_t, 128> WideTo; - if (std::error_code EC = widenPath(To, WideTo)) - return EC; - - // We normally expect this loop to succeed after a few iterations. If it - // requires more than 200 tries, it's more likely that the failures are due to - // a true error, so stop trying. - for (unsigned Retry = 0; Retry != 200; ++Retry) { - auto EC = rename_internal(FromHandle, To, true); - - if (EC == - std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { - // Wine doesn't support SetFileInformationByHandle in rename_internal. - // Fall back to MoveFileEx. - SmallVector<wchar_t, MAX_PATH> WideFrom; - if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) - return EC2; - if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), - MOVEFILE_REPLACE_EXISTING)) - return std::error_code(); - return mapWindowsError(GetLastError()); - } - - if (!EC || EC != errc::permission_denied) - return EC; - - // The destination file probably exists and is currently open in another - // process, either because the file was opened without FILE_SHARE_DELETE or - // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to - // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE - // to arrange for the destination file to be deleted when the other process - // closes it. - ScopedFileHandle ToHandle( - ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); - if (!ToHandle) { - auto EC = mapWindowsError(GetLastError()); - // Another process might have raced with us and moved the existing file - // out of the way before we had a chance to open it. If that happens, try - // to rename the source file again. - if (EC == errc::no_such_file_or_directory) - continue; - return EC; - } - - BY_HANDLE_FILE_INFORMATION FI; - if (!GetFileInformationByHandle(ToHandle, &FI)) - return mapWindowsError(GetLastError()); - - // Try to find a unique new name for the destination file. - for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { - std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); - if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { - if (EC == errc::file_exists || EC == errc::permission_denied) { - // Again, another process might have raced with us and moved the file - // before we could move it. Check whether this is the case, as it - // might have caused the permission denied error. If that was the - // case, we don't need to move it ourselves. - ScopedFileHandle ToHandle2(::CreateFileW( - WideTo.begin(), 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); - if (!ToHandle2) { - auto EC = mapWindowsError(GetLastError()); - if (EC == errc::no_such_file_or_directory) - break; - return EC; - } - BY_HANDLE_FILE_INFORMATION FI2; - if (!GetFileInformationByHandle(ToHandle2, &FI2)) - return mapWindowsError(GetLastError()); - if (FI.nFileIndexHigh != FI2.nFileIndexHigh || - FI.nFileIndexLow != FI2.nFileIndexLow || - FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) - break; - continue; - } - return EC; - } - break; - } - - // Okay, the old destination file has probably been moved out of the way at - // this point, so try to rename the source file again. Still, another - // process might have raced with us to create and open the destination - // file, so we need to keep doing this until we succeed. - } - - // The most likely root cause. - return errc::permission_denied; -} - -static std::error_code rename_fd(int FromFD, const Twine &To) { - HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD)); - return rename_handle(FromHandle, To); -} - -std::error_code rename(const Twine &From, const Twine &To) { - // Convert to utf-16. - SmallVector<wchar_t, 128> WideFrom; - if (std::error_code EC = widenPath(From, WideFrom)) - return EC; - - ScopedFileHandle FromHandle; - // Retry this a few times to defeat badly behaved file system scanners. - for (unsigned Retry = 0; Retry != 200; ++Retry) { - if (Retry != 0) - ::Sleep(10); - FromHandle = - ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (FromHandle) - break; - } - if (!FromHandle) - return mapWindowsError(GetLastError()); - - return rename_handle(FromHandle, To); -} - -std::error_code resize_file(int FD, uint64_t Size) { -#ifdef HAVE__CHSIZE_S - errno_t error = ::_chsize_s(FD, Size); -#else - errno_t error = ::_chsize(FD, Size); -#endif - return std::error_code(error, std::generic_category()); -} - -std::error_code access(const Twine &Path, AccessMode Mode) { - SmallVector<wchar_t, 128> PathUtf16; - - if (std::error_code EC = widenPath(Path, PathUtf16)) - return EC; - - DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); - - if (Attributes == INVALID_FILE_ATTRIBUTES) { - // See if the file didn't actually exist. - DWORD LastError = ::GetLastError(); - if (LastError != ERROR_FILE_NOT_FOUND && - LastError != ERROR_PATH_NOT_FOUND) - return mapWindowsError(LastError); - return errc::no_such_file_or_directory; - } - - if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) - return errc::permission_denied; - - return std::error_code(); -} - -bool can_execute(const Twine &Path) { - return !access(Path, AccessMode::Execute) || - !access(Path + ".exe", AccessMode::Execute); -} - -bool equivalent(file_status A, file_status B) { - assert(status_known(A) && status_known(B)); - return A.FileIndexHigh == B.FileIndexHigh && - A.FileIndexLow == B.FileIndexLow && - A.FileSizeHigh == B.FileSizeHigh && - A.FileSizeLow == B.FileSizeLow && - A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && - A.LastAccessedTimeLow == B.LastAccessedTimeLow && - A.LastWriteTimeHigh == B.LastWriteTimeHigh && - A.LastWriteTimeLow == B.LastWriteTimeLow && - A.VolumeSerialNumber == B.VolumeSerialNumber; -} - -std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { - file_status fsA, fsB; - if (std::error_code ec = status(A, fsA)) - return ec; - if (std::error_code ec = status(B, fsB)) - return ec; - result = equivalent(fsA, fsB); - return std::error_code(); -} - -static bool isReservedName(StringRef path) { - // This list of reserved names comes from MSDN, at: - // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx - static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", - "com1", "com2", "com3", "com4", - "com5", "com6", "com7", "com8", - "com9", "lpt1", "lpt2", "lpt3", - "lpt4", "lpt5", "lpt6", "lpt7", - "lpt8", "lpt9" }; - - // First, check to see if this is a device namespace, which always - // starts with \\.\, since device namespaces are not legal file paths. - if (path.startswith("\\\\.\\")) - return true; - - // Then compare against the list of ancient reserved names. - for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { - if (path.equals_lower(sReservedNames[i])) - return true; - } - - // The path isn't what we consider reserved. - return false; -} - -static file_type file_type_from_attrs(DWORD Attrs) { - return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file - : file_type::regular_file; -} - -static perms perms_from_attrs(DWORD Attrs) { - return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; -} - -static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { - if (FileHandle == INVALID_HANDLE_VALUE) - goto handle_status_error; - - switch (::GetFileType(FileHandle)) { - default: - llvm_unreachable("Don't know anything about this file type"); - case FILE_TYPE_UNKNOWN: { - DWORD Err = ::GetLastError(); - if (Err != NO_ERROR) - return mapWindowsError(Err); - Result = file_status(file_type::type_unknown); - return std::error_code(); - } - case FILE_TYPE_DISK: - break; - case FILE_TYPE_CHAR: - Result = file_status(file_type::character_file); - return std::error_code(); - case FILE_TYPE_PIPE: - Result = file_status(file_type::fifo_file); - return std::error_code(); - } - - BY_HANDLE_FILE_INFORMATION Info; - if (!::GetFileInformationByHandle(FileHandle, &Info)) - goto handle_status_error; - - Result = file_status( - file_type_from_attrs(Info.dwFileAttributes), - perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, - Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, - Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, - Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, - Info.nFileIndexHigh, Info.nFileIndexLow); - return std::error_code(); - -handle_status_error: - DWORD LastError = ::GetLastError(); - if (LastError == ERROR_FILE_NOT_FOUND || - LastError == ERROR_PATH_NOT_FOUND) - Result = file_status(file_type::file_not_found); - else if (LastError == ERROR_SHARING_VIOLATION) - Result = file_status(file_type::type_unknown); - else - Result = file_status(file_type::status_error); - return mapWindowsError(LastError); -} - -std::error_code status(const Twine &path, file_status &result, bool Follow) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - StringRef path8 = path.toStringRef(path_storage); - if (isReservedName(path8)) { - result = file_status(file_type::character_file); - return std::error_code(); - } - - if (std::error_code ec = widenPath(path8, path_utf16)) - return ec; - - DWORD attr = ::GetFileAttributesW(path_utf16.begin()); - if (attr == INVALID_FILE_ATTRIBUTES) - return getStatus(INVALID_HANDLE_VALUE, result); - - DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; - // Handle reparse points. - if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) - Flags |= FILE_FLAG_OPEN_REPARSE_POINT; - - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, Flags, 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); - - return getStatus(h, result); -} - -std::error_code status(int FD, file_status &Result) { - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - return getStatus(FileHandle, Result); -} - -std::error_code status(file_t FileHandle, file_status &Result) { - return getStatus(FileHandle, Result); -} - -unsigned getUmask() { - return 0; -} - -std::error_code setPermissions(const Twine &Path, perms Permissions) { - SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = widenPath(Path, PathUTF16)) - return EC; - - DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); - if (Attributes == INVALID_FILE_ATTRIBUTES) - return mapWindowsError(GetLastError()); - - // There are many Windows file attributes that are not to do with the file - // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve - // them. - if (Permissions & all_write) { - Attributes &= ~FILE_ATTRIBUTE_READONLY; - if (Attributes == 0) - // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. - Attributes |= FILE_ATTRIBUTE_NORMAL; - } - else { - Attributes |= FILE_ATTRIBUTE_READONLY; - // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so - // remove it, if it is present. - Attributes &= ~FILE_ATTRIBUTE_NORMAL; - } - - if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) - return mapWindowsError(GetLastError()); - - return std::error_code(); -} - -std::error_code setPermissions(int FD, perms Permissions) { - // FIXME Not implemented. - return std::make_error_code(std::errc::not_supported); -} - -std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, - TimePoint<> ModificationTime) { - FILETIME AccessFT = toFILETIME(AccessTime); - FILETIME ModifyFT = toFILETIME(ModificationTime); - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - if (!SetFileTime(FileHandle, NULL, &AccessFT, &ModifyFT)) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, - uint64_t Offset, mapmode Mode) { - this->Mode = Mode; - if (OrigFileHandle == INVALID_HANDLE_VALUE) - return make_error_code(errc::bad_file_descriptor); - - DWORD flprotect; - switch (Mode) { - case readonly: flprotect = PAGE_READONLY; break; - case readwrite: flprotect = PAGE_READWRITE; break; - case priv: flprotect = PAGE_WRITECOPY; break; - } - - HANDLE FileMappingHandle = - ::CreateFileMappingW(OrigFileHandle, 0, flprotect, - Hi_32(Size), - Lo_32(Size), - 0); - if (FileMappingHandle == NULL) { - std::error_code ec = mapWindowsError(GetLastError()); - return ec; - } - - DWORD dwDesiredAccess; - switch (Mode) { - case readonly: dwDesiredAccess = FILE_MAP_READ; break; - case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; - case priv: dwDesiredAccess = FILE_MAP_COPY; break; - } - Mapping = ::MapViewOfFile(FileMappingHandle, - dwDesiredAccess, - Offset >> 32, - Offset & 0xffffffff, - Size); - if (Mapping == NULL) { - std::error_code ec = mapWindowsError(GetLastError()); - ::CloseHandle(FileMappingHandle); - return ec; - } - - if (Size == 0) { - MEMORY_BASIC_INFORMATION mbi; - SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); - if (Result == 0) { - std::error_code ec = mapWindowsError(GetLastError()); - ::UnmapViewOfFile(Mapping); - ::CloseHandle(FileMappingHandle); - return ec; - } - Size = mbi.RegionSize; - } - - // Close the file mapping handle, as it's kept alive by the file mapping. But - // neither the file mapping nor the file mapping handle keep the file handle - // alive, so we need to keep a reference to the file in case all other handles - // are closed and the file is deleted, which may cause invalid data to be read - // from the file. - ::CloseHandle(FileMappingHandle); - if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, - ::GetCurrentProcess(), &FileHandle, 0, 0, - DUPLICATE_SAME_ACCESS)) { - std::error_code ec = mapWindowsError(GetLastError()); - ::UnmapViewOfFile(Mapping); - return ec; - } - - return std::error_code(); -} - -mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, - size_t length, uint64_t offset, - std::error_code &ec) - : Size(length), Mapping() { - ec = init(fd, offset, mode); - if (ec) - Mapping = 0; -} - -static bool hasFlushBufferKernelBug() { - static bool Ret{GetWindowsOSVersion() < llvm::VersionTuple(10, 0, 0, 17763)}; - return Ret; -} - -static bool isEXE(StringRef Magic) { - static const char PEMagic[] = {'P', 'E', '\0', '\0'}; - if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) { - uint32_t off = read32le(Magic.data() + 0x3c); - // PE/COFF file, either EXE or DLL. - if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic)))) - return true; - } - return false; -} - -mapped_file_region::~mapped_file_region() { - if (Mapping) { - - bool Exe = isEXE(StringRef((char *)Mapping, Size)); - - ::UnmapViewOfFile(Mapping); - - if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) { - // There is a Windows kernel bug, the exact trigger conditions of which - // are not well understood. When triggered, dirty pages are not properly - // flushed and subsequent process's attempts to read a file can return - // invalid data. Calling FlushFileBuffers on the write handle is - // sufficient to ensure that this bug is not triggered. - // The bug only occurs when writing an executable and executing it right - // after, under high I/O pressure. - ::FlushFileBuffers(FileHandle); - } - - ::CloseHandle(FileHandle); - } -} - -size_t mapped_file_region::size() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Size; -} - -char *mapped_file_region::data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<char*>(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<const char*>(Mapping); -} - -int mapped_file_region::alignment() { - SYSTEM_INFO SysInfo; - ::GetSystemInfo(&SysInfo); - return SysInfo.dwAllocationGranularity; -} - -static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { - return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), - perms_from_attrs(FindData->dwFileAttributes), - FindData->ftLastAccessTime.dwHighDateTime, - FindData->ftLastAccessTime.dwLowDateTime, - FindData->ftLastWriteTime.dwHighDateTime, - FindData->ftLastWriteTime.dwLowDateTime, - FindData->nFileSizeHigh, FindData->nFileSizeLow); -} - -std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, - StringRef Path, - bool FollowSymlinks) { - SmallVector<wchar_t, 128> PathUTF16; - - if (std::error_code EC = widenPath(Path, PathUTF16)) - return EC; - - // Convert path to the format that Windows is happy with. - if (PathUTF16.size() > 0 && - !is_separator(PathUTF16[Path.size() - 1]) && - PathUTF16[Path.size() - 1] != L':') { - PathUTF16.push_back(L'\\'); - PathUTF16.push_back(L'*'); - } else { - PathUTF16.push_back(L'*'); - } - - // Get the first directory entry. - WIN32_FIND_DATAW FirstFind; - ScopedFindHandle FindHandle(::FindFirstFileExW( - c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, - NULL, FIND_FIRST_EX_LARGE_FETCH)); - if (!FindHandle) - return mapWindowsError(::GetLastError()); - - size_t FilenameLen = ::wcslen(FirstFind.cFileName); - while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || - (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && - FirstFind.cFileName[1] == L'.')) - if (!::FindNextFileW(FindHandle, &FirstFind)) { - DWORD LastError = ::GetLastError(); - // Check for end. - if (LastError == ERROR_NO_MORE_FILES) - return detail::directory_iterator_destruct(IT); - return mapWindowsError(LastError); - } else - FilenameLen = ::wcslen(FirstFind.cFileName); - - // Construct the current directory entry. - SmallString<128> DirectoryEntryNameUTF8; - if (std::error_code EC = - UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), - DirectoryEntryNameUTF8)) - return EC; - - IT.IterationHandle = intptr_t(FindHandle.take()); - SmallString<128> DirectoryEntryPath(Path); - path::append(DirectoryEntryPath, DirectoryEntryNameUTF8); - IT.CurrentEntry = - directory_entry(DirectoryEntryPath, FollowSymlinks, - file_type_from_attrs(FirstFind.dwFileAttributes), - status_from_find_data(&FirstFind)); - - return std::error_code(); -} - -std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) { - if (IT.IterationHandle != 0) - // Closes the handle if it's valid. - ScopedFindHandle close(HANDLE(IT.IterationHandle)); - IT.IterationHandle = 0; - IT.CurrentEntry = directory_entry(); - return std::error_code(); -} - -std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) { - WIN32_FIND_DATAW FindData; - if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) { - DWORD LastError = ::GetLastError(); - // Check for end. - if (LastError == ERROR_NO_MORE_FILES) - return detail::directory_iterator_destruct(IT); - return mapWindowsError(LastError); - } - - size_t FilenameLen = ::wcslen(FindData.cFileName); - if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || - (FilenameLen == 2 && FindData.cFileName[0] == L'.' && - FindData.cFileName[1] == L'.')) - return directory_iterator_increment(IT); - - SmallString<128> DirectoryEntryPathUTF8; - if (std::error_code EC = - UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), - DirectoryEntryPathUTF8)) - return EC; - - IT.CurrentEntry.replace_filename( - Twine(DirectoryEntryPathUTF8), - file_type_from_attrs(FindData.dwFileAttributes), - status_from_find_data(&FindData)); - return std::error_code(); -} - -ErrorOr<basic_file_status> directory_entry::status() const { - return Status; -} - -static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD, - OpenFlags Flags) { - int CrtOpenFlags = 0; - if (Flags & OF_Append) - CrtOpenFlags |= _O_APPEND; - - if (Flags & OF_Text) - CrtOpenFlags |= _O_TEXT; - - ResultFD = -1; - if (!H) - return errorToErrorCode(H.takeError()); - - ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); - if (ResultFD == -1) { - ::CloseHandle(*H); - return mapWindowsError(ERROR_INVALID_HANDLE); - } - return std::error_code(); -} - -static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { - // This is a compatibility hack. Really we should respect the creation - // disposition, but a lot of old code relied on the implicit assumption that - // OF_Append implied it would open an existing file. Since the disposition is - // now explicit and defaults to CD_CreateAlways, this assumption would cause - // any usage of OF_Append to append to a new file, even if the file already - // existed. A better solution might have two new creation dispositions: - // CD_AppendAlways and CD_AppendNew. This would also address the problem of - // OF_Append being used on a read-only descriptor, which doesn't make sense. - if (Flags & OF_Append) - return OPEN_ALWAYS; - - switch (Disp) { - case CD_CreateAlways: - return CREATE_ALWAYS; - case CD_CreateNew: - return CREATE_NEW; - case CD_OpenAlways: - return OPEN_ALWAYS; - case CD_OpenExisting: - return OPEN_EXISTING; - } - llvm_unreachable("unreachable!"); -} - -static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { - DWORD Result = 0; - if (Access & FA_Read) - Result |= GENERIC_READ; - if (Access & FA_Write) - Result |= GENERIC_WRITE; - if (Flags & OF_Delete) - Result |= DELETE; - if (Flags & OF_UpdateAtime) - Result |= FILE_WRITE_ATTRIBUTES; - return Result; -} - -static std::error_code openNativeFileInternal(const Twine &Name, - file_t &ResultFile, DWORD Disp, - DWORD Access, DWORD Flags, - bool Inherit = false) { - SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; - - SECURITY_ATTRIBUTES SA; - SA.nLength = sizeof(SA); - SA.lpSecurityDescriptor = nullptr; - SA.bInheritHandle = Inherit; - - HANDLE H = - ::CreateFileW(PathUTF16.begin(), Access, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, - Disp, Flags, NULL); - if (H == INVALID_HANDLE_VALUE) { - DWORD LastError = ::GetLastError(); - std::error_code EC = mapWindowsError(LastError); - // Provide a better error message when trying to open directories. - // This only runs if we failed to open the file, so there is probably - // no performances issues. - if (LastError != ERROR_ACCESS_DENIED) - return EC; - if (is_directory(Name)) - return make_error_code(errc::is_a_directory); - return EC; - } - ResultFile = H; - return std::error_code(); -} - -Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp, - FileAccess Access, OpenFlags Flags, - unsigned Mode) { - // Verify that we don't have both "append" and "excl". - assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && - "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); - - DWORD NativeDisp = nativeDisposition(Disp, Flags); - DWORD NativeAccess = nativeAccess(Access, Flags); - - bool Inherit = false; - if (Flags & OF_ChildInherit) - Inherit = true; - - file_t Result; - std::error_code EC = openNativeFileInternal( - Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); - if (EC) - return errorCodeToError(EC); - - if (Flags & OF_UpdateAtime) { - FILETIME FileTime; - SYSTEMTIME SystemTime; - GetSystemTime(&SystemTime); - if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || - SetFileTime(Result, NULL, &FileTime, NULL) == 0) { - DWORD LastError = ::GetLastError(); - ::CloseHandle(Result); - return errorCodeToError(mapWindowsError(LastError)); - } - } - - if (Flags & OF_Delete) { - if ((EC = setDeleteDisposition(Result, true))) { - ::CloseHandle(Result); - return errorCodeToError(EC); - } - } - return Result; -} - -std::error_code openFile(const Twine &Name, int &ResultFD, - CreationDisposition Disp, FileAccess Access, - OpenFlags Flags, unsigned int Mode) { - Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags); - if (!Result) - return errorToErrorCode(Result.takeError()); - - return nativeFileToFd(*Result, ResultFD, Flags); -} - -static std::error_code directoryRealPath(const Twine &Name, - SmallVectorImpl<char> &RealPath) { - file_t File; - std::error_code EC = openNativeFileInternal( - Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); - if (EC) - return EC; - - EC = realPathFromHandle(File, RealPath); - ::CloseHandle(File); - return EC; -} - -std::error_code openFileForRead(const Twine &Name, int &ResultFD, - OpenFlags Flags, - SmallVectorImpl<char> *RealPath) { - Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath); - return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); -} - -Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, - SmallVectorImpl<char> *RealPath) { - Expected<file_t> Result = - openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); - - // Fetch the real name of the file, if the user asked - if (Result && RealPath) - realPathFromHandle(*Result, *RealPath); - - return Result; -} - -file_t convertFDToNativeFile(int FD) { - return reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); -} - -file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } -file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } -file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } - -std::error_code readNativeFileImpl(file_t FileHandle, char *BufPtr, size_t BytesToRead, - size_t *BytesRead, OVERLAPPED *Overlap) { - // ReadFile can only read 2GB at a time. The caller should check the number of - // bytes and read in a loop until termination. - DWORD BytesToRead32 = - std::min(size_t(std::numeric_limits<DWORD>::max()), BytesToRead); - DWORD BytesRead32 = 0; - bool Success = - ::ReadFile(FileHandle, BufPtr, BytesToRead32, &BytesRead32, Overlap); - *BytesRead = BytesRead32; - if (!Success) { - DWORD Err = ::GetLastError(); - // Pipe EOF is not an error. - if (Err == ERROR_BROKEN_PIPE) - return std::error_code(); - return mapWindowsError(Err); - } - return std::error_code(); -} - -std::error_code readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf, - size_t *BytesRead) { - return readNativeFileImpl(FileHandle, Buf.data(), Buf.size(), BytesRead, - /*Overlap=*/nullptr); -} - -std::error_code readNativeFileSlice(file_t FileHandle, - MutableArrayRef<char> Buf, size_t Offset) { - char *BufPtr = Buf.data(); - size_t BytesLeft = Buf.size(); - - while (BytesLeft) { - uint64_t CurOff = Buf.size() - BytesLeft + Offset; - OVERLAPPED Overlapped = {}; - Overlapped.Offset = uint32_t(CurOff); - Overlapped.OffsetHigh = uint32_t(uint64_t(CurOff) >> 32); - - size_t BytesRead = 0; - if (auto EC = readNativeFileImpl(FileHandle, BufPtr, BytesLeft, &BytesRead, - &Overlapped)) - return EC; - - // Once we reach EOF, zero the remaining bytes in the buffer. - if (BytesRead == 0) { - memset(BufPtr, 0, BytesLeft); - break; - } - BytesLeft -= BytesRead; - BufPtr += BytesRead; - } - return std::error_code(); -} - -std::error_code closeFile(file_t &F) { - file_t TmpF = F; - F = kInvalidFile; - if (!::CloseHandle(TmpF)) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { - // Convert to utf-16. - SmallVector<wchar_t, 128> Path16; - std::error_code EC = widenPath(path, Path16); - if (EC && !IgnoreErrors) - return EC; - - // SHFileOperation() accepts a list of paths, and so must be double null- - // terminated to indicate the end of the list. The buffer is already null - // terminated, but since that null character is not considered part of the - // vector's size, pushing another one will just consume that byte. So we - // need to push 2 null terminators. - Path16.push_back(0); - Path16.push_back(0); - - SHFILEOPSTRUCTW shfos = {}; - shfos.wFunc = FO_DELETE; - shfos.pFrom = Path16.data(); - shfos.fFlags = FOF_NO_UI; - - int result = ::SHFileOperationW(&shfos); - if (result != 0 && !IgnoreErrors) - return mapWindowsError(result); - return std::error_code(); -} - -static void expandTildeExpr(SmallVectorImpl<char> &Path) { - // Path does not begin with a tilde expression. - if (Path.empty() || Path[0] != '~') - return; - - StringRef PathStr(Path.begin(), Path.size()); - PathStr = PathStr.drop_front(); - StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); - - if (!Expr.empty()) { - // This is probably a ~username/ expression. Don't support this on Windows. - return; - } - - SmallString<128> HomeDir; - if (!path::home_directory(HomeDir)) { - // For some reason we couldn't get the home directory. Just exit. - return; - } - - // Overwrite the first character and insert the rest. - Path[0] = HomeDir[0]; - Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); -} - -void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { - dest.clear(); - if (path.isTriviallyEmpty()) - return; - - path.toVector(dest); - expandTildeExpr(dest); - - return; -} - -std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, - bool expand_tilde) { - dest.clear(); - if (path.isTriviallyEmpty()) - return std::error_code(); - - if (expand_tilde) { - SmallString<128> Storage; - path.toVector(Storage); - expandTildeExpr(Storage); - return real_path(Storage, dest, false); - } - - if (is_directory(path)) - return directoryRealPath(path, dest); - - int fd; - if (std::error_code EC = - llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) - return EC; - ::close(fd); - return std::error_code(); -} - -} // end namespace fs - -namespace path { -static bool getKnownFolderPath(KNOWNFOLDERID folderId, - SmallVectorImpl<char> &result) { - wchar_t *path = nullptr; - if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) - return false; - - bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); - ::CoTaskMemFree(path); - return ok; -} - -bool home_directory(SmallVectorImpl<char> &result) { - return getKnownFolderPath(FOLDERID_Profile, result); -} - -static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) { - SmallVector<wchar_t, 1024> Buf; - size_t Size = 1024; - do { - Buf.reserve(Size); - Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); - if (Size == 0) - return false; - - // Try again with larger buffer. - } while (Size > Buf.capacity()); - Buf.set_size(Size); - - return !windows::UTF16ToUTF8(Buf.data(), Size, Res); -} - -static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { - const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; - for (auto *Env : EnvironmentVariables) { - if (getTempDirEnvVar(Env, Res)) - return true; - } - return false; -} - -void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { - (void)ErasedOnReboot; - Result.clear(); - - // Check whether the temporary directory is specified by an environment var. - // This matches GetTempPath logic to some degree. GetTempPath is not used - // directly as it cannot handle evn var longer than 130 chars on Windows 7 - // (fixed on Windows 8). - if (getTempDirEnvVar(Result)) { - assert(!Result.empty() && "Unexpected empty path"); - native(Result); // Some Unix-like shells use Unix path separator in $TMP. - fs::make_absolute(Result); // Make it absolute if not already. - return; - } - - // Fall back to a system default. - const char *DefaultResult = "C:\\Temp"; - Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); -} -} // end namespace path - -namespace windows { -std::error_code CodePageToUTF16(unsigned codepage, - llvm::StringRef original, - llvm::SmallVectorImpl<wchar_t> &utf16) { - if (!original.empty()) { - int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), - original.size(), utf16.begin(), 0); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - - utf16.reserve(len + 1); - utf16.set_size(len); - - len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), - original.size(), utf16.begin(), utf16.size()); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - } - - // Make utf16 null terminated. - utf16.push_back(0); - utf16.pop_back(); - - return std::error_code(); -} - -std::error_code UTF8ToUTF16(llvm::StringRef utf8, - llvm::SmallVectorImpl<wchar_t> &utf16) { - return CodePageToUTF16(CP_UTF8, utf8, utf16); -} - -std::error_code CurCPToUTF16(llvm::StringRef curcp, - llvm::SmallVectorImpl<wchar_t> &utf16) { - return CodePageToUTF16(CP_ACP, curcp, utf16); -} - -static -std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, - size_t utf16_len, - llvm::SmallVectorImpl<char> &converted) { - if (utf16_len) { - // Get length. - int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), - 0, NULL, NULL); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - - converted.reserve(len); - converted.set_size(len); - - // Now do the actual conversion. - len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), - converted.size(), NULL, NULL); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - } - - // Make the new string null terminated. - converted.push_back(0); - converted.pop_back(); - - return std::error_code(); -} - -std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &utf8) { - return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); -} - -std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &curcp) { - return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); -} - -} // end namespace windows -} // end namespace sys -} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc deleted file mode 100644 index 4b91f9f7fc66..000000000000 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ /dev/null @@ -1,485 +0,0 @@ -//===- Win32/Process.cpp - Win32 Process 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 the Process class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Allocator.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/WindowsError.h" -#include <malloc.h> - -// The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" - -#include <direct.h> -#include <io.h> -#include <psapi.h> -#include <shellapi.h> - -#if !defined(__MINGW32__) - #pragma comment(lib, "psapi.lib") - #pragma comment(lib, "shell32.lib") -#endif - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef __MINGW32__ -// This ban should be lifted when MinGW 1.0+ has defined this value. -# define _HEAPOK (-2) -#endif - -using namespace llvm; - -// This function retrieves the page size using GetNativeSystemInfo() and is -// present solely so it can be called once to initialize the self_process member -// below. -static unsigned computePageSize() { - // GetNativeSystemInfo() provides the physical page size which may differ - // from GetSystemInfo() in 32-bit applications running under WOW64. - SYSTEM_INFO info; - GetNativeSystemInfo(&info); - // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, - // but dwAllocationGranularity. - return static_cast<unsigned>(info.dwPageSize); -} - -Expected<unsigned> Process::getPageSize() { - static unsigned Ret = computePageSize(); - return Ret; -} - -size_t -Process::GetMallocUsage() -{ - _HEAPINFO hinfo; - hinfo._pentry = NULL; - - size_t size = 0; - - while (_heapwalk(&hinfo) == _HEAPOK) - size += hinfo._size; - - return size; -} - -void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, - std::chrono::nanoseconds &sys_time) { - elapsed = std::chrono::system_clock::now();; - - FILETIME ProcCreate, ProcExit, KernelTime, UserTime; - if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, - &UserTime) == 0) - return; - - user_time = toDuration(UserTime); - sys_time = toDuration(KernelTime); -} - -// Some LLVM programs such as bugpoint produce core files as a normal part of -// their operation. To prevent the disk from filling up, this configuration -// item does what's necessary to prevent their generation. -void Process::PreventCoreFiles() { - // Windows does have the concept of core files, called minidumps. However, - // disabling minidumps for a particular application extends past the lifetime - // of that application, which is the incorrect behavior for this API. - // Additionally, the APIs require elevated privileges to disable and re- - // enable minidumps, which makes this untenable. For more information, see - // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and - // later). - // - // Windows also has modal pop-up message boxes. As this method is used by - // bugpoint, preventing these pop-ups is additionally important. - SetErrorMode(SEM_FAILCRITICALERRORS | - SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - - coreFilesPrevented = true; -} - -/// Returns the environment variable \arg Name's value as a string encoded in -/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. -Optional<std::string> Process::GetEnv(StringRef Name) { - // Convert the argument to UTF-16 to pass it to _wgetenv(). - SmallVector<wchar_t, 128> NameUTF16; - if (windows::UTF8ToUTF16(Name, NameUTF16)) - return None; - - // Environment variable can be encoded in non-UTF8 encoding, and there's no - // way to know what the encoding is. The only reliable way to look up - // multibyte environment variable is to use GetEnvironmentVariableW(). - SmallVector<wchar_t, MAX_PATH> Buf; - size_t Size = MAX_PATH; - do { - Buf.reserve(Size); - SetLastError(NO_ERROR); - Size = - GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); - if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) - return None; - - // Try again with larger buffer. - } while (Size > Buf.capacity()); - Buf.set_size(Size); - - // Convert the result from UTF-16 to UTF-8. - SmallVector<char, MAX_PATH> Res; - if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) - return None; - return std::string(Res.data()); -} - -/// Perform wildcard expansion of Arg, or just push it into Args if it doesn't -/// have wildcards or doesn't match any files. -static std::error_code WildcardExpand(StringRef Arg, - SmallVectorImpl<const char *> &Args, - StringSaver &Saver) { - std::error_code EC; - - // Don't expand Arg if it does not contain any wildcard characters. This is - // the common case. Also don't wildcard expand /?. Always treat it as an - // option. - if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" || - Arg == "-?") { - Args.push_back(Arg.data()); - return EC; - } - - // Convert back to UTF-16 so we can call FindFirstFileW. - SmallVector<wchar_t, MAX_PATH> ArgW; - EC = windows::UTF8ToUTF16(Arg, ArgW); - if (EC) - return EC; - - // Search for matching files. - // FIXME: This assumes the wildcard is only in the file name and not in the - // directory portion of the file path. For example, it doesn't handle - // "*\foo.c" nor "s?c\bar.cpp". - WIN32_FIND_DATAW FileData; - HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData); - if (FindHandle == INVALID_HANDLE_VALUE) { - Args.push_back(Arg.data()); - return EC; - } - - // Extract any directory part of the argument. - SmallString<MAX_PATH> Dir = Arg; - sys::path::remove_filename(Dir); - const int DirSize = Dir.size(); - - do { - SmallString<MAX_PATH> FileName; - EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), - FileName); - if (EC) - break; - - // Append FileName to Dir, and remove it afterwards. - llvm::sys::path::append(Dir, FileName); - Args.push_back(Saver.save(StringRef(Dir)).data()); - Dir.resize(DirSize); - } while (FindNextFileW(FindHandle, &FileData)); - - FindClose(FindHandle); - return EC; -} - -static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { - // The first argument may contain just the name of the executable (e.g., - // "clang") rather than the full path, so swap it with the full path. - wchar_t ModuleName[MAX_PATH]; - size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); - if (Length == 0 || Length == MAX_PATH) { - return mapWindowsError(GetLastError()); - } - - // If the first argument is a shortened (8.3) name (which is possible even - // if we got the module name), the driver will have trouble distinguishing it - // (e.g., clang.exe v. clang++.exe), so expand it now. - Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); - if (Length == 0) - return mapWindowsError(GetLastError()); - if (Length > MAX_PATH) { - // We're not going to try to deal with paths longer than MAX_PATH, so we'll - // treat this as an error. GetLastError() returns ERROR_SUCCESS, which - // isn't useful, so we'll hardcode an appropriate error value. - return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); - } - - std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); - if (EC) - return EC; - - StringRef Base = sys::path::filename(Filename.data()); - Filename.assign(Base.begin(), Base.end()); - return std::error_code(); -} - -std::error_code -windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args, - BumpPtrAllocator &Alloc) { - const wchar_t *CmdW = GetCommandLineW(); - assert(CmdW); - std::error_code EC; - SmallString<MAX_PATH> Cmd; - EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd); - if (EC) - return EC; - - SmallVector<const char *, 20> TmpArgs; - StringSaver Saver(Alloc); - cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false); - - for (const char *Arg : TmpArgs) { - EC = WildcardExpand(Arg, Args, Saver); - if (EC) - return EC; - } - - SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0])); - SmallVector<char, MAX_PATH> Filename; - sys::path::remove_filename(Arg0); - EC = GetExecutableName(Filename); - if (EC) - return EC; - sys::path::append(Arg0, Filename); - Args[0] = Saver.save(Arg0).data(); - return std::error_code(); -} - -std::error_code Process::FixupStandardFileDescriptors() { - return std::error_code(); -} - -std::error_code Process::SafelyCloseFileDescriptor(int FD) { - if (::close(FD) < 0) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -bool Process::StandardInIsUserInput() { - return FileDescriptorIsDisplayed(0); -} - -bool Process::StandardOutIsDisplayed() { - return FileDescriptorIsDisplayed(1); -} - -bool Process::StandardErrIsDisplayed() { - return FileDescriptorIsDisplayed(2); -} - -bool Process::FileDescriptorIsDisplayed(int fd) { - DWORD Mode; // Unused - return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); -} - -unsigned Process::StandardOutColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -unsigned Process::StandardErrColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -// The terminal always has colors. -bool Process::FileDescriptorHasColors(int fd) { - return FileDescriptorIsDisplayed(fd); -} - -bool Process::StandardOutHasColors() { - return FileDescriptorHasColors(1); -} - -bool Process::StandardErrHasColors() { - return FileDescriptorHasColors(2); -} - -static bool UseANSI = false; -void Process::UseANSIEscapeCodes(bool enable) { -#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) - if (enable) { - HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD Mode; - GetConsoleMode(Console, &Mode); - Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(Console, Mode); - } -#endif - UseANSI = enable; -} - -namespace { -class DefaultColors -{ - private: - WORD defaultColor; - public: - DefaultColors() - :defaultColor(GetCurrentColor()) {} - static unsigned GetCurrentColor() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - return csbi.wAttributes; - return 0; - } - WORD operator()() const { return defaultColor; } -}; - -DefaultColors defaultColors; - -WORD fg_color(WORD color) { - return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | - FOREGROUND_INTENSITY | FOREGROUND_RED); -} - -WORD bg_color(WORD color) { - return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | - BACKGROUND_INTENSITY | BACKGROUND_RED); -} -} - -bool Process::ColorNeedsFlush() { - return !UseANSI; -} - -const char *Process::OutputBold(bool bg) { - if (UseANSI) return "\033[1m"; - - WORD colors = DefaultColors::GetCurrentColor(); - if (bg) - colors |= BACKGROUND_INTENSITY; - else - colors |= FOREGROUND_INTENSITY; - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -const char *Process::OutputColor(char code, bool bold, bool bg) { - if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; - - WORD current = DefaultColors::GetCurrentColor(); - WORD colors; - if (bg) { - colors = ((code&1) ? BACKGROUND_RED : 0) | - ((code&2) ? BACKGROUND_GREEN : 0 ) | - ((code&4) ? BACKGROUND_BLUE : 0); - if (bold) - colors |= BACKGROUND_INTENSITY; - colors |= fg_color(current); - } else { - colors = ((code&1) ? FOREGROUND_RED : 0) | - ((code&2) ? FOREGROUND_GREEN : 0 ) | - ((code&4) ? FOREGROUND_BLUE : 0); - if (bold) - colors |= FOREGROUND_INTENSITY; - colors |= bg_color(current); - } - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); - return info.wAttributes; -} - -const char *Process::OutputReverse() { - if (UseANSI) return "\033[7m"; - - const WORD attributes - = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); - - const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | - FOREGROUND_RED | FOREGROUND_INTENSITY; - const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | - BACKGROUND_RED | BACKGROUND_INTENSITY; - const WORD color_mask = foreground_mask | background_mask; - - WORD new_attributes = - ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | - ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | - ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | - ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | - ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | - ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | - ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | - ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | - 0; - new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); - - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); - return 0; -} - -const char *Process::ResetColor() { - if (UseANSI) return "\033[0m"; - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); - return 0; -} - -// Include GetLastError() in a fatal error message. -static void ReportLastErrorFatal(const char *Msg) { - std::string ErrMsg; - MakeErrMsg(&ErrMsg, Msg); - report_fatal_error(ErrMsg); -} - -unsigned Process::GetRandomNumber() { - HCRYPTPROV HCPC; - if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - ReportLastErrorFatal("Could not acquire a cryptographic context"); - - ScopedCryptContext CryptoProvider(HCPC); - unsigned Ret; - if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), - reinterpret_cast<BYTE *>(&Ret))) - ReportLastErrorFatal("Could not generate a random number"); - return Ret; -} - -typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) - -llvm::VersionTuple llvm::GetWindowsOSVersion() { - HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); - if (getVer) { - RTL_OSVERSIONINFOEXW info{}; - info.dwOSVersionInfoSize = sizeof(info); - if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) { - return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0, - info.dwBuildNumber); - } - } - } - return llvm::VersionTuple(0, 0, 0, 0); -} - -bool llvm::RunningWindows8OrGreater() { - // Windows 8 is version 6.2, service pack 0. - return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0); -} diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc deleted file mode 100644 index 0f54e59ee55b..000000000000 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ /dev/null @@ -1,523 +0,0 @@ -//===- Win32/Program.cpp - Win32 Program 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 the Program class. -// -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/WindowsError.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdio> -#include <fcntl.h> -#include <io.h> -#include <malloc.h> -#include <numeric> - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -namespace llvm { - -ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {} - -ErrorOr<std::string> sys::findProgramByName(StringRef Name, - ArrayRef<StringRef> Paths) { - assert(!Name.empty() && "Must have a name!"); - - if (Name.find_first_of("/\\") != StringRef::npos) - return std::string(Name); - - const wchar_t *Path = nullptr; - std::wstring PathStorage; - if (!Paths.empty()) { - PathStorage.reserve(Paths.size() * MAX_PATH); - for (unsigned i = 0; i < Paths.size(); ++i) { - if (i) - PathStorage.push_back(L';'); - StringRef P = Paths[i]; - SmallVector<wchar_t, MAX_PATH> TmpPath; - if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath)) - return EC; - PathStorage.append(TmpPath.begin(), TmpPath.end()); - } - Path = PathStorage.c_str(); - } - - SmallVector<wchar_t, MAX_PATH> U16Name; - if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name)) - return EC; - - SmallVector<StringRef, 12> PathExts; - PathExts.push_back(""); - PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%. - if (const char *PathExtEnv = std::getenv("PATHEXT")) - SplitString(PathExtEnv, PathExts, ";"); - - SmallVector<wchar_t, MAX_PATH> U16Result; - DWORD Len = MAX_PATH; - for (StringRef Ext : PathExts) { - SmallVector<wchar_t, MAX_PATH> U16Ext; - if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext)) - return EC; - - do { - U16Result.reserve(Len); - // Lets attach the extension manually. That is needed for files - // with a point in name like aaa.bbb. SearchPathW will not add extension - // from its argument to such files because it thinks they already had one. - SmallVector<wchar_t, MAX_PATH> U16NameExt; - if (std::error_code EC = - windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt)) - return EC; - - Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr, - U16Result.capacity(), U16Result.data(), nullptr); - } while (Len > U16Result.capacity()); - - if (Len != 0) - break; // Found it. - } - - if (Len == 0) - return mapWindowsError(::GetLastError()); - - U16Result.set_size(Len); - - SmallVector<char, MAX_PATH> U8Result; - if (std::error_code EC = - windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result)) - return EC; - - return std::string(U8Result.begin(), U8Result.end()); -} - -bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { - if (!ErrMsg) - return true; - char *buffer = NULL; - DWORD LastError = GetLastError(); - DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); - if (R) - *ErrMsg = prefix + ": " + buffer; - else - *ErrMsg = prefix + ": Unknown error"; - *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")"; - - LocalFree(buffer); - return R != 0; -} - -static HANDLE RedirectIO(Optional<StringRef> Path, int fd, - std::string *ErrMsg) { - HANDLE h; - if (!Path) { - if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - return INVALID_HANDLE_VALUE; - return h; - } - - std::string fname; - if (Path->empty()) - fname = "NUL"; - else - fname = *Path; - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - SmallVector<wchar_t, 128> fnameUnicode; - if (Path->empty()) { - // Don't play long-path tricks on "NUL". - if (windows::UTF8ToUTF16(fname, fnameUnicode)) - return INVALID_HANDLE_VALUE; - } else { - if (path::widenPath(fname, fnameUnicode)) - return INVALID_HANDLE_VALUE; - } - h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, fname + ": Can't open file for " + - (fd ? "input" : "output")); - } - - return h; -} - -} - -static bool Execute(ProcessInfo &PI, StringRef Program, - ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, - ArrayRef<Optional<StringRef>> Redirects, - unsigned MemoryLimit, std::string *ErrMsg) { - if (!sys::fs::can_execute(Program)) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // can_execute may succeed by looking at Program + ".exe". CreateProcessW - // will implicitly add the .exe if we provide a command line without an - // executable path, but since we use an explicit executable, we have to add - // ".exe" ourselves. - SmallString<64> ProgramStorage; - if (!sys::fs::exists(Program)) - Program = Twine(Program + ".exe").toStringRef(ProgramStorage); - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces (or are empty). - std::string Command = flattenWindowsCommandLine(Args); - - // The pointer to the environment block for the new process. - std::vector<wchar_t> EnvBlock; - - if (Env) { - // An environment block consists of a null-terminated block of - // null-terminated strings. Convert the array of environment variables to - // an environment block by concatenating them. - for (const auto E : *Env) { - SmallVector<wchar_t, MAX_PATH> EnvString; - if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); - return false; - } - - EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); - EnvBlock.push_back(0); - } - EnvBlock.push_back(0); - } - - // Create a child process. - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - if (!Redirects.empty()) { - si.dwFlags = STARTF_USESTDHANDLES; - - si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg); - if (si.hStdInput == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, "can't redirect stdin"); - return false; - } - si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg); - if (si.hStdOutput == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - MakeErrMsg(ErrMsg, "can't redirect stdout"); - return false; - } - if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { - // If stdout and stderr should go to the same place, redirect stderr - // to the handle already open for stdout. - if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); - return false; - } - } else { - // Just redirect stderr - si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg); - if (si.hStdError == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't redirect stderr"); - return false; - } - } - } - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - - fflush(stdout); - fflush(stderr); - - SmallVector<wchar_t, MAX_PATH> ProgramUtf16; - if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, - std::string("Unable to convert application name to UTF-16")); - return false; - } - - SmallVector<wchar_t, MAX_PATH> CommandUtf16; - if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, - std::string("Unable to convert command-line to UTF-16")); - return false; - } - - BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, - TRUE, CREATE_UNICODE_ENVIRONMENT, - EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, - &pi); - DWORD err = GetLastError(); - - // Regardless of whether the process got created or not, we are done with - // the handles we created for it to inherit. - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - // Now return an error if the process didn't get created. - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - Program.str() + "'"); - return false; - } - - PI.Pid = pi.dwProcessId; - PI.Process = pi.hProcess; - - // Make sure these get closed no matter what. - ScopedCommonHandle hThread(pi.hThread); - - // Assign the process to a job if a memory limit is defined. - ScopedJobHandle hJob; - if (MemoryLimit != 0) { - hJob = CreateJobObjectW(0, 0); - bool success = false; - if (hJob) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576; - if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, - &jeli, sizeof(jeli))) { - if (AssignProcessToJobObject(hJob, pi.hProcess)) - success = true; - } - } - if (!success) { - SetLastError(GetLastError()); - MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); - TerminateProcess(pi.hProcess, 1); - WaitForSingleObject(pi.hProcess, INFINITE); - return false; - } - } - - return true; -} - -static bool argNeedsQuotes(StringRef Arg) { - if (Arg.empty()) - return true; - return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|\n"); -} - -static std::string quoteSingleArg(StringRef Arg) { - std::string Result; - Result.push_back('"'); - - while (!Arg.empty()) { - size_t FirstNonBackslash = Arg.find_first_not_of('\\'); - size_t BackslashCount = FirstNonBackslash; - if (FirstNonBackslash == StringRef::npos) { - // The entire remainder of the argument is backslashes. Escape all of - // them and just early out. - BackslashCount = Arg.size(); - Result.append(BackslashCount * 2, '\\'); - break; - } - - if (Arg[FirstNonBackslash] == '\"') { - // This is an embedded quote. Escape all preceding backslashes, then - // add one additional backslash to escape the quote. - Result.append(BackslashCount * 2 + 1, '\\'); - Result.push_back('\"'); - } else { - // This is just a normal character. Don't escape any of the preceding - // backslashes, just append them as they are and then append the - // character. - Result.append(BackslashCount, '\\'); - Result.push_back(Arg[FirstNonBackslash]); - } - - // Drop all the backslashes, plus the following character. - Arg = Arg.drop_front(FirstNonBackslash + 1); - } - - Result.push_back('"'); - return Result; -} - -namespace llvm { -std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { - std::string Command; - for (StringRef Arg : Args) { - if (argNeedsQuotes(Arg)) - Command += quoteSingleArg(Arg); - else - Command += Arg; - - Command.push_back(' '); - } - - return Command; -} - -ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, - bool WaitUntilChildTerminates, std::string *ErrMsg) { - assert(PI.Pid && "invalid pid to wait on, process not started?"); - assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && - "invalid process handle to wait on, process not started?"); - DWORD milliSecondsToWait = 0; - if (WaitUntilChildTerminates) - milliSecondsToWait = INFINITE; - else if (SecondsToWait > 0) - milliSecondsToWait = SecondsToWait * 1000; - - ProcessInfo WaitResult = PI; - DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); - if (WaitStatus == WAIT_TIMEOUT) { - if (SecondsToWait) { - if (!TerminateProcess(PI.Process, 1)) { - if (ErrMsg) - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program"); - - // -2 indicates a crash or timeout as opposed to failure to execute. - WaitResult.ReturnCode = -2; - CloseHandle(PI.Process); - return WaitResult; - } - WaitForSingleObject(PI.Process, INFINITE); - CloseHandle(PI.Process); - } else { - // Non-blocking wait. - return ProcessInfo(); - } - } - - // Get its exit status. - DWORD status; - BOOL rc = GetExitCodeProcess(PI.Process, &status); - DWORD err = GetLastError(); - if (err != ERROR_INVALID_HANDLE) - CloseHandle(PI.Process); - - if (!rc) { - SetLastError(err); - if (ErrMsg) - MakeErrMsg(ErrMsg, "Failed getting status for program"); - - // -2 indicates a crash or timeout as opposed to failure to execute. - WaitResult.ReturnCode = -2; - return WaitResult; - } - - if (!status) - return WaitResult; - - // Pass 10(Warning) and 11(Error) to the callee as negative value. - if ((status & 0xBFFF0000U) == 0x80000000U) - WaitResult.ReturnCode = static_cast<int>(status); - else if (status & 0xFF) - WaitResult.ReturnCode = status & 0x7FFFFFFF; - else - WaitResult.ReturnCode = 1; - - return WaitResult; -} - -std::error_code sys::ChangeStdinToBinary() { - int result = _setmode(_fileno(stdin), _O_BINARY); - if (result == -1) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -std::error_code sys::ChangeStdoutToBinary() { - int result = _setmode(_fileno(stdout), _O_BINARY); - if (result == -1) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -std::error_code -llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, - WindowsEncodingMethod Encoding) { - std::error_code EC; - llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::F_Text); - if (EC) - return EC; - - if (Encoding == WEM_UTF8) { - OS << Contents; - } else if (Encoding == WEM_CurrentCodePage) { - SmallVector<wchar_t, 1> ArgsUTF16; - SmallVector<char, 1> ArgsCurCP; - - if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) - return EC; - - if ((EC = windows::UTF16ToCurCP( - ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP))) - return EC; - - OS.write(ArgsCurCP.data(), ArgsCurCP.size()); - } else if (Encoding == WEM_UTF16) { - SmallVector<wchar_t, 1> ArgsUTF16; - - if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) - return EC; - - // Endianness guessing - char BOM[2]; - uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE; - memcpy(BOM, &src, 2); - OS.write(BOM, 2); - OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1); - } else { - llvm_unreachable("Unknown encoding"); - } - - if (OS.has_error()) - return make_error_code(errc::io_error); - - return EC; -} - -bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, - ArrayRef<StringRef> Args) { - // The documented max length of the command line passed to CreateProcess. - static const size_t MaxCommandStringLength = 32768; - SmallVector<StringRef, 8> FullArgs; - FullArgs.push_back(Program); - FullArgs.append(Args.begin(), Args.end()); - std::string Result = flattenWindowsCommandLine(FullArgs); - return (Result.size() + 1) <= MaxCommandStringLength; -} -} diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc deleted file mode 100644 index 8df9bc394160..000000000000 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ /dev/null @@ -1,128 +0,0 @@ -//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// -// -// 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 implements the Win32 specific (non-pthread) RWMutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" - -namespace llvm { - -// Windows has slim read-writer lock support on Vista and higher, so we -// will attempt to load the APIs. If they exist, we will use them, and -// if not, we will fall back on critical sections. When we drop support -// for XP, we can stop lazy-loading these APIs and just use them directly. -#if defined(__MINGW32__) - // Taken from WinNT.h - typedef struct _RTL_SRWLOCK { - PVOID Ptr; - } RTL_SRWLOCK, *PRTL_SRWLOCK; - - // Taken from WinBase.h - typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; -#endif - -static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL; - -static bool sHasSRW = false; - -static bool loadSRW() { - static bool sChecked = false; - if (!sChecked) { - sChecked = true; - - if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) { - fpInitializeSRWLock = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "InitializeSRWLock"); - fpAcquireSRWLockExclusive = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "AcquireSRWLockExclusive"); - fpAcquireSRWLockShared = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "AcquireSRWLockShared"); - fpReleaseSRWLockExclusive = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "ReleaseSRWLockExclusive"); - fpReleaseSRWLockShared = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "ReleaseSRWLockShared"); - - if (fpInitializeSRWLock != NULL) { - sHasSRW = true; - } - } - } - return sHasSRW; -} - -sys::RWMutexImpl::RWMutexImpl() { - if (loadSRW()) { - data_ = safe_calloc(1, sizeof(SRWLOCK)); - fpInitializeSRWLock(static_cast<PSRWLOCK>(data_)); - } else { - data_ = safe_calloc(1, sizeof(CRITICAL_SECTION)); - InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - } -} - -sys::RWMutexImpl::~RWMutexImpl() { - if (!sHasSRW) - DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - // Nothing to do in the case of slim reader/writers except free the memory. - free(data_); -} - -bool sys::RWMutexImpl::reader_acquire() { - if (sHasSRW) { - fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_)); - } else { - EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - } - return true; -} - -bool sys::RWMutexImpl::reader_release() { - if (sHasSRW) { - fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_)); - } else { - LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - } - return true; -} - -bool sys::RWMutexImpl::writer_acquire() { - if (sHasSRW) { - fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_)); - } else { - EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - } - return true; -} - -bool sys::RWMutexImpl::writer_release() { - if (sHasSRW) { - fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_)); - } else { - LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - } - return true; -} - - -} diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc deleted file mode 100644 index 6a820ef22b1e..000000000000 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ /dev/null @@ -1,874 +0,0 @@ -//===- Win32/Signals.cpp - Win32 Signals 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 the Signals class. -// -//===----------------------------------------------------------------------===// -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/WindowsError.h" -#include <algorithm> -#include <io.h> -#include <signal.h> -#include <stdio.h> - -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -// The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" - -#ifdef __MINGW32__ - #include <imagehlp.h> -#else - #include <crtdbg.h> - #include <dbghelp.h> -#endif -#include <psapi.h> - -#ifdef _MSC_VER - #pragma comment(lib, "psapi.lib") -#elif __MINGW32__ - // The version of g++ that comes with MinGW does *not* properly understand - // the ll format specifier for printf. However, MinGW passes the format - // specifiers on to the MSVCRT entirely, and the CRT understands the ll - // specifier. So these warnings are spurious in this case. Since we compile - // with -Wall, this will generate these warnings which should be ignored. So - // we will turn off the warnings for this just file. However, MinGW also does - // not support push and pop for diagnostics, so we have to manually turn it - // back on at the end of the file. - #pragma GCC diagnostic ignored "-Wformat" - #pragma GCC diagnostic ignored "-Wformat-extra-args" - - #if !defined(__MINGW64_VERSION_MAJOR) - // MinGW.org does not have updated support for the 64-bit versions of the - // DebugHlp APIs. So we will have to load them manually. The structures and - // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, - // and adjusted for brevity. - typedef struct _IMAGEHLP_LINE64 { - DWORD SizeOfStruct; - PVOID Key; - DWORD LineNumber; - PCHAR FileName; - DWORD64 Address; - } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; - - typedef struct _IMAGEHLP_SYMBOL64 { - DWORD SizeOfStruct; - DWORD64 Address; - DWORD Size; - DWORD Flags; - DWORD MaxNameLength; - CHAR Name[1]; - } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD64 Reserved[5]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; - ADDRESS64 AddrReturn; - ADDRESS64 AddrFrame; - ADDRESS64 AddrStack; - ADDRESS64 AddrBStore; - PVOID FuncTableEntry; - DWORD64 Params[4]; - BOOL Far; - BOOL Virtual; - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64, *LPSTACKFRAME64; - #endif // !defined(__MINGW64_VERSION_MAJOR) -#endif // __MINGW32__ - -typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, - DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, - LPDWORD lpNumberOfBytesRead); - -typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, - DWORD64 AddrBase); - -typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, - DWORD64 Address); - -typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, - HANDLE hThread, LPADDRESS64 lpaddr); - -typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, - PMINIDUMP_EXCEPTION_INFORMATION, - PMINIDUMP_USER_STREAM_INFORMATION, - PMINIDUMP_CALLBACK_INFORMATION); -static fpMiniDumpWriteDump fMiniDumpWriteDump; - -typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, - PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, - PFUNCTION_TABLE_ACCESS_ROUTINE64, - PGET_MODULE_BASE_ROUTINE64, - PTRANSLATE_ADDRESS_ROUTINE64); -static fpStackWalk64 fStackWalk64; - -typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); -static fpSymGetModuleBase64 fSymGetModuleBase64; - -typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, - PDWORD64, PIMAGEHLP_SYMBOL64); -static fpSymGetSymFromAddr64 fSymGetSymFromAddr64; - -typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, - PDWORD, PIMAGEHLP_LINE64); -static fpSymGetLineFromAddr64 fSymGetLineFromAddr64; - -typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, - PIMAGEHLP_MODULE64 ModuleInfo); -static fpSymGetModuleInfo64 fSymGetModuleInfo64; - -typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); -static fpSymFunctionTableAccess64 fSymFunctionTableAccess64; - -typedef DWORD (WINAPI *fpSymSetOptions)(DWORD); -static fpSymSetOptions fSymSetOptions; - -typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); -static fpSymInitialize fSymInitialize; - -typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); -static fpEnumerateLoadedModules fEnumerateLoadedModules; - -static bool load64BitDebugHelp(void) { - HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); - if (hLib) { - fMiniDumpWriteDump = (fpMiniDumpWriteDump) - ::GetProcAddress(hLib, "MiniDumpWriteDump"); - fStackWalk64 = (fpStackWalk64) - ::GetProcAddress(hLib, "StackWalk64"); - fSymGetModuleBase64 = (fpSymGetModuleBase64) - ::GetProcAddress(hLib, "SymGetModuleBase64"); - fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) - ::GetProcAddress(hLib, "SymGetSymFromAddr64"); - fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) - ::GetProcAddress(hLib, "SymGetLineFromAddr64"); - fSymGetModuleInfo64 = (fpSymGetModuleInfo64) - ::GetProcAddress(hLib, "SymGetModuleInfo64"); - fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) - ::GetProcAddress(hLib, "SymFunctionTableAccess64"); - fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); - fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); - fEnumerateLoadedModules = (fpEnumerateLoadedModules) - ::GetProcAddress(hLib, "EnumerateLoadedModules64"); - } - return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; -} - -using namespace llvm; - -// Forward declare. -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); - -// The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = 0; - -static std::vector<std::string> *FilesToRemove = NULL; -static bool RegisteredUnhandledExceptionFilter = false; -static bool CleanupExecuted = false; -static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; - -// Windows creates a new thread to execute the console handler when an event -// (such as CTRL/C) occurs. This causes concurrency issues with the above -// globals which this critical section addresses. -static CRITICAL_SECTION CriticalSection; -static bool CriticalSectionInitialized = false; - -static StringRef Argv0; - -enum { -#if defined(_M_X64) - NativeMachineType = IMAGE_FILE_MACHINE_AMD64 -#elif defined(_M_ARM64) - NativeMachineType = IMAGE_FILE_MACHINE_ARM64 -#elif defined(_M_IX86) - NativeMachineType = IMAGE_FILE_MACHINE_I386 -#elif defined(_M_ARM) - NativeMachineType = IMAGE_FILE_MACHINE_ARMNT -#else - NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN -#endif -}; - -static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, - HANDLE hProcess, HANDLE hThread, - STACKFRAME64 &StackFrameOrig, - CONTEXT *ContextOrig) { - // StackWalk64 modifies the incoming stack frame and context, so copy them. - STACKFRAME64 StackFrame = StackFrameOrig; - - // Copy the register context so that we don't modify it while we unwind. We - // could use InitializeContext + CopyContext, but that's only required to get - // at AVX registers, which typically aren't needed by StackWalk64. Reduce the - // flag set to indicate that there's less data. - CONTEXT Context = *ContextOrig; - Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - - static void *StackTrace[256]; - size_t Depth = 0; - while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, - &Context, 0, fSymFunctionTableAccess64, - fSymGetModuleBase64, 0)) { - if (StackFrame.AddrFrame.Offset == 0) - break; - StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; - if (Depth >= array_lengthof(StackTrace)) - break; - } - - return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); -} - -namespace { -struct FindModuleData { - void **StackTrace; - int Depth; - const char **Modules; - intptr_t *Offsets; - StringSaver *StrPool; -}; -} - -static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, - DWORD64 ModuleBase, ULONG ModuleSize, - void *VoidData) { - FindModuleData *Data = (FindModuleData*)VoidData; - intptr_t Beg = ModuleBase; - intptr_t End = Beg + ModuleSize; - for (int I = 0; I < Data->Depth; I++) { - if (Data->Modules[I]) - continue; - intptr_t Addr = (intptr_t)Data->StackTrace[I]; - if (Beg <= Addr && Addr < End) { - Data->Modules[I] = Data->StrPool->save(ModuleName).data(); - Data->Offsets[I] = Addr - Beg; - } - } - return TRUE; -} - -static bool findModulesAndOffsets(void **StackTrace, int Depth, - const char **Modules, intptr_t *Offsets, - const char *MainExecutableName, - StringSaver &StrPool) { - if (!fEnumerateLoadedModules) - return false; - FindModuleData Data; - Data.StackTrace = StackTrace; - Data.Depth = Depth; - Data.Modules = Modules; - Data.Offsets = Offsets; - Data.StrPool = &StrPool; - fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); - return true; -} - -static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, - HANDLE hThread, STACKFRAME64 &StackFrame, - CONTEXT *Context) { - // Initialize the symbol handler. - fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); - fSymInitialize(hProcess, NULL, TRUE); - - // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs - // and DWARF, so it should do a good job regardless of what debug info or - // linker is in use. - if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, - Context)) { - return; - } - - while (true) { - if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, - Context, 0, fSymFunctionTableAccess64, - fSymGetModuleBase64, 0)) { - break; - } - - if (StackFrame.AddrFrame.Offset == 0) - break; - - using namespace llvm; - // Print the PC in hexadecimal. - DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) || defined(_M_ARM64) - OS << format("0x%016llX", PC); -#elif defined(_M_IX86) || defined(_M_ARM) - OS << format("0x%08lX", static_cast<DWORD>(PC)); -#endif - -// Print the parameters. Assume there are four. -#if defined(_M_X64) || defined(_M_ARM64) - OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", - StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], - StackFrame.Params[3]); -#elif defined(_M_IX86) || defined(_M_ARM) - OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", - static_cast<DWORD>(StackFrame.Params[0]), - static_cast<DWORD>(StackFrame.Params[1]), - static_cast<DWORD>(StackFrame.Params[2]), - static_cast<DWORD>(StackFrame.Params[3])); -#endif - // Verify the PC belongs to a module in this process. - if (!fSymGetModuleBase64(hProcess, PC)) { - OS << " <unknown module>\n"; - continue; - } - - // Print the symbol name. - char buffer[512]; - IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); - memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); - symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dwDisp; - if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { - OS << '\n'; - continue; - } - - buffer[511] = 0; - if (dwDisp > 0) - OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, - dwDisp); - else - OS << format(", %s", (const char*)symbol->Name); - - // Print the source file and line number information. - IMAGEHLP_LINE64 line = {}; - DWORD dwLineDisp; - line.SizeOfStruct = sizeof(line); - if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { - OS << format(", %s, line %lu", line.FileName, line.LineNumber); - if (dwLineDisp > 0) - OS << format(" + 0x%lX byte(s)", dwLineDisp); - } - - OS << '\n'; - } -} - -namespace llvm { - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef _MSC_VER -/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report -/// dialog. "retry" raises an exception which ultimately triggers our stack -/// dumper. -static LLVM_ATTRIBUTE_UNUSED int -AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { - // Set *Return to the retry code for the return value of _CrtDbgReport: - // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx - // This may also trigger just-in-time debugging via DebugBreak(). - if (Return) - *Return = 1; - // Don't call _CrtDbgReport. - return TRUE; -} - -#endif - -extern "C" void HandleAbort(int Sig) { - if (Sig == SIGABRT) { - LLVM_BUILTIN_TRAP; - } -} - -static void InitializeThreading() { - if (CriticalSectionInitialized) - return; - - // Now's the time to create the critical section. This is the first time - // through here, and there's only one thread. - InitializeCriticalSection(&CriticalSection); - CriticalSectionInitialized = true; -} - -static void RegisterHandler() { - // If we cannot load up the APIs (which would be unexpected as they should - // exist on every version of Windows we support), we will bail out since - // there would be nothing to report. - if (!load64BitDebugHelp()) { - assert(false && "These APIs should always be available"); - return; - } - - if (RegisteredUnhandledExceptionFilter) { - EnterCriticalSection(&CriticalSection); - return; - } - - InitializeThreading(); - - // Enter it immediately. Now if someone hits CTRL/C, the console handler - // can't proceed until the globals are updated. - EnterCriticalSection(&CriticalSection); - - RegisteredUnhandledExceptionFilter = true; - OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); - SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); - - // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or - // else multi-threading problems will ensue. -} - -// The public API -bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { - RegisterHandler(); - - if (CleanupExecuted) { - if (ErrMsg) - *ErrMsg = "Process terminating -- cannot register for removal"; - return true; - } - - if (FilesToRemove == NULL) - FilesToRemove = new std::vector<std::string>; - - FilesToRemove->push_back(Filename); - - LeaveCriticalSection(&CriticalSection); - return false; -} - -// The public API -void sys::DontRemoveFileOnSignal(StringRef Filename) { - if (FilesToRemove == NULL) - return; - - RegisterHandler(); - - std::vector<std::string>::reverse_iterator I = - find(reverse(*FilesToRemove), Filename); - if (I != FilesToRemove->rend()) - FilesToRemove->erase(I.base()-1); - - LeaveCriticalSection(&CriticalSection); -} - -void sys::DisableSystemDialogsOnCrash() { - // Crash to stack trace handler on abort. - signal(SIGABRT, HandleAbort); - - // The following functions are not reliably accessible on MinGW. -#ifdef _MSC_VER - // We're already handling writing a "something went wrong" message. - _set_abort_behavior(0, _WRITE_ABORT_MSG); - // Disable Dr. Watson. - _set_abort_behavior(0, _CALL_REPORTFAULT); - _CrtSetReportHook(AvoidMessageBoxHook); -#endif - - // Disable standard error dialog box. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - _set_error_mode(_OUT_TO_STDERR); -} - -/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the -/// process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, - bool DisableCrashReporting) { - ::Argv0 = Argv0; - - if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) - Process::PreventCoreFiles(); - - DisableSystemDialogsOnCrash(); - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} -} - -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is -// missing it but mingw-w64 has it. -extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); -#endif - -void llvm::sys::PrintStackTrace(raw_ostream &OS) { - STACKFRAME64 StackFrame = {}; - CONTEXT Context = {}; - ::RtlCaptureContext(&Context); -#if defined(_M_X64) - StackFrame.AddrPC.Offset = Context.Rip; - StackFrame.AddrStack.Offset = Context.Rsp; - StackFrame.AddrFrame.Offset = Context.Rbp; -#elif defined(_M_IX86) - StackFrame.AddrPC.Offset = Context.Eip; - StackFrame.AddrStack.Offset = Context.Esp; - StackFrame.AddrFrame.Offset = Context.Ebp; -#elif defined(_M_ARM64) - StackFrame.AddrPC.Offset = Context.Pc; - StackFrame.AddrStack.Offset = Context.Sp; - StackFrame.AddrFrame.Offset = Context.Fp; -#elif defined(_M_ARM) - StackFrame.AddrPC.Offset = Context.Pc; - StackFrame.AddrStack.Offset = Context.Sp; - StackFrame.AddrFrame.Offset = Context.R11; -#endif - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Mode = AddrModeFlat; - StackFrame.AddrFrame.Mode = AddrModeFlat; - PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), - StackFrame, &Context); -} - - -void llvm::sys::SetInterruptFunction(void (*IF)()) { - RegisterHandler(); - InterruptFunction = IF; - LeaveCriticalSection(&CriticalSection); -} - -void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { - // Unimplemented. -} - - -/// Add a function to be called when a signal is delivered to the process. The -/// handler can have a cookie passed to it to identify what instance of the -/// handler it is. -void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, - void *Cookie) { - insertSignalHandler(FnPtr, Cookie); - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} - -static void Cleanup() { - if (CleanupExecuted) - return; - - EnterCriticalSection(&CriticalSection); - - // Prevent other thread from registering new files and directories for - // removal, should we be executing because of the console handler callback. - CleanupExecuted = true; - - // FIXME: open files cannot be deleted. - if (FilesToRemove != NULL) - while (!FilesToRemove->empty()) { - llvm::sys::fs::remove(FilesToRemove->back()); - FilesToRemove->pop_back(); - } - llvm::sys::RunSignalHandlers(); - LeaveCriticalSection(&CriticalSection); -} - -void llvm::sys::RunInterruptHandlers() { - // The interrupt handler may be called from an interrupt, but it may also be - // called manually (such as the case of report_fatal_error with no registered - // error handler). We must ensure that the critical section is properly - // initialized. - InitializeThreading(); - Cleanup(); -} - -/// Find the Windows Registry Key for a given location. -/// -/// \returns a valid HKEY if the location exists, else NULL. -static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { - HKEY Key; - if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, - RegistryLocation.str().c_str(), 0, - KEY_QUERY_VALUE | KEY_READ, &Key)) - return NULL; - - return Key; -} - -/// Populate ResultDirectory with the value for "DumpFolder" for a given -/// Windows Registry key. -/// -/// \returns true if a valid value for DumpFolder exists, false otherwise. -static bool GetDumpFolder(HKEY Key, - llvm::SmallVectorImpl<char> &ResultDirectory) { - using llvm::sys::windows::UTF16ToUTF8; - - if (!Key) - return false; - - DWORD BufferLengthBytes = 0; - - if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, - NULL, NULL, &BufferLengthBytes)) - return false; - - SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); - - if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, - NULL, Buffer.data(), &BufferLengthBytes)) - return false; - - DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); - - if (!ExpandBufferSize) - return false; - - SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); - - if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), - ExpandBuffer.data(), - ExpandBufferSize)) - return false; - - if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) - return false; - - return true; -} - -/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of -/// "DumpType" for a given Windows Registry key. -/// -/// According to -/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx -/// valid values for DumpType are: -/// * 0: Custom dump -/// * 1: Mini dump -/// * 2: Full dump -/// If "Custom dump" is specified then the "CustomDumpFlags" field is read -/// containing a bitwise combination of MINIDUMP_TYPE values. -/// -/// \returns true if a valid value for ResultType can be set, false otherwise. -static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { - if (!Key) - return false; - - DWORD DumpType; - DWORD TypeSize = sizeof(DumpType); - if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, - NULL, &DumpType, - &TypeSize)) - return false; - - switch (DumpType) { - case 0: { - DWORD Flags = 0; - if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", - RRF_RT_REG_DWORD, NULL, &Flags, - &TypeSize)) - return false; - - ResultType = static_cast<MINIDUMP_TYPE>(Flags); - break; - } - case 1: - ResultType = MiniDumpNormal; - break; - case 2: - ResultType = MiniDumpWithFullMemory; - break; - default: - return false; - } - return true; -} - -/// Write a Windows dump file containing process information that can be -/// used for post-mortem debugging. -/// -/// \returns zero error code if a mini dump created, actual error code -/// otherwise. -static std::error_code WINAPI -WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { - using namespace llvm; - using namespace llvm::sys; - - std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); - StringRef ProgramName; - - if (MainExecutableName.empty()) { - // If we can't get the executable filename, - // things are in worse shape than we realize - // and we should just bail out. - return mapWindowsError(::GetLastError()); - } - - ProgramName = path::filename(MainExecutableName.c_str()); - - // The Windows Registry location as specified at - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx - // "Collecting User-Mode Dumps" that may optionally be set to collect crash - // dumps in a specified location. - StringRef LocalDumpsRegistryLocation = - "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; - - // The key pointing to the Registry location that may contain global crash - // dump settings. This will be NULL if the location can not be found. - ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); - - // The key pointing to the Registry location that may contain - // application-specific crash dump settings. This will be NULL if the - // location can not be found. - ScopedRegHandle AppSpecificKey( - FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); - - // Look to see if a dump type is specified in the registry; first with the - // app-specific key and failing that with the global key. If none are found - // default to a normal dump (GetDumpType will return false either if the key - // is NULL or if there is no valid DumpType value at its location). - MINIDUMP_TYPE DumpType; - if (!GetDumpType(AppSpecificKey, DumpType)) - if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) - DumpType = MiniDumpNormal; - - // Look to see if a dump location is specified in the registry; first with the - // app-specific key and failing that with the global key. If none are found - // we'll just create the dump file in the default temporary file location - // (GetDumpFolder will return false either if the key is NULL or if there is - // no valid DumpFolder value at its location). - bool ExplicitDumpDirectorySet = true; - SmallString<MAX_PATH> DumpDirectory; - if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) - if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) - ExplicitDumpDirectorySet = false; - - int FD; - SmallString<MAX_PATH> DumpPath; - - if (ExplicitDumpDirectorySet) { - if (std::error_code EC = fs::create_directories(DumpDirectory)) - return EC; - if (std::error_code EC = fs::createUniqueFile( - Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, - DumpPath)) - return EC; - } else if (std::error_code EC = - fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) - return EC; - - // Our support functions return a file descriptor but Windows wants a handle. - ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); - - if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), - FileHandle, DumpType, ExceptionInfo, NULL, NULL)) - return mapWindowsError(::GetLastError()); - - llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; - return std::error_code(); -} - -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { - Cleanup(); - - // We'll automatically write a Minidump file here to help diagnose - // the nasty sorts of crashes that aren't 100% reproducible from a set of - // inputs (or in the event that the user is unable or unwilling to provide a - // reproducible case). - if (!llvm::sys::Process::AreCoreFilesPrevented()) { - MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; - ExceptionInfo.ThreadId = ::GetCurrentThreadId(); - ExceptionInfo.ExceptionPointers = ep; - ExceptionInfo.ClientPointers = FALSE; - - if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) - llvm::errs() << "Could not write crash dump file: " << EC.message() - << "\n"; - } - - // Initialize the STACKFRAME structure. - STACKFRAME64 StackFrame = {}; - -#if defined(_M_X64) - StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; - StackFrame.AddrStack.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; - StackFrame.AddrFrame.Mode = AddrModeFlat; -#elif defined(_M_IX86) - StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; - StackFrame.AddrStack.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; - StackFrame.AddrFrame.Mode = AddrModeFlat; -#elif defined(_M_ARM64) || defined(_M_ARM) - StackFrame.AddrPC.Offset = ep->ContextRecord->Pc; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = ep->ContextRecord->Sp; - StackFrame.AddrStack.Mode = AddrModeFlat; -#if defined(_M_ARM64) - StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp; -#else - StackFrame.AddrFrame.Offset = ep->ContextRecord->R11; -#endif - StackFrame.AddrFrame.Mode = AddrModeFlat; -#endif - - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, - ep->ContextRecord); - - _exit(ep->ExceptionRecord->ExceptionCode); -} - -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { - // We are running in our very own thread, courtesy of Windows. - EnterCriticalSection(&CriticalSection); - Cleanup(); - - // If an interrupt function has been set, go and run one it; otherwise, - // the process dies. - void (*IF)() = InterruptFunction; - InterruptFunction = 0; // Don't run it on another CTRL-C. - - if (IF) { - // Note: if the interrupt function throws an exception, there is nothing - // to catch it in this thread so it will kill the process. - IF(); // Run it now. - LeaveCriticalSection(&CriticalSection); - return TRUE; // Don't kill the process. - } - - // Allow normal processing to take place; i.e., the process dies. - LeaveCriticalSection(&CriticalSection); - return FALSE; -} - -#if __MINGW32__ - // We turned these warnings off for this file so that MinGW-g++ doesn't - // complain about the ll format specifiers used. Now we are turning the - // warnings back on. If MinGW starts to support diagnostic stacks, we can - // replace this with a pop. - #pragma GCC diagnostic warning "-Wformat" - #pragma GCC diagnostic warning "-Wformat-extra-args" -#endif diff --git a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc deleted file mode 100644 index 1e0ed955e9ab..000000000000 --- a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc +++ /dev/null @@ -1,51 +0,0 @@ -//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- 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 implements the Win32 specific (non-pthread) ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" -#include "llvm/Support/ThreadLocal.h" - -namespace llvm { - -sys::ThreadLocalImpl::ThreadLocalImpl() : data() { - static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); - DWORD* tls = reinterpret_cast<DWORD*>(&data); - *tls = TlsAlloc(); - assert(*tls != TLS_OUT_OF_INDEXES); -} - -sys::ThreadLocalImpl::~ThreadLocalImpl() { - DWORD* tls = reinterpret_cast<DWORD*>(&data); - TlsFree(*tls); -} - -void *sys::ThreadLocalImpl::getInstance() { - DWORD* tls = reinterpret_cast<DWORD*>(&data); - return TlsGetValue(*tls); -} - -void sys::ThreadLocalImpl::setInstance(const void* d){ - DWORD* tls = reinterpret_cast<DWORD*>(&data); - int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); - assert(errorcode != 0); - (void)errorcode; -} - -void sys::ThreadLocalImpl::removeInstance() { - setInstance(0); -} - -} diff --git a/contrib/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm/lib/Support/Windows/Threading.inc deleted file mode 100644 index 96649472cc90..000000000000 --- a/contrib/llvm/lib/Support/Windows/Threading.inc +++ /dev/null @@ -1,124 +0,0 @@ -//===- Windows/Threading.inc - Win32 Threading 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 Threading functions. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" - -#include "WindowsSupport.h" -#include <process.h> - -// Windows will at times define MemoryFence. -#ifdef MemoryFence -#undef MemoryFence -#endif - -namespace { - struct ThreadInfo { - void(*func)(void*); - void *param; - }; -} - -static unsigned __stdcall ThreadCallback(void *param) { - struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); - info->func(info->param); - - return 0; -} - -void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - struct ThreadInfo param = { Fn, UserData }; - - HANDLE hThread = (HANDLE)::_beginthreadex(NULL, - RequestedStackSize, ThreadCallback, - ¶m, 0, NULL); - - if (hThread) { - // We actually don't care whether the wait succeeds or fails, in - // the same way we don't care whether the pthread_join call succeeds - // or fails. There's not much we could do if this were to fail. But - // on success, this call will wait until the thread finishes executing - // before returning. - (void)::WaitForSingleObject(hThread, INFINITE); - ::CloseHandle(hThread); - } -} - -uint64_t llvm::get_threadid() { - return uint64_t(::GetCurrentThreadId()); -} - -uint32_t llvm::get_max_thread_name_length() { return 0; } - -#if defined(_MSC_VER) -static void SetThreadName(DWORD Id, LPCSTR Name) { - constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; - -#pragma pack(push, 8) - struct THREADNAME_INFO { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to thread name - DWORD dwThreadId; // Thread ID (-1 == current thread) - DWORD dwFlags; // Reserved. Do not use. - }; -#pragma pack(pop) - - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = Name; - info.dwThreadId = Id; - info.dwFlags = 0; - - __try { - ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), - (ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) { - } -} -#endif - -void llvm::set_thread_name(const Twine &Name) { -#if defined(_MSC_VER) - // Make sure the input is null terminated. - SmallString<64> Storage; - StringRef NameStr = Name.toNullTerminatedStringRef(Storage); - SetThreadName(::GetCurrentThreadId(), NameStr.data()); -#endif -} - -void llvm::get_thread_name(SmallVectorImpl<char> &Name) { - // "Name" is not an inherent property of a thread on Windows. In fact, when - // you "set" the name, you are only firing a one-time message to a debugger - // which it interprets as a program setting its threads' name. We may be - // able to get fancy by creating a TLS entry when someone calls - // set_thread_name so that subsequent calls to get_thread_name return this - // value. - Name.clear(); -} - -SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { - // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority - // Begin background processing mode. The system lowers the resource scheduling - // priorities of the thread so that it can perform background work without - // significantly affecting activity in the foreground. - // End background processing mode. The system restores the resource scheduling - // priorities of the thread as they were before the thread entered background - // processing mode. - return SetThreadPriority(GetCurrentThread(), - Priority == ThreadPriority::Background - ? THREAD_MODE_BACKGROUND_BEGIN - : THREAD_MODE_BACKGROUND_END) - ? SetThreadPriorityResult::SUCCESS - : SetThreadPriorityResult::FAILURE; -} diff --git a/contrib/llvm/lib/Support/Windows/Watchdog.inc b/contrib/llvm/lib/Support/Windows/Watchdog.inc deleted file mode 100644 index a362c999de76..000000000000 --- a/contrib/llvm/lib/Support/Windows/Watchdog.inc +++ /dev/null @@ -1,23 +0,0 @@ -//===--- Windows/Watchdog.inc - Windows Watchdog 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 generic Windows implementation of the Watchdog class. -// -//===----------------------------------------------------------------------===// - -// TODO: implement. -// Currently this is only used by PrettyStackTrace which is also unimplemented -// on Windows. Roughly, a Windows implementation would use CreateWaitableTimer -// and a second thread to run the TimerAPCProc. - -namespace llvm { - namespace sys { - Watchdog::Watchdog(unsigned int seconds) {} - Watchdog::~Watchdog() {} - } -} diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h deleted file mode 100644 index fed9b2f462ef..000000000000 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ /dev/null @@ -1,234 +0,0 @@ -//===- WindowsSupport.h - Common Windows Include File -----------*- 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 defines things specific to Windows implementations. In addition to -// providing some helpers for working with win32 APIs, this header wraps -// <windows.h> with some portability macros. Always include WindowsSupport.h -// instead of including <windows.h> directly. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H -#define LLVM_SUPPORT_WINDOWSSUPPORT_H - -// mingw-w64 tends to define it as 0x0502 in its headers. -#undef _WIN32_WINNT -#undef _WIN32_IE - -// Require at least Windows 7 API. -#define _WIN32_WINNT 0x0601 -#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed. -#define WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Config/config.h" // Get build system configuration settings -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/VersionTuple.h" -#include <cassert> -#include <string> -#include <system_error> -#include <windows.h> - -// Must be included after windows.h -#include <wincrypt.h> - -namespace llvm { - -/// Determines if the program is running on Windows 8 or newer. This -/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended -/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't -/// yet have VersionHelpers.h, so we have our own helper. -bool RunningWindows8OrGreater(); - -/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses -/// RtlGetVersion or GetVersionEx under the hood depending on what is available. -/// GetVersionEx is deprecated, but this API exposes the build number which can -/// be useful for working around certain kernel bugs. -llvm::VersionTuple GetWindowsOSVersion(); - -bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix); - -template <typename HandleTraits> -class ScopedHandle { - typedef typename HandleTraits::handle_type handle_type; - handle_type Handle; - - ScopedHandle(const ScopedHandle &other) = delete; - void operator=(const ScopedHandle &other) = delete; -public: - ScopedHandle() - : Handle(HandleTraits::GetInvalid()) {} - - explicit ScopedHandle(handle_type h) - : Handle(h) {} - - ~ScopedHandle() { - if (HandleTraits::IsValid(Handle)) - HandleTraits::Close(Handle); - } - - handle_type take() { - handle_type t = Handle; - Handle = HandleTraits::GetInvalid(); - return t; - } - - ScopedHandle &operator=(handle_type h) { - if (HandleTraits::IsValid(Handle)) - HandleTraits::Close(Handle); - Handle = h; - return *this; - } - - // True if Handle is valid. - explicit operator bool() const { - return HandleTraits::IsValid(Handle) ? true : false; - } - - operator handle_type() const { - return Handle; - } -}; - -struct CommonHandleTraits { - typedef HANDLE handle_type; - - static handle_type GetInvalid() { - return INVALID_HANDLE_VALUE; - } - - static void Close(handle_type h) { - ::CloseHandle(h); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct JobHandleTraits : CommonHandleTraits { - static handle_type GetInvalid() { - return NULL; - } -}; - -struct CryptContextTraits : CommonHandleTraits { - typedef HCRYPTPROV handle_type; - - static handle_type GetInvalid() { - return 0; - } - - static void Close(handle_type h) { - ::CryptReleaseContext(h, 0); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct RegTraits : CommonHandleTraits { - typedef HKEY handle_type; - - static handle_type GetInvalid() { - return NULL; - } - - static void Close(handle_type h) { - ::RegCloseKey(h); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct FindHandleTraits : CommonHandleTraits { - static void Close(handle_type h) { - ::FindClose(h); - } -}; - -struct FileHandleTraits : CommonHandleTraits {}; - -typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; -typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; -typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; -typedef ScopedHandle<RegTraits> ScopedRegHandle; -typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; -typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; - -template <class T> -class SmallVectorImpl; - -template <class T> -typename SmallVectorImpl<T>::const_pointer -c_str(SmallVectorImpl<T> &str) { - str.push_back(0); - str.pop_back(); - return str.data(); -} - -namespace sys { - -inline std::chrono::nanoseconds toDuration(FILETIME Time) { - ULARGE_INTEGER TimeInteger; - TimeInteger.LowPart = Time.dwLowDateTime; - TimeInteger.HighPart = Time.dwHighDateTime; - - // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) - return std::chrono::nanoseconds(100 * TimeInteger.QuadPart); -} - -inline TimePoint<> toTimePoint(FILETIME Time) { - ULARGE_INTEGER TimeInteger; - TimeInteger.LowPart = Time.dwLowDateTime; - TimeInteger.HighPart = Time.dwHighDateTime; - - // Adjust for different epoch - TimeInteger.QuadPart -= 11644473600ll * 10000000; - - // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) - return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart)); -} - -inline FILETIME toFILETIME(TimePoint<> TP) { - ULARGE_INTEGER TimeInteger; - TimeInteger.QuadPart = TP.time_since_epoch().count() / 100; - TimeInteger.QuadPart += 11644473600ll * 10000000; - - FILETIME Time; - Time.dwLowDateTime = TimeInteger.LowPart; - Time.dwHighDateTime = TimeInteger.HighPart; - return Time; -} - -namespace windows { -// Returns command line arguments. Unlike arguments given to main(), -// this function guarantees that the returned arguments are encoded in -// UTF-8 regardless of the current code page setting. -std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args, - BumpPtrAllocator &Alloc); -} // end namespace windows -} // end namespace sys -} // end namespace llvm. - -#endif diff --git a/contrib/llvm/lib/Support/Windows/explicit_symbols.inc b/contrib/llvm/lib/Support/Windows/explicit_symbols.inc deleted file mode 100644 index bbbf7ea6a777..000000000000 --- a/contrib/llvm/lib/Support/Windows/explicit_symbols.inc +++ /dev/null @@ -1,102 +0,0 @@ -/* in libgcc.a */ - -#ifdef HAVE__ALLOCA - EXPLICIT_SYMBOL(_alloca) - EXPLICIT_SYMBOL2(alloca, _alloca) -#endif -#ifdef HAVE___ALLOCA - EXPLICIT_SYMBOL(__alloca) -#endif -#ifdef HAVE___CHKSTK - EXPLICIT_SYMBOL(__chkstk) -#endif -#ifdef HAVE___CHKSTK_MS - EXPLICIT_SYMBOL(__chkstk_ms) -#endif -#ifdef HAVE____CHKSTK - EXPLICIT_SYMBOL(___chkstk) -#endif -#ifdef HAVE____CHKSTK_MS - EXPLICIT_SYMBOL(___chkstk_ms) -#endif -#ifdef HAVE___MAIN - EXPLICIT_SYMBOL(__main) // FIXME: Don't call it. -#endif - -#ifdef HAVE___ASHLDI3 - EXPLICIT_SYMBOL(__ashldi3) -#endif -#ifdef HAVE___ASHRDI3 - EXPLICIT_SYMBOL(__ashrdi3) -#endif -#ifdef HAVE___CMPDI2 // FIXME: unused - EXPLICIT_SYMBOL(__cmpdi2) -#endif -#ifdef HAVE___DIVDI3 - EXPLICIT_SYMBOL(__divdi3) -#endif -#ifdef HAVE___FIXDFDI - EXPLICIT_SYMBOL(__fixdfdi) -#endif -#ifdef HAVE___FIXSFDI - EXPLICIT_SYMBOL(__fixsfdi) -#endif -#ifdef HAVE___FIXUNSDFDI - EXPLICIT_SYMBOL(__fixunsdfdi) -#endif -#ifdef HAVE___FIXUNSSFDI - EXPLICIT_SYMBOL(__fixunssfdi) -#endif -#ifdef HAVE___FLOATDIDF - EXPLICIT_SYMBOL(__floatdidf) -#endif -#ifdef HAVE___FLOATDISF - EXPLICIT_SYMBOL(__floatdisf) -#endif -#ifdef HAVE___LSHRDI3 - EXPLICIT_SYMBOL(__lshrdi3) -#endif -#ifdef HAVE___MODDI3 - EXPLICIT_SYMBOL(__moddi3) -#endif -#ifdef HAVE___UDIVDI3 - EXPLICIT_SYMBOL(__udivdi3) -#endif -#ifdef HAVE___UMODDI3 - EXPLICIT_SYMBOL(__umoddi3) -#endif - -/* msvcrt */ -#if defined(_MSC_VER) - EXPLICIT_SYMBOL2(alloca, _alloca_probe) - -#ifdef _M_IX86 -#define INLINE_DEF_FLOAT_SYMBOL(SYM, ARGC) INLINE_DEF_SYMBOL##ARGC(float, SYM) - INLINE_DEF_FLOAT_SYMBOL(acosf, 1) - INLINE_DEF_FLOAT_SYMBOL(asinf, 1) - INLINE_DEF_FLOAT_SYMBOL(atanf, 1) - INLINE_DEF_FLOAT_SYMBOL(atan2f, 2) - INLINE_DEF_FLOAT_SYMBOL(ceilf, 1) - INLINE_DEF_FLOAT_SYMBOL(cosf, 1) - INLINE_DEF_FLOAT_SYMBOL(coshf, 1) - INLINE_DEF_FLOAT_SYMBOL(expf, 1) - INLINE_DEF_FLOAT_SYMBOL(floorf, 1) - INLINE_DEF_FLOAT_SYMBOL(fmodf, 2) - INLINE_DEF_FLOAT_SYMBOL(logf, 1) - INLINE_DEF_FLOAT_SYMBOL(powf, 2) - INLINE_DEF_FLOAT_SYMBOL(sinf, 1) - INLINE_DEF_FLOAT_SYMBOL(sinhf, 1) - INLINE_DEF_FLOAT_SYMBOL(sqrtf, 1) - INLINE_DEF_FLOAT_SYMBOL(tanf, 1) - INLINE_DEF_FLOAT_SYMBOL(tanhf, 1) - - // These were added in VS 2013. -#if (1800 <= _MSC_VER && _MSC_VER < 1900) - INLINE_DEF_FLOAT_SYMBOL(copysignf, 2) - INLINE_DEF_FLOAT_SYMBOL(fminf, 2) - INLINE_DEF_FLOAT_SYMBOL(fmaxf, 2) -#endif -#undef INLINE_DEF_FLOAT_SYMBOL -#endif - -#endif |