1155408Srwatson//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 2155408Srwatson// 3155408Srwatson// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4155408Srwatson// See https://llvm.org/LICENSE.txt for license information. 5155408Srwatson// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6155408Srwatson// 7155408Srwatson//===----------------------------------------------------------------------===// 8155408Srwatson// 9155408Srwatson// This file provides the Win32 specific implementation of the Signals class. 10155408Srwatson// 11155408Srwatson//===----------------------------------------------------------------------===// 12155408Srwatson#include "llvm/Support/ConvertUTF.h" 13155408Srwatson#include "llvm/Support/ExitCodes.h" 14155408Srwatson#include "llvm/Support/FileSystem.h" 15155408Srwatson#include "llvm/Support/Path.h" 16155408Srwatson#include "llvm/Support/Process.h" 17155408Srwatson#include "llvm/Support/WindowsError.h" 18155408Srwatson#include <algorithm> 19155408Srwatson#include <io.h> 20155408Srwatson#include <signal.h> 21155408Srwatson#include <stdio.h> 22155408Srwatson 23155408Srwatson#include "llvm/Support/Format.h" 24155408Srwatson#include "llvm/Support/raw_ostream.h" 25155408Srwatson 26155408Srwatson// The Windows.h header must be after LLVM and standard headers. 27155408Srwatson#include "llvm/Support/Windows/WindowsSupport.h" 28155408Srwatson 29155408Srwatson#ifdef __MINGW32__ 30155408Srwatson#include <imagehlp.h> 31155408Srwatson#else 32155408Srwatson#include <crtdbg.h> 33155408Srwatson#include <dbghelp.h> 34155408Srwatson#endif 35155408Srwatson#include <psapi.h> 36155408Srwatson 37155408Srwatson#ifdef _MSC_VER 38155408Srwatson#pragma comment(lib, "psapi.lib") 39155408Srwatson#elif __MINGW32__ 40155408Srwatson// The version of g++ that comes with MinGW does *not* properly understand 41155408Srwatson// the ll format specifier for printf. However, MinGW passes the format 42155408Srwatson// specifiers on to the MSVCRT entirely, and the CRT understands the ll 43155408Srwatson// specifier. So these warnings are spurious in this case. Since we compile 44155408Srwatson// with -Wall, this will generate these warnings which should be ignored. So 45155408Srwatson// we will turn off the warnings for this just file. However, MinGW also does 46155408Srwatson// not support push and pop for diagnostics, so we have to manually turn it 47155408Srwatson// back on at the end of the file. 48155408Srwatson#pragma GCC diagnostic ignored "-Wformat" 49155408Srwatson#pragma GCC diagnostic ignored "-Wformat-extra-args" 50155408Srwatson 51156880Srwatson#if !defined(__MINGW64_VERSION_MAJOR) 52155408Srwatson// MinGW.org does not have updated support for the 64-bit versions of the 53155408Srwatson// DebugHlp APIs. So we will have to load them manually. The structures and 54155408Srwatson// method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 55155408Srwatson// and adjusted for brevity. 56155408Srwatsontypedef struct _IMAGEHLP_LINE64 { 57155408Srwatson DWORD SizeOfStruct; 58159269Srwatson PVOID Key; 59159269Srwatson DWORD LineNumber; 60155408Srwatson PCHAR FileName; 61155408Srwatson DWORD64 Address; 62155408Srwatson} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 63155408Srwatson 64155408Srwatsontypedef struct _IMAGEHLP_SYMBOL64 { 65155408Srwatson DWORD SizeOfStruct; 66155408Srwatson DWORD64 Address; 67155408Srwatson DWORD Size; 68159269Srwatson DWORD Flags; 69159269Srwatson DWORD MaxNameLength; 70155408Srwatson CHAR Name[1]; 71155408Srwatson} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 72155408Srwatson 73155408Srwatsontypedef struct _tagADDRESS64 { 74156883Srwatson DWORD64 Offset; 75156880Srwatson WORD Segment; 76155408Srwatson ADDRESS_MODE Mode; 77155408Srwatson} ADDRESS64, *LPADDRESS64; 78155408Srwatson 79155408Srwatsontypedef struct _KDHELP64 { 80155408Srwatson DWORD64 Thread; 81155408Srwatson DWORD ThCallbackStack; 82155408Srwatson DWORD ThCallbackBStore; 83155408Srwatson DWORD NextCallback; 84155408Srwatson DWORD FramePointer; 85155408Srwatson DWORD64 KiCallUserMode; 86155408Srwatson DWORD64 KeUserCallbackDispatcher; 87155408Srwatson DWORD64 SystemRangeStart; 88159269Srwatson DWORD64 KiUserExceptionDispatcher; 89159269Srwatson DWORD64 StackBase; 90159269Srwatson DWORD64 StackLimit; 91159269Srwatson DWORD64 Reserved[5]; 92159269Srwatson} KDHELP64, *PKDHELP64; 93159269Srwatson 94159269Srwatsontypedef struct _tagSTACKFRAME64 { 95159269Srwatson ADDRESS64 AddrPC; 96159269Srwatson ADDRESS64 AddrReturn; 97159269Srwatson ADDRESS64 AddrFrame; 98159269Srwatson ADDRESS64 AddrStack; 99159269Srwatson ADDRESS64 AddrBStore; 100159269Srwatson PVOID FuncTableEntry; 101159269Srwatson DWORD64 Params[4]; 102159269Srwatson BOOL Far; 103159269Srwatson BOOL Virtual; 104159269Srwatson DWORD64 Reserved[3]; 105155408Srwatson KDHELP64 KdHelp; 106155408Srwatson} STACKFRAME64, *LPSTACKFRAME64; 107155408Srwatson#endif // !defined(__MINGW64_VERSION_MAJOR) 108155408Srwatson#endif // __MINGW32__ 109155408Srwatson 110155408Srwatsontypedef BOOL(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( 111155408Srwatson HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 112155408Srwatson LPDWORD lpNumberOfBytesRead); 113155408Srwatson 114155408Srwatsontypedef PVOID(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, 115155408Srwatson DWORD64 AddrBase); 116155408Srwatson 117155408Srwatsontypedef DWORD64(__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 118155408Srwatson DWORD64 Address); 119155408Srwatson 120155408Srwatsontypedef DWORD64(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 121155408Srwatson HANDLE hThread, 122155408Srwatson LPADDRESS64 lpaddr); 123155408Srwatson 124155408Srwatsontypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, 125159269Srwatson PMINIDUMP_EXCEPTION_INFORMATION, 126159269Srwatson PMINIDUMP_USER_STREAM_INFORMATION, 127159269Srwatson PMINIDUMP_CALLBACK_INFORMATION); 128159269Srwatsonstatic fpMiniDumpWriteDump fMiniDumpWriteDump; 129159269Srwatson 130159269Srwatsontypedef BOOL(WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 131159269Srwatson PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 132159269Srwatson PFUNCTION_TABLE_ACCESS_ROUTINE64, 133159269Srwatson PGET_MODULE_BASE_ROUTINE64, 134159269Srwatson PTRANSLATE_ADDRESS_ROUTINE64); 135159269Srwatsonstatic fpStackWalk64 fStackWalk64; 136159269Srwatson 137159269Srwatsontypedef DWORD64(WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 138155408Srwatsonstatic fpSymGetModuleBase64 fSymGetModuleBase64; 139155408Srwatson 140159269Srwatsontypedef BOOL(WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, 141159269Srwatson PIMAGEHLP_SYMBOL64); 142159269Srwatsonstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64; 143155408Srwatson 144155408Srwatsontypedef BOOL(WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, 145155408Srwatson PIMAGEHLP_LINE64); 146155408Srwatsonstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64; 147159269Srwatson 148155408Srwatsontypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, 149155408Srwatson PIMAGEHLP_MODULE64 ModuleInfo); 150155408Srwatsonstatic fpSymGetModuleInfo64 fSymGetModuleInfo64; 151155408Srwatson 152155408Srwatsontypedef PVOID(WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 153155408Srwatsonstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64; 154159269Srwatson 155159269Srwatsontypedef DWORD(WINAPI *fpSymSetOptions)(DWORD); 156159269Srwatsonstatic fpSymSetOptions fSymSetOptions; 157155408Srwatson 158155408Srwatsontypedef BOOL(WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); 159155408Srwatsonstatic fpSymInitialize fSymInitialize; 160155408Srwatson 161155408Srwatsontypedef BOOL(WINAPI *fpEnumerateLoadedModules)(HANDLE, 162155408Srwatson PENUMLOADED_MODULES_CALLBACK64, 163155408Srwatson PVOID); 164155408Srwatsonstatic fpEnumerateLoadedModules fEnumerateLoadedModules; 165155408Srwatson 166155408Srwatsonstatic bool isDebugHelpInitialized() { 167155408Srwatson return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; 168155408Srwatson} 169155408Srwatson 170155408Srwatsonstatic bool load64BitDebugHelp(void) { 171155408Srwatson HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 172155408Srwatson if (hLib) { 173155408Srwatson fMiniDumpWriteDump = 174155408Srwatson (fpMiniDumpWriteDump)::GetProcAddress(hLib, "MiniDumpWriteDump"); 175161582Srwatson fStackWalk64 = (fpStackWalk64)::GetProcAddress(hLib, "StackWalk64"); 176155408Srwatson fSymGetModuleBase64 = 177155408Srwatson (fpSymGetModuleBase64)::GetProcAddress(hLib, "SymGetModuleBase64"); 178155408Srwatson fSymGetSymFromAddr64 = 179159269Srwatson (fpSymGetSymFromAddr64)::GetProcAddress(hLib, "SymGetSymFromAddr64"); 180155408Srwatson fSymGetLineFromAddr64 = 181155408Srwatson (fpSymGetLineFromAddr64)::GetProcAddress(hLib, "SymGetLineFromAddr64"); 182155408Srwatson fSymGetModuleInfo64 = 183155408Srwatson (fpSymGetModuleInfo64)::GetProcAddress(hLib, "SymGetModuleInfo64"); 184155408Srwatson fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)::GetProcAddress( 185161582Srwatson hLib, "SymFunctionTableAccess64"); 186155408Srwatson fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); 187155408Srwatson fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); 188155408Srwatson fEnumerateLoadedModules = (fpEnumerateLoadedModules)::GetProcAddress( 189161582Srwatson hLib, "EnumerateLoadedModules64"); 190161582Srwatson } 191161582Srwatson return isDebugHelpInitialized(); 192161582Srwatson} 193161582Srwatson 194161582Srwatsonusing namespace llvm; 195161582Srwatson 196161582Srwatson// Forward declare. 197161582Srwatsonstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 198161582Srwatsonstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 199155408Srwatson 200155408Srwatson// The function to call if ctrl-c is pressed. 201155408Srwatsonstatic void (*InterruptFunction)() = 0; 202155408Srwatson 203155408Srwatsonstatic std::vector<std::string> *FilesToRemove = NULL; 204155408Srwatsonstatic bool RegisteredUnhandledExceptionFilter = false; 205155408Srwatsonstatic bool CleanupExecuted = false; 206155408Srwatsonstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 207155408Srwatson 208155408Srwatson/// The function to call on "SIGPIPE" (one-time use only). 209155408Srwatsonstatic std::atomic<void (*)()> OneShotPipeSignalFunction(nullptr); 210155408Srwatson 211155408Srwatson// Windows creates a new thread to execute the console handler when an event 212155408Srwatson// (such as CTRL/C) occurs. This causes concurrency issues with the above 213155408Srwatson// globals which this critical section addresses. 214155408Srwatsonstatic CRITICAL_SECTION CriticalSection; 215155408Srwatsonstatic bool CriticalSectionInitialized = false; 216155408Srwatson 217155408Srwatsonstatic StringRef Argv0; 218155408Srwatson 219159269Srwatsonenum { 220159269Srwatson#if defined(_M_X64) 221159269Srwatson NativeMachineType = IMAGE_FILE_MACHINE_AMD64 222159269Srwatson#elif defined(_M_ARM64) 223159269Srwatson NativeMachineType = IMAGE_FILE_MACHINE_ARM64 224159269Srwatson#elif defined(_M_IX86) 225159269Srwatson NativeMachineType = IMAGE_FILE_MACHINE_I386 226159269Srwatson#elif defined(_M_ARM) 227159269Srwatson NativeMachineType = IMAGE_FILE_MACHINE_ARMNT 228159269Srwatson#else 229159269Srwatson NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN 230159269Srwatson#endif 231159269Srwatson}; 232159269Srwatson 233159269Srwatsonstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, 234159269Srwatson HANDLE hProcess, HANDLE hThread, 235159269Srwatson STACKFRAME64 &StackFrameOrig, 236159269Srwatson CONTEXT *ContextOrig) { 237159269Srwatson // StackWalk64 modifies the incoming stack frame and context, so copy them. 238159269Srwatson STACKFRAME64 StackFrame = StackFrameOrig; 239159269Srwatson 240159269Srwatson // Copy the register context so that we don't modify it while we unwind. We 241159269Srwatson // could use InitializeContext + CopyContext, but that's only required to get 242159269Srwatson // at AVX registers, which typically aren't needed by StackWalk64. Reduce the 243159269Srwatson // flag set to indicate that there's less data. 244159269Srwatson CONTEXT Context = *ContextOrig; 245159269Srwatson Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; 246159269Srwatson 247159269Srwatson static void *StackTrace[256]; 248159269Srwatson size_t Depth = 0; 249159269Srwatson while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 250159269Srwatson &Context, 0, fSymFunctionTableAccess64, 251159269Srwatson fSymGetModuleBase64, 0)) { 252159269Srwatson if (StackFrame.AddrFrame.Offset == 0) 253159269Srwatson break; 254159269Srwatson StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; 255159269Srwatson if (Depth >= std::size(StackTrace)) 256159269Srwatson break; 257159269Srwatson } 258159269Srwatson 259159269Srwatson return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); 260159269Srwatson} 261159269Srwatson 262159269Srwatsonnamespace { 263159269Srwatsonstruct FindModuleData { 264159269Srwatson void **StackTrace; 265159269Srwatson int Depth; 266159269Srwatson const char **Modules; 267159269Srwatson intptr_t *Offsets; 268159269Srwatson StringSaver *StrPool; 269159269Srwatson}; 270159269Srwatson} // namespace 271159269Srwatson 272159269Srwatsonstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName, DWORD64 ModuleBase, 273159269Srwatson ULONG ModuleSize, void *VoidData) { 274159269Srwatson FindModuleData *Data = (FindModuleData *)VoidData; 275159269Srwatson intptr_t Beg = ModuleBase; 276159269Srwatson intptr_t End = Beg + ModuleSize; 277159269Srwatson for (int I = 0; I < Data->Depth; I++) { 278159269Srwatson if (Data->Modules[I]) 279159269Srwatson continue; 280159269Srwatson intptr_t Addr = (intptr_t)Data->StackTrace[I]; 281159269Srwatson if (Beg <= Addr && Addr < End) { 282159269Srwatson Data->Modules[I] = Data->StrPool->save(ModuleName).data(); 283159269Srwatson Data->Offsets[I] = Addr - Beg; 284159269Srwatson } 285159269Srwatson } 286159269Srwatson return TRUE; 287159269Srwatson} 288159269Srwatson 289159269Srwatsonstatic bool findModulesAndOffsets(void **StackTrace, int Depth, 290159269Srwatson const char **Modules, intptr_t *Offsets, 291159269Srwatson const char *MainExecutableName, 292159269Srwatson StringSaver &StrPool) { 293159269Srwatson if (!fEnumerateLoadedModules) 294159269Srwatson return false; 295159269Srwatson FindModuleData Data; 296159269Srwatson Data.StackTrace = StackTrace; 297159269Srwatson Data.Depth = Depth; 298159269Srwatson Data.Modules = Modules; 299159269Srwatson Data.Offsets = Offsets; 300159269Srwatson Data.StrPool = &StrPool; 301159269Srwatson fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); 302159269Srwatson return true; 303159269Srwatson} 304159269Srwatson 305159269Srwatsonstatic bool printMarkupContext(llvm::raw_ostream &OS, 306159269Srwatson const char *MainExecutableName) { 307159269Srwatson return false; 308159269Srwatson} 309159269Srwatson 310159269Srwatsonstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, 311159269Srwatson HANDLE hThread, STACKFRAME64 &StackFrame, 312159269Srwatson CONTEXT *Context) { 313159269Srwatson // It's possible that DbgHelp.dll hasn't been loaded yet (e.g. if this 314159269Srwatson // function is called before the main program called `llvm::InitLLVM`). 315159269Srwatson // In this case just return, not stacktrace will be printed. 316159269Srwatson if (!isDebugHelpInitialized()) 317159269Srwatson return; 318159269Srwatson 319159269Srwatson // Initialize the symbol handler. 320159269Srwatson fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); 321159269Srwatson fSymInitialize(hProcess, NULL, TRUE); 322159269Srwatson 323159269Srwatson // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs 324159269Srwatson // and DWARF, so it should do a good job regardless of what debug info or 325159269Srwatson // linker is in use. 326159269Srwatson if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, 327159269Srwatson Context)) { 328159269Srwatson return; 329159269Srwatson } 330159269Srwatson 331159269Srwatson while (true) { 332159269Srwatson if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 333159269Srwatson Context, 0, fSymFunctionTableAccess64, 334159269Srwatson fSymGetModuleBase64, 0)) { 335159269Srwatson break; 336159269Srwatson } 337159269Srwatson 338159269Srwatson if (StackFrame.AddrFrame.Offset == 0) 339159269Srwatson break; 340159269Srwatson 341159269Srwatson using namespace llvm; 342159269Srwatson // Print the PC in hexadecimal. 343159269Srwatson DWORD64 PC = StackFrame.AddrPC.Offset; 344159269Srwatson#if defined(_M_X64) || defined(_M_ARM64) 345159269Srwatson OS << format("0x%016llX", PC); 346159269Srwatson#elif defined(_M_IX86) || defined(_M_ARM) 347159269Srwatson OS << format("0x%08lX", static_cast<DWORD>(PC)); 348159269Srwatson#endif 349159269Srwatson 350159269Srwatson // Verify the PC belongs to a module in this process. 351159269Srwatson if (!fSymGetModuleBase64(hProcess, PC)) { 352159269Srwatson OS << " <unknown module>\n"; 353159269Srwatson continue; 354159269Srwatson } 355159269Srwatson 356159269Srwatson IMAGEHLP_MODULE64 M; 357159269Srwatson memset(&M, 0, sizeof(IMAGEHLP_MODULE64)); 358159269Srwatson M.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); 359159269Srwatson if (fSymGetModuleInfo64(hProcess, fSymGetModuleBase64(hProcess, PC), &M)) { 360159269Srwatson DWORD64 const disp = PC - M.BaseOfImage; 361159269Srwatson OS << format(", %s(0x%016llX) + 0x%llX byte(s)", 362159269Srwatson static_cast<char *>(M.ImageName), M.BaseOfImage, 363159269Srwatson static_cast<long long>(disp)); 364159269Srwatson } else { 365159269Srwatson OS << ", <unknown module>"; 366159269Srwatson } 367159269Srwatson 368159269Srwatson // Print the symbol name. 369159269Srwatson char buffer[512]; 370159269Srwatson IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 371159269Srwatson memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 372159269Srwatson symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 373159269Srwatson symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 374159269Srwatson 375159269Srwatson DWORD64 dwDisp; 376159269Srwatson if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 377159269Srwatson OS << '\n'; 378159269Srwatson continue; 379159269Srwatson } 380159269Srwatson 381159269Srwatson buffer[511] = 0; 382159269Srwatson OS << format(", %s() + 0x%llX byte(s)", static_cast<char *>(symbol->Name), 383159269Srwatson static_cast<long long>(dwDisp)); 384159269Srwatson 385159269Srwatson // Print the source file and line number information. 386159269Srwatson IMAGEHLP_LINE64 line = {}; 387159269Srwatson DWORD dwLineDisp; 388159269Srwatson line.SizeOfStruct = sizeof(line); 389159269Srwatson if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 390159269Srwatson OS << format(", %s, line %lu + 0x%lX byte(s)", line.FileName, 391159269Srwatson line.LineNumber, dwLineDisp); 392159269Srwatson } 393159269Srwatson 394159269Srwatson OS << '\n'; 395159269Srwatson } 396159269Srwatson} 397159269Srwatson 398155408Srwatsonnamespace llvm { 399155408Srwatson 400155408Srwatson//===----------------------------------------------------------------------===// 401155408Srwatson//=== WARNING: Implementation here must contain only Win32 specific code 402155408Srwatson//=== and must not be UNIX code 403155408Srwatson//===----------------------------------------------------------------------===// 404155408Srwatson 405155408Srwatson#ifdef _MSC_VER 406155408Srwatson/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report 407155408Srwatson/// dialog. "retry" raises an exception which ultimately triggers our stack 408155408Srwatson/// dumper. 409155408Srwatsonstatic LLVM_ATTRIBUTE_UNUSED int 410155408SrwatsonAvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 411155408Srwatson // Set *Return to the retry code for the return value of _CrtDbgReport: 412156292Srwatson // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 413155408Srwatson // This may also trigger just-in-time debugging via DebugBreak(). 414155408Srwatson if (Return) 415155408Srwatson *Return = 1; 416155408Srwatson // Don't call _CrtDbgReport. 417155408Srwatson return TRUE; 418155408Srwatson} 419155408Srwatson 420155408Srwatson#endif 421155408Srwatson 422155408Srwatsonextern "C" void HandleAbort(int Sig) { 423155408Srwatson if (Sig == SIGABRT) { 424155408Srwatson LLVM_BUILTIN_TRAP; 425155408Srwatson } 426155408Srwatson} 427155408Srwatson 428155408Srwatsonstatic void InitializeThreading() { 429155408Srwatson if (CriticalSectionInitialized) 430155408Srwatson return; 431155428Srwatson 432155408Srwatson // Now's the time to create the critical section. This is the first time 433155408Srwatson // through here, and there's only one thread. 434155408Srwatson InitializeCriticalSection(&CriticalSection); 435155408Srwatson CriticalSectionInitialized = true; 436155408Srwatson} 437155408Srwatson 438155408Srwatsonstatic void RegisterHandler() { 439155408Srwatson // If we cannot load up the APIs (which would be unexpected as they should 440161582Srwatson // exist on every version of Windows we support), we will bail out since 441155408Srwatson // there would be nothing to report. 442155408Srwatson if (!load64BitDebugHelp()) { 443155408Srwatson assert(false && "These APIs should always be available"); 444155408Srwatson return; 445155408Srwatson } 446155408Srwatson 447155408Srwatson if (RegisteredUnhandledExceptionFilter) { 448155408Srwatson EnterCriticalSection(&CriticalSection); 449155408Srwatson return; 450159269Srwatson } 451159269Srwatson 452155408Srwatson InitializeThreading(); 453155408Srwatson 454155408Srwatson // Enter it immediately. Now if someone hits CTRL/C, the console handler 455155408Srwatson // can't proceed until the globals are updated. 456155408Srwatson EnterCriticalSection(&CriticalSection); 457155408Srwatson 458155408Srwatson RegisteredUnhandledExceptionFilter = true; 459155408Srwatson OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 460155408Srwatson SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 461155408Srwatson 462159269Srwatson // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 463159269Srwatson // else multi-threading problems will ensue. 464159269Srwatson} 465159269Srwatson 466159269Srwatson// The public API 467159269Srwatsonbool sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) { 468159269Srwatson RegisterHandler(); 469159269Srwatson 470159269Srwatson if (CleanupExecuted) { 471159269Srwatson if (ErrMsg) 472159269Srwatson *ErrMsg = "Process terminating -- cannot register for removal"; 473159269Srwatson return true; 474159269Srwatson } 475159269Srwatson 476159269Srwatson if (FilesToRemove == NULL) 477159269Srwatson FilesToRemove = new std::vector<std::string>; 478159269Srwatson 479159269Srwatson FilesToRemove->push_back(std::string(Filename)); 480159269Srwatson 481159269Srwatson LeaveCriticalSection(&CriticalSection); 482159269Srwatson return false; 483159269Srwatson} 484159269Srwatson 485159269Srwatson// The public API 486159269Srwatsonvoid sys::DontRemoveFileOnSignal(StringRef Filename) { 487159269Srwatson if (FilesToRemove == NULL) 488159269Srwatson return; 489159269Srwatson 490159269Srwatson RegisterHandler(); 491159269Srwatson 492155408Srwatson std::vector<std::string>::reverse_iterator I = 493155408Srwatson find(reverse(*FilesToRemove), Filename); 494155408Srwatson if (I != FilesToRemove->rend()) 495155408Srwatson FilesToRemove->erase(I.base() - 1); 496155408Srwatson 497155408Srwatson LeaveCriticalSection(&CriticalSection); 498155408Srwatson} 499159269Srwatson 500155408Srwatsonvoid sys::DisableSystemDialogsOnCrash() { 501159269Srwatson // Crash to stack trace handler on abort. 502155408Srwatson signal(SIGABRT, HandleAbort); 503155408Srwatson 504155408Srwatson // The following functions are not reliably accessible on MinGW. 505155408Srwatson#ifdef _MSC_VER 506155408Srwatson // We're already handling writing a "something went wrong" message. 507155408Srwatson _set_abort_behavior(0, _WRITE_ABORT_MSG); 508155408Srwatson // Disable Dr. Watson. 509155408Srwatson _set_abort_behavior(0, _CALL_REPORTFAULT); 510155408Srwatson _CrtSetReportHook(AvoidMessageBoxHook); 511155408Srwatson#endif 512155408Srwatson 513155408Srwatson // Disable standard error dialog box. 514155408Srwatson SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 515155408Srwatson SEM_NOOPENFILEERRORBOX); 516155408Srwatson _set_error_mode(_OUT_TO_STDERR); 517155408Srwatson} 518155408Srwatson 519155408Srwatson/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the 520155408Srwatson/// process, print a stack trace and then exit. 521155408Srwatsonvoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0, 522155408Srwatson bool DisableCrashReporting) { 523155408Srwatson ::Argv0 = Argv0; 524155408Srwatson 525155408Srwatson if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) 526155408Srwatson Process::PreventCoreFiles(); 527155408Srwatson 528155408Srwatson DisableSystemDialogsOnCrash(); 529155408Srwatson RegisterHandler(); 530155408Srwatson LeaveCriticalSection(&CriticalSection); 531155408Srwatson} 532155408Srwatson} // namespace llvm 533155408Srwatson 534155408Srwatson#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 535155408Srwatson// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is 536161582Srwatson// missing it but mingw-w64 has it. 537161582Srwatsonextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); 538159269Srwatson#endif 539159269Srwatson 540159269Srwatsonstatic void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { 541159269Srwatson STACKFRAME64 StackFrame{}; 542159269Srwatson CONTEXT Context{}; 543159269Srwatson if (!C) { 544159269Srwatson ::RtlCaptureContext(&Context); 545159269Srwatson C = &Context; 546159269Srwatson } 547159269Srwatson#if defined(_M_X64) 548159269Srwatson StackFrame.AddrPC.Offset = Context.Rip; 549159269Srwatson StackFrame.AddrStack.Offset = Context.Rsp; 550159269Srwatson StackFrame.AddrFrame.Offset = Context.Rbp; 551161582Srwatson#elif defined(_M_IX86) 552161582Srwatson StackFrame.AddrPC.Offset = Context.Eip; 553161582Srwatson StackFrame.AddrStack.Offset = Context.Esp; 554155408Srwatson StackFrame.AddrFrame.Offset = Context.Ebp; 555155408Srwatson#elif defined(_M_ARM64) 556155408Srwatson StackFrame.AddrPC.Offset = Context.Pc; 557159269Srwatson StackFrame.AddrStack.Offset = Context.Sp; 558155408Srwatson StackFrame.AddrFrame.Offset = Context.Fp; 559155408Srwatson#elif defined(_M_ARM) 560155408Srwatson StackFrame.AddrPC.Offset = Context.Pc; 561155408Srwatson StackFrame.AddrStack.Offset = Context.Sp; 562159269Srwatson StackFrame.AddrFrame.Offset = Context.R11; 563155408Srwatson#endif 564155408Srwatson StackFrame.AddrPC.Mode = AddrModeFlat; 565159269Srwatson StackFrame.AddrStack.Mode = AddrModeFlat; 566155408Srwatson StackFrame.AddrFrame.Mode = AddrModeFlat; 567155408Srwatson PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), 568155408Srwatson StackFrame, C); 569155408Srwatson} 570155408Srwatson 571155408Srwatsonvoid llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { 572155408Srwatson // FIXME: Handle "Depth" parameter to print stack trace upto specified Depth 573155408Srwatson LocalPrintStackTrace(OS, nullptr); 574155408Srwatson} 575155408Srwatson 576155408Srwatsonvoid llvm::sys::SetInterruptFunction(void (*IF)()) { 577159269Srwatson RegisterHandler(); 578159269Srwatson InterruptFunction = IF; 579159269Srwatson LeaveCriticalSection(&CriticalSection); 580159269Srwatson} 581159269Srwatson 582159269Srwatsonvoid llvm::sys::SetInfoSignalFunction(void (*Handler)()) { 583159269Srwatson // Unimplemented. 584159269Srwatson} 585159269Srwatson 586159269Srwatsonvoid llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { 587159269Srwatson OneShotPipeSignalFunction.exchange(Handler); 588159269Srwatson} 589159269Srwatson 590159269Srwatsonvoid llvm::sys::DefaultOneShotPipeSignalHandler() { 591159269Srwatson llvm::sys::Process::Exit(EX_IOERR, /*NoCleanup=*/true); 592159269Srwatson} 593161582Srwatson 594159269Srwatsonvoid llvm::sys::CallOneShotPipeSignalHandler() { 595155408Srwatson if (auto OldOneShotPipeFunction = OneShotPipeSignalFunction.exchange(nullptr)) 596155408Srwatson OldOneShotPipeFunction(); 597155408Srwatson} 598155408Srwatson 599155408Srwatson/// Add a function to be called when a signal is delivered to the process. The 600155408Srwatson/// handler can have a cookie passed to it to identify what instance of the 601155408Srwatson/// handler it is. 602155408Srwatsonvoid llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, 603155408Srwatson void *Cookie) { 604155408Srwatson insertSignalHandler(FnPtr, Cookie); 605155408Srwatson RegisterHandler(); 606155408Srwatson LeaveCriticalSection(&CriticalSection); 607155408Srwatson} 608155408Srwatson 609155408Srwatsonstatic void Cleanup(bool ExecuteSignalHandlers) { 610155408Srwatson if (CleanupExecuted) 611155408Srwatson return; 612155408Srwatson 613155408Srwatson EnterCriticalSection(&CriticalSection); 614155408Srwatson 615155408Srwatson // Prevent other thread from registering new files and directories for 616155408Srwatson // removal, should we be executing because of the console handler callback. 617155408Srwatson CleanupExecuted = true; 618155408Srwatson 619155408Srwatson // FIXME: open files cannot be deleted. 620155408Srwatson if (FilesToRemove != NULL) 621155408Srwatson while (!FilesToRemove->empty()) { 622155408Srwatson llvm::sys::fs::remove(FilesToRemove->back()); 623155408Srwatson FilesToRemove->pop_back(); 624155408Srwatson } 625155408Srwatson 626155408Srwatson if (ExecuteSignalHandlers) 627155408Srwatson llvm::sys::RunSignalHandlers(); 628155408Srwatson 629155408Srwatson LeaveCriticalSection(&CriticalSection); 630155408Srwatson} 631155408Srwatson 632155408Srwatsonvoid llvm::sys::RunInterruptHandlers() { 633155408Srwatson // The interrupt handler may be called from an interrupt, but it may also be 634155408Srwatson // called manually (such as the case of report_fatal_error with no registered 635155408Srwatson // error handler). We must ensure that the critical section is properly 636155408Srwatson // initialized. 637155408Srwatson InitializeThreading(); 638155408Srwatson Cleanup(true); 639155408Srwatson} 640155408Srwatson 641155408Srwatson/// Find the Windows Registry Key for a given location. 642155408Srwatson/// 643155408Srwatson/// \returns a valid HKEY if the location exists, else NULL. 644155408Srwatsonstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) { 645155408Srwatson HKEY Key; 646155408Srwatson if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, 647155408Srwatson RegistryLocation.str().c_str(), 0, 648155408Srwatson KEY_QUERY_VALUE | KEY_READ, &Key)) 649155408Srwatson return NULL; 650155408Srwatson 651155408Srwatson return Key; 652155408Srwatson} 653155408Srwatson 654155408Srwatson/// Populate ResultDirectory with the value for "DumpFolder" for a given 655155408Srwatson/// Windows Registry key. 656155408Srwatson/// 657155408Srwatson/// \returns true if a valid value for DumpFolder exists, false otherwise. 658155408Srwatsonstatic bool GetDumpFolder(HKEY Key, 659155408Srwatson llvm::SmallVectorImpl<char> &ResultDirectory) { 660155408Srwatson using llvm::sys::windows::UTF16ToUTF8; 661155408Srwatson 662155408Srwatson if (!Key) 663155408Srwatson return false; 664155408Srwatson 665155408Srwatson DWORD BufferLengthBytes = 0; 666155408Srwatson 667155408Srwatson if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 668155408Srwatson NULL, NULL, &BufferLengthBytes)) 669155408Srwatson return false; 670155408Srwatson 671155408Srwatson SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); 672155408Srwatson 673155408Srwatson if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 674155408Srwatson NULL, Buffer.data(), &BufferLengthBytes)) 675155408Srwatson return false; 676155408Srwatson 677155408Srwatson DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); 678155408Srwatson 679156880Srwatson if (!ExpandBufferSize) 680156880Srwatson return false; 681155408Srwatson 682155408Srwatson SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); 683155408Srwatson 684155408Srwatson if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), 685155408Srwatson ExpandBuffer.data(), 686155408Srwatson ExpandBufferSize)) 687155408Srwatson return false; 688155408Srwatson 689159269Srwatson if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) 690155408Srwatson return false; 691159269Srwatson 692159269Srwatson return true; 693159269Srwatson} 694155408Srwatson 695155408Srwatson/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of 696155408Srwatson/// "DumpType" for a given Windows Registry key. 697159269Srwatson/// 698159269Srwatson/// According to 699159269Srwatson/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx 700159269Srwatson/// valid values for DumpType are: 701159269Srwatson/// * 0: Custom dump 702159269Srwatson/// * 1: Mini dump 703155408Srwatson/// * 2: Full dump 704155408Srwatson/// If "Custom dump" is specified then the "CustomDumpFlags" field is read 705155408Srwatson/// containing a bitwise combination of MINIDUMP_TYPE values. 706155408Srwatson/// 707155408Srwatson/// \returns true if a valid value for ResultType can be set, false otherwise. 708155408Srwatsonstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { 709155408Srwatson if (!Key) 710155408Srwatson return false; 711155408Srwatson 712155408Srwatson DWORD DumpType; 713155408Srwatson DWORD TypeSize = sizeof(DumpType); 714155408Srwatson if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, 715155408Srwatson NULL, &DumpType, &TypeSize)) 716155408Srwatson return false; 717155408Srwatson 718155408Srwatson switch (DumpType) { 719155408Srwatson case 0: { 720155408Srwatson DWORD Flags = 0; 721155408Srwatson if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", 722155408Srwatson RRF_RT_REG_DWORD, NULL, &Flags, 723155408Srwatson &TypeSize)) 724155408Srwatson return false; 725155408Srwatson 726155408Srwatson ResultType = static_cast<MINIDUMP_TYPE>(Flags); 727155408Srwatson break; 728155408Srwatson } 729155408Srwatson case 1: 730155408Srwatson ResultType = MiniDumpNormal; 731155408Srwatson break; 732155408Srwatson case 2: 733155408Srwatson ResultType = MiniDumpWithFullMemory; 734155408Srwatson break; 735155408Srwatson default: 736155408Srwatson return false; 737155408Srwatson } 738155408Srwatson return true; 739155408Srwatson} 740155408Srwatson 741155408Srwatson/// Write a Windows dump file containing process information that can be 742156880Srwatson/// used for post-mortem debugging. 743155408Srwatson/// 744156880Srwatson/// \returns zero error code if a mini dump created, actual error code 745156880Srwatson/// otherwise. 746156880Srwatsonstatic std::error_code WINAPI 747156880SrwatsonWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { 748156880Srwatson struct ScopedCriticalSection { 749156880Srwatson ScopedCriticalSection() { EnterCriticalSection(&CriticalSection); } 750156880Srwatson ~ScopedCriticalSection() { LeaveCriticalSection(&CriticalSection); } 751156880Srwatson } SCS; 752156880Srwatson 753156880Srwatson using namespace llvm; 754156880Srwatson using namespace llvm::sys; 755156880Srwatson 756156880Srwatson std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); 757156880Srwatson StringRef ProgramName; 758156880Srwatson 759156880Srwatson if (MainExecutableName.empty()) { 760156880Srwatson // If we can't get the executable filename, 761156880Srwatson // things are in worse shape than we realize 762156880Srwatson // and we should just bail out. 763156880Srwatson return mapWindowsError(::GetLastError()); 764156884Srwatson } 765156884Srwatson 766156884Srwatson ProgramName = path::filename(MainExecutableName.c_str()); 767156884Srwatson 768156884Srwatson // The Windows Registry location as specified at 769156884Srwatson // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx 770156884Srwatson // "Collecting User-Mode Dumps" that may optionally be set to collect crash 771156884Srwatson // dumps in a specified location. 772156884Srwatson StringRef LocalDumpsRegistryLocation = 773156884Srwatson "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; 774159269Srwatson 775159269Srwatson // The key pointing to the Registry location that may contain global crash 776159269Srwatson // dump settings. This will be NULL if the location can not be found. 777159269Srwatson ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); 778159269Srwatson 779159269Srwatson // The key pointing to the Registry location that may contain 780159269Srwatson // application-specific crash dump settings. This will be NULL if the 781159269Srwatson // location can not be found. 782159269Srwatson ScopedRegHandle AppSpecificKey( 783159269Srwatson FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); 784159269Srwatson 785159269Srwatson // Look to see if a dump type is specified in the registry; first with the 786159269Srwatson // app-specific key and failing that with the global key. If none are found 787159269Srwatson // default to a normal dump (GetDumpType will return false either if the key 788159269Srwatson // is NULL or if there is no valid DumpType value at its location). 789159269Srwatson MINIDUMP_TYPE DumpType; 790159269Srwatson if (!GetDumpType(AppSpecificKey, DumpType)) 791159269Srwatson if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) 792159269Srwatson DumpType = MiniDumpNormal; 793159269Srwatson 794159269Srwatson // Look to see if a dump location is specified on the command line. If not, 795159269Srwatson // look to see if a dump location is specified in the registry; first with the 796159269Srwatson // app-specific key and failing that with the global key. If none are found 797159269Srwatson // we'll just create the dump file in the default temporary file location 798159269Srwatson // (GetDumpFolder will return false either if the key is NULL or if there is 799159269Srwatson // no valid DumpFolder value at its location). 800159269Srwatson bool ExplicitDumpDirectorySet = true; 801159269Srwatson SmallString<MAX_PATH> DumpDirectory(*CrashDiagnosticsDirectory); 802159269Srwatson if (DumpDirectory.empty()) 803159269Srwatson if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) 804159269Srwatson if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) 805159269Srwatson ExplicitDumpDirectorySet = false; 806159269Srwatson 807159269Srwatson int FD; 808159269Srwatson SmallString<MAX_PATH> DumpPath; 809159269Srwatson 810159269Srwatson if (ExplicitDumpDirectorySet) { 811159269Srwatson if (std::error_code EC = fs::create_directories(DumpDirectory)) 812159269Srwatson return EC; 813159269Srwatson if (std::error_code EC = fs::createUniqueFile( 814159269Srwatson Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, 815159269Srwatson DumpPath)) 816159269Srwatson return EC; 817159269Srwatson } else if (std::error_code EC = 818159269Srwatson fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) 819159269Srwatson return EC; 820159269Srwatson 821159269Srwatson // Our support functions return a file descriptor but Windows wants a handle. 822159269Srwatson ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); 823159269Srwatson 824159269Srwatson if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), 825159269Srwatson FileHandle, DumpType, ExceptionInfo, NULL, NULL)) 826159269Srwatson return mapWindowsError(::GetLastError()); 827159269Srwatson 828159269Srwatson llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; 829159269Srwatson return std::error_code(); 830159269Srwatson} 831159269Srwatson 832159269Srwatsonvoid sys::CleanupOnSignal(uintptr_t Context) { 833159269Srwatson LPEXCEPTION_POINTERS EP = (LPEXCEPTION_POINTERS)Context; 834159269Srwatson // Broken pipe is not a crash. 835159269Srwatson // 836159269Srwatson // 0xE0000000 is combined with the return code in the exception raised in 837159269Srwatson // CrashRecoveryContext::HandleExit(). 838159269Srwatson unsigned RetCode = EP->ExceptionRecord->ExceptionCode; 839159269Srwatson if (RetCode == (0xE0000000 | EX_IOERR)) 840159269Srwatson return; 841159269Srwatson LLVMUnhandledExceptionFilter(EP); 842159269Srwatson} 843159269Srwatson 844159269Srwatsonstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 845159269Srwatson Cleanup(true); 846159269Srwatson 847159269Srwatson // Write out the exception code. 848159269Srwatson if (ep && ep->ExceptionRecord) 849159269Srwatson llvm::errs() << format("Exception Code: 0x%08X", 850159269Srwatson ep->ExceptionRecord->ExceptionCode) 851159269Srwatson << "\n"; 852159269Srwatson 853159269Srwatson // We'll automatically write a Minidump file here to help diagnose 854159269Srwatson // the nasty sorts of crashes that aren't 100% reproducible from a set of 855159269Srwatson // inputs (or in the event that the user is unable or unwilling to provide a 856159269Srwatson // reproducible case). 857159269Srwatson if (!llvm::sys::Process::AreCoreFilesPrevented()) { 858161646Srwatson MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; 859161646Srwatson ExceptionInfo.ThreadId = ::GetCurrentThreadId(); 860161646Srwatson ExceptionInfo.ExceptionPointers = ep; 861161646Srwatson ExceptionInfo.ClientPointers = FALSE; 862161646Srwatson 863156880Srwatson if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) 864156880Srwatson llvm::errs() << "Could not write crash dump file: " << EC.message() 865156880Srwatson << "\n"; 866156880Srwatson } 867156880Srwatson 868156880Srwatson // Stack unwinding appears to modify the context. Copy it to preserve the 869156880Srwatson // caller's context. 870156880Srwatson CONTEXT ContextCopy; 871156880Srwatson if (ep) 872156880Srwatson memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); 873156880Srwatson 874156880Srwatson LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); 875156880Srwatson 876156880Srwatson return EXCEPTION_EXECUTE_HANDLER; 877156880Srwatson} 878156880Srwatson 879156880Srwatsonstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 880156880Srwatson // We are running in our very own thread, courtesy of Windows. 881156880Srwatson EnterCriticalSection(&CriticalSection); 882156880Srwatson // This function is only ever called when a CTRL-C or similar control signal 883155408Srwatson // is fired. Killing a process in this way is normal, so don't trigger the 884155408Srwatson // signal handlers. 885155408Srwatson Cleanup(false); 886155408Srwatson 887155408Srwatson // If an interrupt function has been set, go and run one it; otherwise, 888155408Srwatson // the process dies. 889155408Srwatson void (*IF)() = InterruptFunction; 890155408Srwatson InterruptFunction = 0; // Don't run it on another CTRL-C. 891155408Srwatson 892159269Srwatson if (IF) { 893159269Srwatson // Note: if the interrupt function throws an exception, there is nothing 894159269Srwatson // to catch it in this thread so it will kill the process. 895159269Srwatson IF(); // Run it now. 896159269Srwatson LeaveCriticalSection(&CriticalSection); 897159269Srwatson return TRUE; // Don't kill the process. 898159269Srwatson } 899159269Srwatson 900159269Srwatson // Allow normal processing to take place; i.e., the process dies. 901159269Srwatson LeaveCriticalSection(&CriticalSection); 902159269Srwatson return FALSE; 903155408Srwatson} 904155408Srwatson 905155408Srwatson#if __MINGW32__ 906155408Srwatson// We turned these warnings off for this file so that MinGW-g++ doesn't 907155408Srwatson// complain about the ll format specifiers used. Now we are turning the 908155408Srwatson// warnings back on. If MinGW starts to support diagnostic stacks, we can 909155408Srwatson// replace this with a pop. 910155408Srwatson#pragma GCC diagnostic warning "-Wformat" 911155408Srwatson#pragma GCC diagnostic warning "-Wformat-extra-args" 912155408Srwatson#endif 913155408Srwatson 914155408Srwatsonvoid sys::unregisterHandlers() {} 915155408Srwatson