brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.0 KiB · bacbb76 Raw
865 lines · plain
1//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the Win32 specific implementation of the Signals class.10//11//===----------------------------------------------------------------------===//12#include "llvm/Config/llvm-config.h"13#include "llvm/Support/ConvertUTF.h"14#include "llvm/Support/ExitCodes.h"15#include "llvm/Support/FileSystem.h"16#include "llvm/Support/Path.h"17#include "llvm/Support/Process.h"18#include "llvm/Support/WindowsError.h"19#include <io.h>20#include <signal.h>21#include <stdio.h>22 23#include "llvm/Support/Format.h"24#include "llvm/Support/raw_ostream.h"25 26// The Windows.h header must be after LLVM and standard headers.27#include "llvm/Support/Windows/WindowsSupport.h"28 29#ifdef __MINGW32__30#include <imagehlp.h>31#else32#include <crtdbg.h>33#include <dbghelp.h>34#endif35#include <psapi.h>36 37#ifdef _MSC_VER38#pragma comment(lib, "psapi.lib")39#elif __MINGW32__40// The version of g++ that comes with MinGW does *not* properly understand41// the ll format specifier for printf. However, MinGW passes the format42// specifiers on to the MSVCRT entirely, and the CRT understands the ll43// specifier. So these warnings are spurious in this case. Since we compile44// with -Wall, this will generate these warnings which should be ignored. So45// we will turn off the warnings for this just file. However, MinGW also does46// not support push and pop for diagnostics, so we have to manually turn it47// back on at the end of the file.48#pragma GCC diagnostic ignored "-Wformat"49#pragma GCC diagnostic ignored "-Wformat-extra-args"50#endif // __MINGW32__51 52typedef BOOL(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(53    HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,54    LPDWORD lpNumberOfBytesRead);55 56typedef PVOID(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess,57                                                           DWORD64 AddrBase);58 59typedef DWORD64(__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,60                                                       DWORD64 Address);61 62typedef DWORD64(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,63                                                         HANDLE hThread,64                                                         LPADDRESS64 lpaddr);65 66typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,67                                          PMINIDUMP_EXCEPTION_INFORMATION,68                                          PMINIDUMP_USER_STREAM_INFORMATION,69                                          PMINIDUMP_CALLBACK_INFORMATION);70static fpMiniDumpWriteDump fMiniDumpWriteDump;71 72typedef BOOL(WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,73                                    PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,74                                    PFUNCTION_TABLE_ACCESS_ROUTINE64,75                                    PGET_MODULE_BASE_ROUTINE64,76                                    PTRANSLATE_ADDRESS_ROUTINE64);77static fpStackWalk64 fStackWalk64;78 79typedef DWORD64(WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);80static fpSymGetModuleBase64 fSymGetModuleBase64;81 82typedef BOOL(WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64,83                                            PIMAGEHLP_SYMBOL64);84static fpSymGetSymFromAddr64 fSymGetSymFromAddr64;85 86typedef BOOL(WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD,87                                             PIMAGEHLP_LINE64);88static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;89 90typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,91                                           PIMAGEHLP_MODULE64 ModuleInfo);92static fpSymGetModuleInfo64 fSymGetModuleInfo64;93 94typedef PVOID(WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);95static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;96 97typedef DWORD(WINAPI *fpSymSetOptions)(DWORD);98static fpSymSetOptions fSymSetOptions;99 100typedef BOOL(WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);101static fpSymInitialize fSymInitialize;102 103typedef BOOL(WINAPI *fpEnumerateLoadedModules)(HANDLE,104                                               PENUMLOADED_MODULES_CALLBACK64,105                                               PVOID);106static fpEnumerateLoadedModules fEnumerateLoadedModules;107 108static bool isDebugHelpInitialized() {109  return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;110}111 112static bool load64BitDebugHelp(void) {113  HMODULE hLib =114      ::LoadLibraryExA("Dbghelp.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);115  if (hLib) {116    fMiniDumpWriteDump = (fpMiniDumpWriteDump)(void *)::GetProcAddress(117        hLib, "MiniDumpWriteDump");118    fStackWalk64 = (fpStackWalk64)(void *)::GetProcAddress(hLib, "StackWalk64");119    fSymGetModuleBase64 = (fpSymGetModuleBase64)(void *)::GetProcAddress(120        hLib, "SymGetModuleBase64");121    fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)(void *)::GetProcAddress(122        hLib, "SymGetSymFromAddr64");123    fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)(void *)::GetProcAddress(124        hLib, "SymGetLineFromAddr64");125    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)(void *)::GetProcAddress(126        hLib, "SymGetModuleInfo64");127    fSymFunctionTableAccess64 =128        (fpSymFunctionTableAccess64)(void *)::GetProcAddress(129            hLib, "SymFunctionTableAccess64");130    fSymSetOptions =131        (fpSymSetOptions)(void *)::GetProcAddress(hLib, "SymSetOptions");132    fSymInitialize =133        (fpSymInitialize)(void *)::GetProcAddress(hLib, "SymInitialize");134    fEnumerateLoadedModules =135        (fpEnumerateLoadedModules)(void *)::GetProcAddress(136            hLib, "EnumerateLoadedModules64");137  }138  return isDebugHelpInitialized();139}140 141using namespace llvm;142 143// Forward declare.144static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);145static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);146 147// The function to call if ctrl-c is pressed.148static void (*InterruptFunction)() = 0;149 150static std::vector<std::string> *FilesToRemove = NULL;151static bool RegisteredUnhandledExceptionFilter = false;152static bool CleanupExecuted = false;153static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;154 155/// The function to call on "SIGPIPE" (one-time use only).156static std::atomic<void (*)()> OneShotPipeSignalFunction(nullptr);157 158// Windows creates a new thread to execute the console handler when an event159// (such as CTRL/C) occurs.  This causes concurrency issues with the above160// globals which this critical section addresses.161static CRITICAL_SECTION CriticalSection;162static bool CriticalSectionInitialized = false;163 164static StringRef Argv0;165 166enum {167#if defined(_M_X64)168  NativeMachineType = IMAGE_FILE_MACHINE_AMD64169#elif defined(_M_ARM64)170  NativeMachineType = IMAGE_FILE_MACHINE_ARM64171#elif defined(_M_IX86)172  NativeMachineType = IMAGE_FILE_MACHINE_I386173#elif defined(_M_ARM)174  NativeMachineType = IMAGE_FILE_MACHINE_ARMNT175#else176  NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN177#endif178};179 180static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,181                                              HANDLE hProcess, HANDLE hThread,182                                              STACKFRAME64 &StackFrameOrig,183                                              CONTEXT *ContextOrig) {184  // StackWalk64 modifies the incoming stack frame and context, so copy them.185  STACKFRAME64 StackFrame = StackFrameOrig;186 187  // Copy the register context so that we don't modify it while we unwind. We188  // could use InitializeContext + CopyContext, but that's only required to get189  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the190  // flag set to indicate that there's less data.191  CONTEXT Context = *ContextOrig;192  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;193 194  static void *StackTrace[256];195  size_t Depth = 0;196  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,197                      &Context, 0, fSymFunctionTableAccess64,198                      fSymGetModuleBase64, 0)) {199    if (StackFrame.AddrFrame.Offset == 0)200      break;201    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;202    if (Depth >= std::size(StackTrace))203      break;204  }205 206  return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);207}208 209namespace {210struct FindModuleData {211  void **StackTrace;212  int Depth;213  const char **Modules;214  intptr_t *Offsets;215  StringSaver *StrPool;216};217} // namespace218 219static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, DWORD64 ModuleBase,220                                        ULONG ModuleSize, void *VoidData) {221  FindModuleData *Data = (FindModuleData *)VoidData;222  intptr_t Beg = ModuleBase;223  intptr_t End = Beg + ModuleSize;224  for (int I = 0; I < Data->Depth; I++) {225    if (Data->Modules[I])226      continue;227    intptr_t Addr = (intptr_t)Data->StackTrace[I];228    if (Beg <= Addr && Addr < End) {229      Data->Modules[I] = Data->StrPool->save(ModuleName).data();230      Data->Offsets[I] = Addr - Beg;231    }232  }233  return TRUE;234}235 236static bool findModulesAndOffsets(void **StackTrace, int Depth,237                                  const char **Modules, intptr_t *Offsets,238                                  const char *MainExecutableName,239                                  StringSaver &StrPool) {240  if (!fEnumerateLoadedModules)241    return false;242  FindModuleData Data;243  Data.StackTrace = StackTrace;244  Data.Depth = Depth;245  Data.Modules = Modules;246  Data.Offsets = Offsets;247  Data.StrPool = &StrPool;248  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);249  return true;250}251 252static bool printMarkupContext(llvm::raw_ostream &OS,253                               const char *MainExecutableName) {254  return false;255}256 257static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,258                                     HANDLE hThread, STACKFRAME64 &StackFrame,259                                     CONTEXT *Context) {260  // It's possible that DbgHelp.dll hasn't been loaded yet (e.g. if this261  // function is called before the main program called `llvm::InitLLVM`).262  // In this case just return, not stacktrace will be printed.263  if (!isDebugHelpInitialized())264    return;265 266  // Initialize the symbol handler.267  fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);268  fSymInitialize(hProcess, NULL, TRUE);269 270  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs271  // and DWARF, so it should do a good job regardless of what debug info or272  // linker is in use.273  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,274                                        Context)) {275    return;276  }277 278  while (true) {279    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,280                      Context, 0, fSymFunctionTableAccess64,281                      fSymGetModuleBase64, 0)) {282      break;283    }284 285    if (StackFrame.AddrFrame.Offset == 0)286      break;287 288    using namespace llvm;289    // Print the PC in hexadecimal.290    DWORD64 PC = StackFrame.AddrPC.Offset;291#if defined(_M_X64) || defined(_M_ARM64)292    OS << format("0x%016llX", PC);293#elif defined(_M_IX86) || defined(_M_ARM)294    OS << format("0x%08lX", static_cast<DWORD>(PC));295#endif296 297    // Verify the PC belongs to a module in this process.298    if (!fSymGetModuleBase64(hProcess, PC)) {299      OS << " <unknown module>\n";300      continue;301    }302 303    IMAGEHLP_MODULE64 M;304    memset(&M, 0, sizeof(IMAGEHLP_MODULE64));305    M.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);306    if (fSymGetModuleInfo64(hProcess, fSymGetModuleBase64(hProcess, PC), &M)) {307      DWORD64 const disp = PC - M.BaseOfImage;308      OS << format(", %s(0x%016llX) + 0x%llX byte(s)",309                   static_cast<char *>(M.ImageName), M.BaseOfImage,310                   static_cast<long long>(disp));311    } else {312      OS << ", <unknown module>";313    }314 315    // Print the symbol name.316    char buffer[512];317    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);318    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));319    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);320    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);321 322    DWORD64 dwDisp;323    if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {324      OS << '\n';325      continue;326    }327 328    buffer[511] = 0;329    OS << format(", %s() + 0x%llX byte(s)", static_cast<char *>(symbol->Name),330                 static_cast<long long>(dwDisp));331 332    // Print the source file and line number information.333    IMAGEHLP_LINE64 line = {};334    DWORD dwLineDisp;335    line.SizeOfStruct = sizeof(line);336    if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {337      OS << format(", %s, line %lu + 0x%lX byte(s)", line.FileName,338                   line.LineNumber, dwLineDisp);339    }340 341    OS << '\n';342  }343}344 345namespace llvm {346 347//===----------------------------------------------------------------------===//348//=== WARNING: Implementation here must contain only Win32 specific code349//===          and must not be UNIX code350//===----------------------------------------------------------------------===//351 352#ifdef _MSC_VER353/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report354/// dialog. "retry" raises an exception which ultimately triggers our stack355/// dumper.356[[maybe_unused]] static int AvoidMessageBoxHook(int ReportType, char *Message,357                                                int *Return) {358  // Set *Return to the retry code for the return value of _CrtDbgReport:359  // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx360  // This may also trigger just-in-time debugging via DebugBreak().361  if (Return)362    *Return = 1;363  // Don't call _CrtDbgReport.364  return TRUE;365}366 367#endif368 369extern "C" void HandleAbort(int Sig) {370  if (Sig == SIGABRT) {371    LLVM_BUILTIN_TRAP;372  }373}374 375static void InitializeThreading() {376  if (CriticalSectionInitialized)377    return;378 379  // Now's the time to create the critical section. This is the first time380  // through here, and there's only one thread.381  InitializeCriticalSection(&CriticalSection);382  CriticalSectionInitialized = true;383}384 385static void RegisterHandler() {386  // If we cannot load up the APIs (which would be unexpected as they should387  // exist on every version of Windows we support), we will bail out since388  // there would be nothing to report.389  if (!load64BitDebugHelp()) {390    assert(false && "These APIs should always be available");391    return;392  }393 394  if (RegisteredUnhandledExceptionFilter) {395    EnterCriticalSection(&CriticalSection);396    return;397  }398 399  InitializeThreading();400 401  // Enter it immediately.  Now if someone hits CTRL/C, the console handler402  // can't proceed until the globals are updated.403  EnterCriticalSection(&CriticalSection);404 405  RegisteredUnhandledExceptionFilter = true;406  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);407  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);408 409  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or410  // else multi-threading problems will ensue.411}412 413// The public API414bool sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) {415  RegisterHandler();416 417  if (CleanupExecuted) {418    if (ErrMsg)419      *ErrMsg = "Process terminating -- cannot register for removal";420    return true;421  }422 423  if (FilesToRemove == NULL) {424    FilesToRemove = new std::vector<std::string>;425    std::atexit([]() {426      delete FilesToRemove;427      FilesToRemove = NULL;428    });429  }430 431  FilesToRemove->push_back(std::string(Filename));432 433  LeaveCriticalSection(&CriticalSection);434  return false;435}436 437// The public API438void sys::DontRemoveFileOnSignal(StringRef Filename) {439  if (FilesToRemove == NULL)440    return;441 442  RegisterHandler();443 444  std::vector<std::string>::reverse_iterator I =445      find(reverse(*FilesToRemove), Filename);446  if (I != FilesToRemove->rend())447    FilesToRemove->erase(I.base() - 1);448 449  LeaveCriticalSection(&CriticalSection);450}451 452void sys::DisableSystemDialogsOnCrash() {453  // Crash to stack trace handler on abort.454  signal(SIGABRT, HandleAbort);455 456  // The following functions are not reliably accessible on MinGW.457#ifdef _MSC_VER458  // We're already handling writing a "something went wrong" message.459  _set_abort_behavior(0, _WRITE_ABORT_MSG);460  // Disable Dr. Watson.461  _set_abort_behavior(0, _CALL_REPORTFAULT);462  _CrtSetReportHook(AvoidMessageBoxHook);463#endif464 465  // Disable standard error dialog box.466  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |467               SEM_NOOPENFILEERRORBOX);468  _set_error_mode(_OUT_TO_STDERR);469}470 471/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the472/// process, print a stack trace and then exit.473void sys::PrintStackTraceOnErrorSignal(StringRef Argv0,474                                       bool DisableCrashReporting) {475  ::Argv0 = Argv0;476 477  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))478    Process::PreventCoreFiles();479 480  DisableSystemDialogsOnCrash();481  RegisterHandler();482  LeaveCriticalSection(&CriticalSection);483}484} // namespace llvm485 486#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN487#error DebugLoc origin-tracking currently unimplemented for Windows.488#endif489 490static void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) {491  STACKFRAME64 StackFrame{};492  CONTEXT Context{};493  if (!C) {494    ::RtlCaptureContext(&Context);495    C = &Context;496  }497#if defined(_M_X64)498  StackFrame.AddrPC.Offset = Context.Rip;499  StackFrame.AddrStack.Offset = Context.Rsp;500  StackFrame.AddrFrame.Offset = Context.Rbp;501#elif defined(_M_IX86)502  StackFrame.AddrPC.Offset = Context.Eip;503  StackFrame.AddrStack.Offset = Context.Esp;504  StackFrame.AddrFrame.Offset = Context.Ebp;505#elif defined(_M_ARM64)506  StackFrame.AddrPC.Offset = Context.Pc;507  StackFrame.AddrStack.Offset = Context.Sp;508  StackFrame.AddrFrame.Offset = Context.Fp;509#elif defined(_M_ARM)510  StackFrame.AddrPC.Offset = Context.Pc;511  StackFrame.AddrStack.Offset = Context.Sp;512  StackFrame.AddrFrame.Offset = Context.R11;513#endif514  StackFrame.AddrPC.Mode = AddrModeFlat;515  StackFrame.AddrStack.Mode = AddrModeFlat;516  StackFrame.AddrFrame.Mode = AddrModeFlat;517  PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),518                           StackFrame, C);519}520 521void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {522  // FIXME: Handle "Depth" parameter to print stack trace upto specified Depth523  LocalPrintStackTrace(OS, nullptr);524}525 526void llvm::sys::SetInterruptFunction(void (*IF)()) {527  RegisterHandler();528  InterruptFunction = IF;529  LeaveCriticalSection(&CriticalSection);530}531 532void llvm::sys::SetInfoSignalFunction(void (*Handler)()) {533  // Unimplemented.534}535 536void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) {537  OneShotPipeSignalFunction.exchange(Handler);538}539 540void llvm::sys::DefaultOneShotPipeSignalHandler() {541  llvm::sys::Process::Exit(EX_IOERR, /*NoCleanup=*/true);542}543 544void llvm::sys::CallOneShotPipeSignalHandler() {545  if (auto OldOneShotPipeFunction = OneShotPipeSignalFunction.exchange(nullptr))546    OldOneShotPipeFunction();547}548 549/// Add a function to be called when a signal is delivered to the process. The550/// handler can have a cookie passed to it to identify what instance of the551/// handler it is.552void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,553                                 void *Cookie) {554  insertSignalHandler(FnPtr, Cookie);555  RegisterHandler();556  LeaveCriticalSection(&CriticalSection);557}558 559static void Cleanup(bool ExecuteSignalHandlers) {560  if (CleanupExecuted)561    return;562 563  EnterCriticalSection(&CriticalSection);564 565  // Prevent other thread from registering new files and directories for566  // removal, should we be executing because of the console handler callback.567  CleanupExecuted = true;568 569  // FIXME: open files cannot be deleted.570  if (FilesToRemove != NULL)571    while (!FilesToRemove->empty()) {572      llvm::sys::fs::remove(FilesToRemove->back());573      FilesToRemove->pop_back();574    }575 576  if (ExecuteSignalHandlers)577    llvm::sys::RunSignalHandlers();578 579  LeaveCriticalSection(&CriticalSection);580}581 582void llvm::sys::RunInterruptHandlers() {583  // The interrupt handler may be called from an interrupt, but it may also be584  // called manually (such as the case of report_fatal_error with no registered585  // error handler). We must ensure that the critical section is properly586  // initialized.587  InitializeThreading();588  Cleanup(true);589}590 591/// Find the Windows Registry Key for a given location.592///593/// \returns a valid HKEY if the location exists, else NULL.594static HKEY FindWERKey(const llvm::Twine &RegistryLocation) {595  HKEY Key;596  if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,597                                       RegistryLocation.str().c_str(), 0,598                                       KEY_QUERY_VALUE | KEY_READ, &Key))599    return NULL;600 601  return Key;602}603 604/// Populate ResultDirectory with the value for "DumpFolder" for a given605/// Windows Registry key.606///607/// \returns true if a valid value for DumpFolder exists, false otherwise.608static bool GetDumpFolder(HKEY Key,609                          llvm::SmallVectorImpl<char> &ResultDirectory) {610  using llvm::sys::windows::UTF16ToUTF8;611 612  if (!Key)613    return false;614 615  DWORD BufferLengthBytes = 0;616 617  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,618                                      NULL, NULL, &BufferLengthBytes))619    return false;620 621  SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);622 623  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,624                                      NULL, Buffer.data(), &BufferLengthBytes))625    return false;626 627  DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);628 629  if (!ExpandBufferSize)630    return false;631 632  SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);633 634  if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),635                                                      ExpandBuffer.data(),636                                                      ExpandBufferSize))637    return false;638 639  if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))640    return false;641 642  return true;643}644 645/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of646/// "DumpType" for a given Windows Registry key.647///648/// According to649/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx650/// valid values for DumpType are:651///   * 0: Custom dump652///   * 1: Mini dump653///   * 2: Full dump654/// If "Custom dump" is specified then the "CustomDumpFlags" field is read655/// containing a bitwise combination of MINIDUMP_TYPE values.656///657/// \returns true if a valid value for ResultType can be set, false otherwise.658static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {659  if (!Key)660    return false;661 662  DWORD DumpType;663  DWORD TypeSize = sizeof(DumpType);664  if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,665                                      NULL, &DumpType, &TypeSize))666    return false;667 668  switch (DumpType) {669  case 0: {670    DWORD Flags = 0;671    if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",672                                        RRF_RT_REG_DWORD, NULL, &Flags,673                                        &TypeSize))674      return false;675 676    ResultType = static_cast<MINIDUMP_TYPE>(Flags);677    break;678  }679  case 1:680    ResultType = MiniDumpNormal;681    break;682  case 2:683    ResultType = MiniDumpWithFullMemory;684    break;685  default:686    return false;687  }688  return true;689}690 691/// Write a Windows dump file containing process information that can be692/// used for post-mortem debugging.693///694/// \returns zero error code if a mini dump created, actual error code695/// otherwise.696static std::error_code WINAPI697WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {698  struct ScopedCriticalSection {699    ScopedCriticalSection() { EnterCriticalSection(&CriticalSection); }700    ~ScopedCriticalSection() { LeaveCriticalSection(&CriticalSection); }701  } SCS;702 703  using namespace llvm;704  using namespace llvm::sys;705 706  std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);707  StringRef ProgramName;708 709  if (MainExecutableName.empty()) {710    // If we can't get the executable filename,711    // things are in worse shape than we realize712    // and we should just bail out.713    return mapWindowsError(::GetLastError());714  }715 716  ProgramName = path::filename(MainExecutableName.c_str());717 718  // The Windows Registry location as specified at719  // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx720  // "Collecting User-Mode Dumps" that may optionally be set to collect crash721  // dumps in a specified location.722  StringRef LocalDumpsRegistryLocation =723      "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";724 725  // The key pointing to the Registry location that may contain global crash726  // dump settings.  This will be NULL if the location can not be found.727  ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));728 729  // The key pointing to the Registry location that may contain730  // application-specific crash dump settings.  This will be NULL if the731  // location can not be found.732  ScopedRegHandle AppSpecificKey(733      FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));734 735  // Look to see if a dump type is specified in the registry; first with the736  // app-specific key and failing that with the global key.  If none are found737  // default to a normal dump (GetDumpType will return false either if the key738  // is NULL or if there is no valid DumpType value at its location).739  MINIDUMP_TYPE DumpType;740  if (!GetDumpType(AppSpecificKey, DumpType))741    if (!GetDumpType(DefaultLocalDumpsKey, DumpType))742      DumpType = MiniDumpNormal;743 744  // Look to see if a dump location is specified on the command line.  If not,745  // look to see if a dump location is specified in the registry; first with the746  // app-specific key and failing that with the global key.  If none are found747  // we'll just create the dump file in the default temporary file location748  // (GetDumpFolder will return false either if the key is NULL or if there is749  // no valid DumpFolder value at its location).750  bool ExplicitDumpDirectorySet = true;751  SmallString<MAX_PATH> DumpDirectory(*CrashDiagnosticsDirectory);752  if (DumpDirectory.empty())753    if (!GetDumpFolder(AppSpecificKey, DumpDirectory))754      if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))755        ExplicitDumpDirectorySet = false;756 757  int FD;758  SmallString<MAX_PATH> DumpPath;759 760  if (ExplicitDumpDirectorySet) {761    if (std::error_code EC = fs::create_directories(DumpDirectory))762      return EC;763    if (std::error_code EC = fs::createUniqueFile(764            Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,765            DumpPath))766      return EC;767  } else if (std::error_code EC =768                 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))769    return EC;770 771  // Our support functions return a file descriptor but Windows wants a handle.772  ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));773 774  if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),775                          FileHandle, DumpType, ExceptionInfo, NULL, NULL))776    return mapWindowsError(::GetLastError());777 778  llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";779  return std::error_code();780}781 782void sys::CleanupOnSignal(uintptr_t Context) {783  LPEXCEPTION_POINTERS EP = (LPEXCEPTION_POINTERS)Context;784  // Broken pipe is not a crash.785  //786  // 0xE0000000 is combined with the return code in the exception raised in787  // CrashRecoveryContext::HandleExit().788  unsigned RetCode = EP->ExceptionRecord->ExceptionCode;789  if (RetCode == (0xE0000000 | EX_IOERR))790    return;791  LLVMUnhandledExceptionFilter(EP);792}793 794static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {795  Cleanup(true);796 797  // Write out the exception code.798  if (ep && ep->ExceptionRecord)799    llvm::errs() << format("Exception Code: 0x%08X",800                           ep->ExceptionRecord->ExceptionCode)801                 << "\n";802 803  // We'll automatically write a Minidump file here to help diagnose804  // the nasty sorts of crashes that aren't 100% reproducible from a set of805  // inputs (or in the event that the user is unable or unwilling to provide a806  // reproducible case).807  if (!llvm::sys::Process::AreCoreFilesPrevented()) {808    MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;809    ExceptionInfo.ThreadId = ::GetCurrentThreadId();810    ExceptionInfo.ExceptionPointers = ep;811    ExceptionInfo.ClientPointers = FALSE;812 813    if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))814      llvm::errs() << "Could not write crash dump file: " << EC.message()815                   << "\n";816  }817 818  // Stack unwinding appears to modify the context. Copy it to preserve the819  // caller's context.820  CONTEXT ContextCopy;821  if (ep)822    memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy));823 824  LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr);825 826  return EXCEPTION_EXECUTE_HANDLER;827}828 829static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {830  // We are running in our very own thread, courtesy of Windows.831  EnterCriticalSection(&CriticalSection);832  // This function is only ever called when a CTRL-C or similar control signal833  // is fired. Killing a process in this way is normal, so don't trigger the834  // signal handlers.835  Cleanup(false);836 837  // If an interrupt function has been set, go and run one it; otherwise,838  // the process dies.839  void (*IF)() = InterruptFunction;840  InterruptFunction = 0; // Don't run it on another CTRL-C.841 842  if (IF) {843    // Note: if the interrupt function throws an exception, there is nothing844    // to catch it in this thread so it will kill the process.845    IF(); // Run it now.846    LeaveCriticalSection(&CriticalSection);847    return TRUE; // Don't kill the process.848  }849 850  // Allow normal processing to take place; i.e., the process dies.851  LeaveCriticalSection(&CriticalSection);852  return FALSE;853}854 855#if __MINGW32__856// We turned these warnings off for this file so that MinGW-g++ doesn't857// complain about the ll format specifiers used.  Now we are turning the858// warnings back on.  If MinGW starts to support diagnostic stacks, we can859// replace this with a pop.860#pragma GCC diagnostic warning "-Wformat"861#pragma GCC diagnostic warning "-Wformat-extra-args"862#endif863 864void sys::unregisterHandlers() {}865