summaryrefslogtreecommitdiff
path: root/lib/Support/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support/Windows')
-rw-r--r--lib/Support/Windows/DynamicLibrary.inc2
-rw-r--r--lib/Support/Windows/Path.inc150
-rw-r--r--lib/Support/Windows/Process.inc38
-rw-r--r--lib/Support/Windows/Signals.inc228
-rw-r--r--lib/Support/Windows/WindowsSupport.h28
5 files changed, 407 insertions, 39 deletions
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc
index 17418b015c758..050689483deb4 100644
--- a/lib/Support/Windows/DynamicLibrary.inc
+++ b/lib/Support/Windows/DynamicLibrary.inc
@@ -45,7 +45,7 @@ static bool loadDebugHelp(void) {
}
static BOOL CALLBACK
-ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, DWORD64 ModuleBase,
+ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase,
ULONG ModuleSize, PVOID UserContext) {
OpenedHandles->insert((HMODULE)ModuleBase);
return TRUE;
diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc
index 5ef77b150ef08..fab6aeca54a94 100644
--- a/lib/Support/Windows/Path.inc
+++ b/lib/Support/Windows/Path.inc
@@ -151,6 +151,29 @@ UniqueID file_status::getUniqueID() const {
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;
+}
+
+TimeValue file_status::getLastAccessedTime() const {
+ ULARGE_INTEGER UI;
+ UI.LowPart = LastAccessedTimeLow;
+ UI.HighPart = LastAccessedTimeHigh;
+
+ TimeValue Ret;
+ Ret.fromWin32Time(UI.QuadPart);
+ return Ret;
+}
+
TimeValue file_status::getLastModificationTime() const {
ULARGE_INTEGER UI;
UI.LowPart = LastWriteTimeLow;
@@ -255,24 +278,43 @@ std::error_code rename(const Twine &from, const Twine &to) {
std::error_code ec = std::error_code();
- // Retry while we see ERROR_ACCESS_DENIED.
+ // Retry while we see recoverable errors.
// System scanners (eg. indexer) might open the source file when it is written
// and closed.
- for (int i = 0; i < 2000; i++) {
- // Try ReplaceFile first, as it is able to associate a new data stream with
- // the destination even if the destination file is currently open.
- if (::ReplaceFileW(wide_to.begin(), wide_from.begin(), NULL, 0, NULL, NULL))
- return std::error_code();
+ bool TryReplace = true;
- // We get ERROR_FILE_NOT_FOUND if the destination file is missing.
- // MoveFileEx can handle this case.
- DWORD ReplaceError = ::GetLastError();
- ec = mapWindowsError(ReplaceError);
- if (ReplaceError != ERROR_ACCESS_DENIED &&
- ReplaceError != ERROR_FILE_NOT_FOUND &&
- ReplaceError != ERROR_SHARING_VIOLATION)
- break;
+ for (int i = 0; i < 2000; i++) {
+ if (i > 0)
+ ::Sleep(1);
+
+ if (TryReplace) {
+ // Try ReplaceFile first, as it is able to associate a new data stream
+ // with the destination even if the destination file is currently open.
+ if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
+ return std::error_code();
+
+ DWORD ReplaceError = ::GetLastError();
+ ec = mapWindowsError(ReplaceError);
+
+ // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
+ // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
+ if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
+ ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
+ TryReplace = false;
+ continue;
+ }
+ // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
+ // using ReplaceFileW().
+ if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
+ continue;
+ // We get ERROR_FILE_NOT_FOUND if the destination file is missing.
+ // MoveFileEx can handle this case.
+ if (ReplaceError != ERROR_ACCESS_DENIED &&
+ ReplaceError != ERROR_FILE_NOT_FOUND &&
+ ReplaceError != ERROR_SHARING_VIOLATION)
+ break;
+ }
if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
@@ -281,8 +323,6 @@ std::error_code rename(const Twine &from, const Twine &to) {
DWORD MoveError = ::GetLastError();
ec = mapWindowsError(MoveError);
if (MoveError != ERROR_ACCESS_DENIED) break;
-
- ::Sleep(1);
}
return ec;
@@ -327,13 +367,15 @@ bool can_execute(const Twine &Path) {
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.LastWriteTimeHigh == B.LastWriteTimeHigh &&
- A.LastWriteTimeLow == B.LastWriteTimeLow &&
- A.VolumeSerialNumber == B.VolumeSerialNumber;
+ 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) {
@@ -361,7 +403,7 @@ static bool isReservedName(StringRef path) {
if (path.startswith("\\\\.\\"))
return true;
- // Then compare against the list of ancient reserved names
+ // 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;
@@ -404,7 +446,9 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
? file_type::directory_file
: file_type::regular_file;
Result =
- file_status(Type, Info.ftLastWriteTime.dwHighDateTime,
+ file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
+ Info.ftLastAccessTime.dwLowDateTime,
+ Info.ftLastWriteTime.dwHighDateTime,
Info.ftLastWriteTime.dwLowDateTime,
Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
@@ -663,7 +707,8 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
return std::error_code();
}
-std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ SmallVectorImpl<char> *RealPath) {
SmallVector<wchar_t, 128> PathUTF16;
if (std::error_code EC = widenPath(Name, PathUTF16))
@@ -692,6 +737,22 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
return mapWindowsError(ERROR_INVALID_HANDLE);
}
+ // Fetch the real name of the file, if the user asked
+ if (RealPath) {
+ RealPath->clear();
+ wchar_t RealPathUTF16[MAX_PATH];
+ DWORD CountChars =
+ ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH,
+ FILE_NAME_NORMALIZED);
+ if (CountChars > 0 && CountChars < MAX_PATH) {
+ // Convert the result from UTF-16 to UTF-8.
+ SmallString<MAX_PATH> RealPathUTF8;
+ if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8))
+ RealPath->append(RealPathUTF8.data(),
+ RealPathUTF8.data() + strlen(RealPathUTF8.data()));
+ }
+ }
+
ResultFD = FD;
return std::error_code();
}
@@ -752,6 +813,42 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
ResultFD = FD;
return std::error_code();
}
+
+std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) {
+ HANDLE FileHandle = reinterpret_cast<HANDLE>(::_get_osfhandle(FD));
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ return make_error_code(errc::bad_file_descriptor);
+
+ DWORD CharCount;
+ SmallVector<wchar_t, 1024> TempPath;
+ do {
+ CharCount = ::GetFinalPathNameByHandleW(FileHandle, TempPath.begin(),
+ TempPath.capacity(),
+ FILE_NAME_NORMALIZED);
+ if (CharCount < TempPath.capacity())
+ break;
+
+ // Reserve sufficient space for the path as well as the null character. Even
+ // though the API does not document that it is required, if we reserve just
+ // CharCount space, the function call will not store the resulting path and
+ // still report success.
+ TempPath.reserve(CharCount + 1);
+ } while (true);
+
+ if (CharCount == 0)
+ return mapWindowsError(::GetLastError());
+
+ TempPath.set_size(CharCount);
+
+ // On earlier Windows releases, the character count includes the terminating
+ // null.
+ if (TempPath.back() == L'\0') {
+ --CharCount;
+ TempPath.pop_back();
+ }
+
+ return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath);
+}
} // end namespace fs
namespace path {
@@ -886,6 +983,7 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
llvm::SmallVectorImpl<char> &utf8) {
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
}
+
} // end namespace windows
} // end namespace sys
} // end namespace llvm
diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc
index dae35a88132ba..b012991c2a549 100644
--- a/lib/Support/Windows/Process.inc
+++ b/lib/Support/Windows/Process.inc
@@ -123,6 +123,8 @@ void Process::PreventCoreFiles() {
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
+
+ coreFilesPrevented = true;
}
/// Returns the environment variable \arg Name's value as a string encoded in
@@ -199,6 +201,9 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
const int DirSize = Dir.size();
// 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(Arg, &FileData);
if (FindHandle == INVALID_HANDLE_VALUE) {
@@ -213,7 +218,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
if (ec)
break;
- // Push the filename onto Dir, and remove it afterwards.
+ // Append FileName to Dir, and remove it afterwards.
llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size()));
AllocateAndPush(Dir, Args, Allocator);
Dir.resize(DirSize);
@@ -223,6 +228,23 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
return ec;
}
+static std::error_code
+ExpandShortFileName(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
+ SpecificBumpPtrAllocator<char> &Allocator) {
+ SmallVector<wchar_t, MAX_PATH> LongPath;
+ DWORD Length = GetLongPathNameW(Arg, LongPath.data(), LongPath.capacity());
+ if (Length == 0)
+ return mapWindowsError(GetLastError());
+ if (Length > LongPath.capacity()) {
+ // 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);
+ }
+ LongPath.set_size(Length);
+ return ConvertAndPushArg(LongPath.data(), Args, Allocator);
+}
+
std::error_code
Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
ArrayRef<const char *>,
@@ -236,7 +258,19 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
Args.reserve(ArgCount);
std::error_code ec;
- for (int i = 0; i < ArgCount; ++i) {
+ // 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];
+ int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH);
+ if (0 < Length && Length < MAX_PATH)
+ UnicodeCommandLine[0] = ModuleName;
+
+ // 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.
+ ec = ExpandShortFileName(UnicodeCommandLine[0], Args, ArgAllocator);
+
+ for (int i = 1; i < ArgCount && !ec; ++i) {
ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator);
if (ec)
break;
diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc
index f40ca72996a12..1e2fa4210df69 100644
--- a/lib/Support/Windows/Signals.inc
+++ b/lib/Support/Windows/Signals.inc
@@ -11,7 +11,11 @@
//
//===----------------------------------------------------------------------===//
#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>
@@ -117,6 +121,12 @@ typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
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,
@@ -154,6 +164,8 @@ 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)
@@ -171,7 +183,7 @@ static bool load64BitDebugHelp(void) {
fEnumerateLoadedModules = (fpEnumerateLoadedModules)
::GetProcAddress(hLib, "EnumerateLoadedModules64");
}
- return fStackWalk64 && fSymInitialize && fSymSetOptions;
+ return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
}
using namespace llvm;
@@ -194,6 +206,8 @@ static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
static CRITICAL_SECTION CriticalSection;
static bool CriticalSectionInitialized = false;
+static StringRef Argv0;
+
enum {
#if defined(_M_X64)
NativeMachineType = IMAGE_FILE_MACHINE_AMD64
@@ -228,7 +242,7 @@ static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
break;
}
- return printSymbolizedStackTrace(&StackTrace[0], Depth, OS);
+ return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);
}
namespace {
@@ -241,7 +255,7 @@ struct FindModuleData {
};
}
-static BOOL CALLBACK findModuleCallback(WIN32_ELMCB_PCSTR ModuleName,
+static BOOL CALLBACK findModuleCallback(PCSTR ModuleName,
DWORD64 ModuleBase, ULONG ModuleSize,
void *VoidData) {
FindModuleData *Data = (FindModuleData*)VoidData;
@@ -484,7 +498,13 @@ void sys::DisableSystemDialogsOnCrash() {
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
-void sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) {
+void sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
+ bool DisableCrashReporting) {
+ ::Argv0 = Argv0;
+
+ if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
+ Process::PreventCoreFiles();
+
DisableSystemDialogsOnCrash();
RegisterHandler();
LeaveCriticalSection(&CriticalSection);
@@ -563,9 +583,209 @@ void llvm::sys::RunInterruptHandlers() {
Cleanup();
}
+/// \brief 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;
+}
+
+/// \brief 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;
+}
+
+/// \brief 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;
+}
+
+/// \brief 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::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 = {};
diff --git a/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h
index 60490f2664345..18ecdf4e73d99 100644
--- a/lib/Support/Windows/WindowsSupport.h
+++ b/lib/Support/Windows/WindowsSupport.h
@@ -45,7 +45,6 @@
#include <wincrypt.h>
#include <cassert>
#include <string>
-#include <vector>
/// 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
@@ -69,15 +68,15 @@ inline bool RunningWindows8OrGreater() {
Mask) != FALSE;
}
-inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) {
+inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
if (!ErrMsg)
return true;
char *buffer = NULL;
DWORD LastError = GetLastError();
- DWORD R = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL, LastError, 0, (LPSTR)&buffer, 1, NULL);
+ 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
@@ -168,6 +167,22 @@ struct CryptContextTraits : CommonHandleTraits {
}
};
+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);
@@ -179,6 +194,7 @@ 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;