1218885Sdim//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 2218885Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6218885Sdim// 7218885Sdim//===----------------------------------------------------------------------===// 8218885Sdim// 9218885Sdim// This file provides the Win32 specific implementation of the Signals class. 10218885Sdim// 11218885Sdim//===----------------------------------------------------------------------===// 12341825Sdim#include "llvm/Support/ConvertUTF.h" 13261991Sdim#include "llvm/Support/FileSystem.h" 14309124Sdim#include "llvm/Support/Path.h" 15309124Sdim#include "llvm/Support/Process.h" 16309124Sdim#include "llvm/Support/WindowsError.h" 17249423Sdim#include <algorithm> 18309124Sdim#include <io.h> 19288943Sdim#include <signal.h> 20218885Sdim#include <stdio.h> 21218885Sdim 22288943Sdim#include "llvm/Support/Format.h" 23288943Sdim#include "llvm/Support/raw_ostream.h" 24288943Sdim 25276479Sdim// The Windows.h header must be after LLVM and standard headers. 26360784Sdim#include "llvm/Support/Windows/WindowsSupport.h" 27276479Sdim 28218885Sdim#ifdef __MINGW32__ 29218885Sdim #include <imagehlp.h> 30218885Sdim#else 31314564Sdim #include <crtdbg.h> 32218885Sdim #include <dbghelp.h> 33218885Sdim#endif 34218885Sdim#include <psapi.h> 35218885Sdim 36226633Sdim#ifdef _MSC_VER 37226633Sdim #pragma comment(lib, "psapi.lib") 38226633Sdim#elif __MINGW32__ 39226633Sdim // The version of g++ that comes with MinGW does *not* properly understand 40226633Sdim // the ll format specifier for printf. However, MinGW passes the format 41226633Sdim // specifiers on to the MSVCRT entirely, and the CRT understands the ll 42226633Sdim // specifier. So these warnings are spurious in this case. Since we compile 43226633Sdim // with -Wall, this will generate these warnings which should be ignored. So 44226633Sdim // we will turn off the warnings for this just file. However, MinGW also does 45226633Sdim // not support push and pop for diagnostics, so we have to manually turn it 46226633Sdim // back on at the end of the file. 47226633Sdim #pragma GCC diagnostic ignored "-Wformat" 48226633Sdim #pragma GCC diagnostic ignored "-Wformat-extra-args" 49218885Sdim 50226633Sdim #if !defined(__MINGW64_VERSION_MAJOR) 51226633Sdim // MinGW.org does not have updated support for the 64-bit versions of the 52226633Sdim // DebugHlp APIs. So we will have to load them manually. The structures and 53226633Sdim // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 54226633Sdim // and adjusted for brevity. 55226633Sdim typedef struct _IMAGEHLP_LINE64 { 56226633Sdim DWORD SizeOfStruct; 57226633Sdim PVOID Key; 58226633Sdim DWORD LineNumber; 59226633Sdim PCHAR FileName; 60226633Sdim DWORD64 Address; 61226633Sdim } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 62226633Sdim 63226633Sdim typedef struct _IMAGEHLP_SYMBOL64 { 64226633Sdim DWORD SizeOfStruct; 65226633Sdim DWORD64 Address; 66226633Sdim DWORD Size; 67226633Sdim DWORD Flags; 68226633Sdim DWORD MaxNameLength; 69226633Sdim CHAR Name[1]; 70226633Sdim } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 71226633Sdim 72226633Sdim typedef struct _tagADDRESS64 { 73226633Sdim DWORD64 Offset; 74226633Sdim WORD Segment; 75226633Sdim ADDRESS_MODE Mode; 76226633Sdim } ADDRESS64, *LPADDRESS64; 77226633Sdim 78226633Sdim typedef struct _KDHELP64 { 79226633Sdim DWORD64 Thread; 80226633Sdim DWORD ThCallbackStack; 81226633Sdim DWORD ThCallbackBStore; 82226633Sdim DWORD NextCallback; 83226633Sdim DWORD FramePointer; 84226633Sdim DWORD64 KiCallUserMode; 85226633Sdim DWORD64 KeUserCallbackDispatcher; 86226633Sdim DWORD64 SystemRangeStart; 87226633Sdim DWORD64 KiUserExceptionDispatcher; 88226633Sdim DWORD64 StackBase; 89226633Sdim DWORD64 StackLimit; 90226633Sdim DWORD64 Reserved[5]; 91226633Sdim } KDHELP64, *PKDHELP64; 92226633Sdim 93226633Sdim typedef struct _tagSTACKFRAME64 { 94226633Sdim ADDRESS64 AddrPC; 95226633Sdim ADDRESS64 AddrReturn; 96226633Sdim ADDRESS64 AddrFrame; 97226633Sdim ADDRESS64 AddrStack; 98226633Sdim ADDRESS64 AddrBStore; 99226633Sdim PVOID FuncTableEntry; 100226633Sdim DWORD64 Params[4]; 101226633Sdim BOOL Far; 102226633Sdim BOOL Virtual; 103226633Sdim DWORD64 Reserved[3]; 104226633Sdim KDHELP64 KdHelp; 105226633Sdim } STACKFRAME64, *LPSTACKFRAME64; 106288943Sdim #endif // !defined(__MINGW64_VERSION_MAJOR) 107288943Sdim#endif // __MINGW32__ 108226633Sdim 109226633Sdimtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, 110226633Sdim DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 111226633Sdim LPDWORD lpNumberOfBytesRead); 112226633Sdim 113226633Sdimtypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, 114226633Sdim DWORD64 AddrBase); 115226633Sdim 116226633Sdimtypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 117226633Sdim DWORD64 Address); 118226633Sdim 119226633Sdimtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 120226633Sdim HANDLE hThread, LPADDRESS64 lpaddr); 121226633Sdim 122309124Sdimtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, 123309124Sdim PMINIDUMP_EXCEPTION_INFORMATION, 124309124Sdim PMINIDUMP_USER_STREAM_INFORMATION, 125309124Sdim PMINIDUMP_CALLBACK_INFORMATION); 126309124Sdimstatic fpMiniDumpWriteDump fMiniDumpWriteDump; 127309124Sdim 128226633Sdimtypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 129226633Sdim PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 130226633Sdim PFUNCTION_TABLE_ACCESS_ROUTINE64, 131226633Sdim PGET_MODULE_BASE_ROUTINE64, 132226633Sdim PTRANSLATE_ADDRESS_ROUTINE64); 133288943Sdimstatic fpStackWalk64 fStackWalk64; 134226633Sdim 135226633Sdimtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 136288943Sdimstatic fpSymGetModuleBase64 fSymGetModuleBase64; 137226633Sdim 138226633Sdimtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, 139226633Sdim PDWORD64, PIMAGEHLP_SYMBOL64); 140288943Sdimstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64; 141226633Sdim 142226633Sdimtypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, 143226633Sdim PDWORD, PIMAGEHLP_LINE64); 144288943Sdimstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64; 145226633Sdim 146296417Sdimtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, 147296417Sdim PIMAGEHLP_MODULE64 ModuleInfo); 148296417Sdimstatic fpSymGetModuleInfo64 fSymGetModuleInfo64; 149296417Sdim 150226633Sdimtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 151288943Sdimstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64; 152226633Sdim 153288943Sdimtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD); 154288943Sdimstatic fpSymSetOptions fSymSetOptions; 155288943Sdim 156288943Sdimtypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); 157288943Sdimstatic fpSymInitialize fSymInitialize; 158288943Sdim 159296417Sdimtypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); 160296417Sdimstatic fpEnumerateLoadedModules fEnumerateLoadedModules; 161296417Sdim 162226633Sdimstatic bool load64BitDebugHelp(void) { 163261991Sdim HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 164226633Sdim if (hLib) { 165309124Sdim fMiniDumpWriteDump = (fpMiniDumpWriteDump) 166309124Sdim ::GetProcAddress(hLib, "MiniDumpWriteDump"); 167288943Sdim fStackWalk64 = (fpStackWalk64) 168226633Sdim ::GetProcAddress(hLib, "StackWalk64"); 169288943Sdim fSymGetModuleBase64 = (fpSymGetModuleBase64) 170226633Sdim ::GetProcAddress(hLib, "SymGetModuleBase64"); 171288943Sdim fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) 172226633Sdim ::GetProcAddress(hLib, "SymGetSymFromAddr64"); 173288943Sdim fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) 174226633Sdim ::GetProcAddress(hLib, "SymGetLineFromAddr64"); 175296417Sdim fSymGetModuleInfo64 = (fpSymGetModuleInfo64) 176296417Sdim ::GetProcAddress(hLib, "SymGetModuleInfo64"); 177288943Sdim fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) 178226633Sdim ::GetProcAddress(hLib, "SymFunctionTableAccess64"); 179288943Sdim fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); 180288943Sdim fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); 181296417Sdim fEnumerateLoadedModules = (fpEnumerateLoadedModules) 182296417Sdim ::GetProcAddress(hLib, "EnumerateLoadedModules64"); 183226633Sdim } 184309124Sdim return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; 185226633Sdim} 186226633Sdim 187296417Sdimusing namespace llvm; 188296417Sdim 189218885Sdim// Forward declare. 190218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 191218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 192218885Sdim 193341825Sdim// The function to call if ctrl-c is pressed. 194218885Sdimstatic void (*InterruptFunction)() = 0; 195218885Sdim 196261991Sdimstatic std::vector<std::string> *FilesToRemove = NULL; 197218885Sdimstatic bool RegisteredUnhandledExceptionFilter = false; 198218885Sdimstatic bool CleanupExecuted = false; 199218885Sdimstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 200218885Sdim 201218885Sdim// Windows creates a new thread to execute the console handler when an event 202218885Sdim// (such as CTRL/C) occurs. This causes concurrency issues with the above 203218885Sdim// globals which this critical section addresses. 204218885Sdimstatic CRITICAL_SECTION CriticalSection; 205288943Sdimstatic bool CriticalSectionInitialized = false; 206218885Sdim 207309124Sdimstatic StringRef Argv0; 208309124Sdim 209296417Sdimenum { 210288943Sdim#if defined(_M_X64) 211296417Sdim NativeMachineType = IMAGE_FILE_MACHINE_AMD64 212327952Sdim#elif defined(_M_ARM64) 213327952Sdim NativeMachineType = IMAGE_FILE_MACHINE_ARM64 214327952Sdim#elif defined(_M_IX86) 215327952Sdim NativeMachineType = IMAGE_FILE_MACHINE_I386 216327952Sdim#elif defined(_M_ARM) 217327952Sdim NativeMachineType = IMAGE_FILE_MACHINE_ARMNT 218288943Sdim#else 219327952Sdim NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN 220288943Sdim#endif 221296417Sdim}; 222288943Sdim 223296417Sdimstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, 224296417Sdim HANDLE hProcess, HANDLE hThread, 225296417Sdim STACKFRAME64 &StackFrameOrig, 226296417Sdim CONTEXT *ContextOrig) { 227296417Sdim // StackWalk64 modifies the incoming stack frame and context, so copy them. 228296417Sdim STACKFRAME64 StackFrame = StackFrameOrig; 229296417Sdim 230296417Sdim // Copy the register context so that we don't modify it while we unwind. We 231296417Sdim // could use InitializeContext + CopyContext, but that's only required to get 232296417Sdim // at AVX registers, which typically aren't needed by StackWalk64. Reduce the 233296417Sdim // flag set to indicate that there's less data. 234296417Sdim CONTEXT Context = *ContextOrig; 235296417Sdim Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; 236296417Sdim 237296417Sdim static void *StackTrace[256]; 238296417Sdim size_t Depth = 0; 239296417Sdim while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 240296417Sdim &Context, 0, fSymFunctionTableAccess64, 241296417Sdim fSymGetModuleBase64, 0)) { 242296417Sdim if (StackFrame.AddrFrame.Offset == 0) 243296417Sdim break; 244296417Sdim StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; 245296417Sdim if (Depth >= array_lengthof(StackTrace)) 246296417Sdim break; 247296417Sdim } 248296417Sdim 249309124Sdim return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); 250296417Sdim} 251296417Sdim 252296417Sdimnamespace { 253296417Sdimstruct FindModuleData { 254296417Sdim void **StackTrace; 255296417Sdim int Depth; 256296417Sdim const char **Modules; 257296417Sdim intptr_t *Offsets; 258296417Sdim StringSaver *StrPool; 259296417Sdim}; 260296417Sdim} 261296417Sdim 262309124Sdimstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName, 263296417Sdim DWORD64 ModuleBase, ULONG ModuleSize, 264296417Sdim void *VoidData) { 265296417Sdim FindModuleData *Data = (FindModuleData*)VoidData; 266296417Sdim intptr_t Beg = ModuleBase; 267296417Sdim intptr_t End = Beg + ModuleSize; 268296417Sdim for (int I = 0; I < Data->Depth; I++) { 269296417Sdim if (Data->Modules[I]) 270296417Sdim continue; 271296417Sdim intptr_t Addr = (intptr_t)Data->StackTrace[I]; 272296417Sdim if (Beg <= Addr && Addr < End) { 273314564Sdim Data->Modules[I] = Data->StrPool->save(ModuleName).data(); 274296417Sdim Data->Offsets[I] = Addr - Beg; 275296417Sdim } 276296417Sdim } 277296417Sdim return TRUE; 278296417Sdim} 279296417Sdim 280296417Sdimstatic bool findModulesAndOffsets(void **StackTrace, int Depth, 281296417Sdim const char **Modules, intptr_t *Offsets, 282296417Sdim const char *MainExecutableName, 283296417Sdim StringSaver &StrPool) { 284296417Sdim if (!fEnumerateLoadedModules) 285296417Sdim return false; 286296417Sdim FindModuleData Data; 287296417Sdim Data.StackTrace = StackTrace; 288296417Sdim Data.Depth = Depth; 289296417Sdim Data.Modules = Modules; 290296417Sdim Data.Offsets = Offsets; 291296417Sdim Data.StrPool = &StrPool; 292296417Sdim fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); 293296417Sdim return true; 294296417Sdim} 295296417Sdim 296296417Sdimstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, 297296417Sdim HANDLE hThread, STACKFRAME64 &StackFrame, 298296417Sdim CONTEXT *Context) { 299288943Sdim // Initialize the symbol handler. 300288943Sdim fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); 301288943Sdim fSymInitialize(hProcess, NULL, TRUE); 302288943Sdim 303296417Sdim // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs 304296417Sdim // and DWARF, so it should do a good job regardless of what debug info or 305296417Sdim // linker is in use. 306296417Sdim if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, 307296417Sdim Context)) { 308296417Sdim return; 309296417Sdim } 310296417Sdim 311288943Sdim while (true) { 312296417Sdim if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 313296417Sdim Context, 0, fSymFunctionTableAccess64, 314296417Sdim fSymGetModuleBase64, 0)) { 315288943Sdim break; 316288943Sdim } 317288943Sdim 318288943Sdim if (StackFrame.AddrFrame.Offset == 0) 319288943Sdim break; 320288943Sdim 321288943Sdim using namespace llvm; 322288943Sdim // Print the PC in hexadecimal. 323288943Sdim DWORD64 PC = StackFrame.AddrPC.Offset; 324327952Sdim#if defined(_M_X64) || defined(_M_ARM64) 325288943Sdim OS << format("0x%016llX", PC); 326327952Sdim#elif defined(_M_IX86) || defined(_M_ARM) 327288943Sdim OS << format("0x%08lX", static_cast<DWORD>(PC)); 328288943Sdim#endif 329288943Sdim 330288943Sdim// Print the parameters. Assume there are four. 331327952Sdim#if defined(_M_X64) || defined(_M_ARM64) 332288943Sdim OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", 333288943Sdim StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], 334288943Sdim StackFrame.Params[3]); 335327952Sdim#elif defined(_M_IX86) || defined(_M_ARM) 336288943Sdim OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", 337288943Sdim static_cast<DWORD>(StackFrame.Params[0]), 338288943Sdim static_cast<DWORD>(StackFrame.Params[1]), 339288943Sdim static_cast<DWORD>(StackFrame.Params[2]), 340288943Sdim static_cast<DWORD>(StackFrame.Params[3])); 341288943Sdim#endif 342288943Sdim // Verify the PC belongs to a module in this process. 343288943Sdim if (!fSymGetModuleBase64(hProcess, PC)) { 344288943Sdim OS << " <unknown module>\n"; 345288943Sdim continue; 346288943Sdim } 347288943Sdim 348288943Sdim // Print the symbol name. 349288943Sdim char buffer[512]; 350288943Sdim IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 351288943Sdim memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 352288943Sdim symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 353288943Sdim symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 354288943Sdim 355288943Sdim DWORD64 dwDisp; 356288943Sdim if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 357288943Sdim OS << '\n'; 358288943Sdim continue; 359288943Sdim } 360288943Sdim 361288943Sdim buffer[511] = 0; 362288943Sdim if (dwDisp > 0) 363288943Sdim OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, 364288943Sdim dwDisp); 365288943Sdim else 366288943Sdim OS << format(", %s", (const char*)symbol->Name); 367288943Sdim 368288943Sdim // Print the source file and line number information. 369288943Sdim IMAGEHLP_LINE64 line = {}; 370288943Sdim DWORD dwLineDisp; 371288943Sdim line.SizeOfStruct = sizeof(line); 372288943Sdim if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 373288943Sdim OS << format(", %s, line %lu", line.FileName, line.LineNumber); 374288943Sdim if (dwLineDisp > 0) 375288943Sdim OS << format(" + 0x%lX byte(s)", dwLineDisp); 376288943Sdim } 377288943Sdim 378288943Sdim OS << '\n'; 379288943Sdim } 380288943Sdim} 381288943Sdim 382218885Sdimnamespace llvm { 383218885Sdim 384218885Sdim//===----------------------------------------------------------------------===// 385218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code 386218885Sdim//=== and must not be UNIX code 387218885Sdim//===----------------------------------------------------------------------===// 388218885Sdim 389218885Sdim#ifdef _MSC_VER 390341825Sdim/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report 391341825Sdim/// dialog. "retry" raises an exception which ultimately triggers our stack 392341825Sdim/// dumper. 393288943Sdimstatic LLVM_ATTRIBUTE_UNUSED int 394288943SdimAvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 395251662Sdim // Set *Return to the retry code for the return value of _CrtDbgReport: 396251662Sdim // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 397251662Sdim // This may also trigger just-in-time debugging via DebugBreak(). 398251662Sdim if (Return) 399251662Sdim *Return = 1; 400251662Sdim // Don't call _CrtDbgReport. 401251662Sdim return TRUE; 402251662Sdim} 403251662Sdim 404218885Sdim#endif 405218885Sdim 406288943Sdimextern "C" void HandleAbort(int Sig) { 407288943Sdim if (Sig == SIGABRT) { 408288943Sdim LLVM_BUILTIN_TRAP; 409288943Sdim } 410288943Sdim} 411288943Sdim 412288943Sdimstatic void InitializeThreading() { 413288943Sdim if (CriticalSectionInitialized) 414288943Sdim return; 415288943Sdim 416288943Sdim // Now's the time to create the critical section. This is the first time 417288943Sdim // through here, and there's only one thread. 418288943Sdim InitializeCriticalSection(&CriticalSection); 419288943Sdim CriticalSectionInitialized = true; 420288943Sdim} 421288943Sdim 422218885Sdimstatic void RegisterHandler() { 423288943Sdim // If we cannot load up the APIs (which would be unexpected as they should 424288943Sdim // exist on every version of Windows we support), we will bail out since 425288943Sdim // there would be nothing to report. 426226633Sdim if (!load64BitDebugHelp()) { 427226633Sdim assert(false && "These APIs should always be available"); 428226633Sdim return; 429226633Sdim } 430226633Sdim 431218885Sdim if (RegisteredUnhandledExceptionFilter) { 432218885Sdim EnterCriticalSection(&CriticalSection); 433218885Sdim return; 434218885Sdim } 435218885Sdim 436288943Sdim InitializeThreading(); 437218885Sdim 438218885Sdim // Enter it immediately. Now if someone hits CTRL/C, the console handler 439218885Sdim // can't proceed until the globals are updated. 440218885Sdim EnterCriticalSection(&CriticalSection); 441218885Sdim 442218885Sdim RegisteredUnhandledExceptionFilter = true; 443218885Sdim OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 444218885Sdim SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 445218885Sdim 446218885Sdim // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 447218885Sdim // else multi-threading problems will ensue. 448218885Sdim} 449218885Sdim 450341825Sdim// The public API 451261991Sdimbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { 452218885Sdim RegisterHandler(); 453218885Sdim 454218885Sdim if (CleanupExecuted) { 455218885Sdim if (ErrMsg) 456218885Sdim *ErrMsg = "Process terminating -- cannot register for removal"; 457218885Sdim return true; 458218885Sdim } 459218885Sdim 460218885Sdim if (FilesToRemove == NULL) 461261991Sdim FilesToRemove = new std::vector<std::string>; 462218885Sdim 463218885Sdim FilesToRemove->push_back(Filename); 464218885Sdim 465218885Sdim LeaveCriticalSection(&CriticalSection); 466218885Sdim return false; 467218885Sdim} 468218885Sdim 469341825Sdim// The public API 470261991Sdimvoid sys::DontRemoveFileOnSignal(StringRef Filename) { 471218885Sdim if (FilesToRemove == NULL) 472218885Sdim return; 473218885Sdim 474218885Sdim RegisterHandler(); 475218885Sdim 476261991Sdim std::vector<std::string>::reverse_iterator I = 477314564Sdim find(reverse(*FilesToRemove), Filename); 478218885Sdim if (I != FilesToRemove->rend()) 479218885Sdim FilesToRemove->erase(I.base()-1); 480218885Sdim 481218885Sdim LeaveCriticalSection(&CriticalSection); 482218885Sdim} 483218885Sdim 484288943Sdimvoid sys::DisableSystemDialogsOnCrash() { 485288943Sdim // Crash to stack trace handler on abort. 486288943Sdim signal(SIGABRT, HandleAbort); 487288943Sdim 488288943Sdim // The following functions are not reliably accessible on MinGW. 489288943Sdim#ifdef _MSC_VER 490288943Sdim // We're already handling writing a "something went wrong" message. 491288943Sdim _set_abort_behavior(0, _WRITE_ABORT_MSG); 492288943Sdim // Disable Dr. Watson. 493288943Sdim _set_abort_behavior(0, _CALL_REPORTFAULT); 494288943Sdim _CrtSetReportHook(AvoidMessageBoxHook); 495288943Sdim#endif 496288943Sdim 497288943Sdim // Disable standard error dialog box. 498288943Sdim SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 499288943Sdim SEM_NOOPENFILEERRORBOX); 500288943Sdim _set_error_mode(_OUT_TO_STDERR); 501288943Sdim} 502288943Sdim 503341825Sdim/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the 504341825Sdim/// process, print a stack trace and then exit. 505309124Sdimvoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0, 506309124Sdim bool DisableCrashReporting) { 507309124Sdim ::Argv0 = Argv0; 508309124Sdim 509309124Sdim if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) 510309124Sdim Process::PreventCoreFiles(); 511309124Sdim 512288943Sdim DisableSystemDialogsOnCrash(); 513218885Sdim RegisterHandler(); 514218885Sdim LeaveCriticalSection(&CriticalSection); 515218885Sdim} 516288943Sdim} 517218885Sdim 518288943Sdim#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 519288943Sdim// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is 520288943Sdim// missing it but mingw-w64 has it. 521288943Sdimextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); 522288943Sdim#endif 523288943Sdim 524360784Sdimstatic void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { 525360784Sdim STACKFRAME64 StackFrame{}; 526360784Sdim CONTEXT Context{}; 527360784Sdim if (!C) { 528360784Sdim ::RtlCaptureContext(&Context); 529360784Sdim C = &Context; 530360784Sdim } 531288943Sdim#if defined(_M_X64) 532288943Sdim StackFrame.AddrPC.Offset = Context.Rip; 533288943Sdim StackFrame.AddrStack.Offset = Context.Rsp; 534288943Sdim StackFrame.AddrFrame.Offset = Context.Rbp; 535327952Sdim#elif defined(_M_IX86) 536288943Sdim StackFrame.AddrPC.Offset = Context.Eip; 537288943Sdim StackFrame.AddrStack.Offset = Context.Esp; 538288943Sdim StackFrame.AddrFrame.Offset = Context.Ebp; 539341825Sdim#elif defined(_M_ARM64) 540327952Sdim StackFrame.AddrPC.Offset = Context.Pc; 541327952Sdim StackFrame.AddrStack.Offset = Context.Sp; 542327952Sdim StackFrame.AddrFrame.Offset = Context.Fp; 543341825Sdim#elif defined(_M_ARM) 544341825Sdim StackFrame.AddrPC.Offset = Context.Pc; 545341825Sdim StackFrame.AddrStack.Offset = Context.Sp; 546341825Sdim StackFrame.AddrFrame.Offset = Context.R11; 547288943Sdim#endif 548288943Sdim StackFrame.AddrPC.Mode = AddrModeFlat; 549288943Sdim StackFrame.AddrStack.Mode = AddrModeFlat; 550288943Sdim StackFrame.AddrFrame.Mode = AddrModeFlat; 551288943Sdim PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), 552360784Sdim StackFrame, C); 553249423Sdim} 554218885Sdim 555360784Sdimvoid llvm::sys::PrintStackTrace(raw_ostream &OS) { 556360784Sdim LocalPrintStackTrace(OS, nullptr); 557360784Sdim} 558249423Sdim 559288943Sdimvoid llvm::sys::SetInterruptFunction(void (*IF)()) { 560218885Sdim RegisterHandler(); 561218885Sdim InterruptFunction = IF; 562218885Sdim LeaveCriticalSection(&CriticalSection); 563218885Sdim} 564218885Sdim 565353358Sdimvoid llvm::sys::SetInfoSignalFunction(void (*Handler)()) { 566353358Sdim // Unimplemented. 567353358Sdim} 568218885Sdim 569360784Sdimvoid llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { 570360784Sdim // Unimplemented. 571360784Sdim} 572353358Sdim 573360784Sdimvoid llvm::sys::DefaultOneShotPipeSignalHandler() { 574360784Sdim // Unimplemented. 575360784Sdim} 576360784Sdim 577341825Sdim/// Add a function to be called when a signal is delivered to the process. The 578341825Sdim/// handler can have a cookie passed to it to identify what instance of the 579341825Sdim/// handler it is. 580341825Sdimvoid llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, 581341825Sdim void *Cookie) { 582341825Sdim insertSignalHandler(FnPtr, Cookie); 583218885Sdim RegisterHandler(); 584218885Sdim LeaveCriticalSection(&CriticalSection); 585218885Sdim} 586218885Sdim 587218885Sdimstatic void Cleanup() { 588288943Sdim if (CleanupExecuted) 589288943Sdim return; 590288943Sdim 591218885Sdim EnterCriticalSection(&CriticalSection); 592218885Sdim 593218885Sdim // Prevent other thread from registering new files and directories for 594218885Sdim // removal, should we be executing because of the console handler callback. 595218885Sdim CleanupExecuted = true; 596218885Sdim 597218885Sdim // FIXME: open files cannot be deleted. 598218885Sdim if (FilesToRemove != NULL) 599218885Sdim while (!FilesToRemove->empty()) { 600276479Sdim llvm::sys::fs::remove(FilesToRemove->back()); 601218885Sdim FilesToRemove->pop_back(); 602218885Sdim } 603296417Sdim llvm::sys::RunSignalHandlers(); 604218885Sdim LeaveCriticalSection(&CriticalSection); 605218885Sdim} 606218885Sdim 607218885Sdimvoid llvm::sys::RunInterruptHandlers() { 608288943Sdim // The interrupt handler may be called from an interrupt, but it may also be 609288943Sdim // called manually (such as the case of report_fatal_error with no registered 610288943Sdim // error handler). We must ensure that the critical section is properly 611288943Sdim // initialized. 612288943Sdim InitializeThreading(); 613218885Sdim Cleanup(); 614218885Sdim} 615218885Sdim 616341825Sdim/// Find the Windows Registry Key for a given location. 617309124Sdim/// 618309124Sdim/// \returns a valid HKEY if the location exists, else NULL. 619309124Sdimstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) { 620309124Sdim HKEY Key; 621309124Sdim if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, 622309124Sdim RegistryLocation.str().c_str(), 0, 623309124Sdim KEY_QUERY_VALUE | KEY_READ, &Key)) 624309124Sdim return NULL; 625309124Sdim 626309124Sdim return Key; 627309124Sdim} 628309124Sdim 629341825Sdim/// Populate ResultDirectory with the value for "DumpFolder" for a given 630309124Sdim/// Windows Registry key. 631309124Sdim/// 632309124Sdim/// \returns true if a valid value for DumpFolder exists, false otherwise. 633309124Sdimstatic bool GetDumpFolder(HKEY Key, 634309124Sdim llvm::SmallVectorImpl<char> &ResultDirectory) { 635309124Sdim using llvm::sys::windows::UTF16ToUTF8; 636309124Sdim 637309124Sdim if (!Key) 638309124Sdim return false; 639309124Sdim 640309124Sdim DWORD BufferLengthBytes = 0; 641309124Sdim 642309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 643309124Sdim NULL, NULL, &BufferLengthBytes)) 644309124Sdim return false; 645309124Sdim 646309124Sdim SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); 647309124Sdim 648309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 649309124Sdim NULL, Buffer.data(), &BufferLengthBytes)) 650309124Sdim return false; 651309124Sdim 652309124Sdim DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); 653309124Sdim 654309124Sdim if (!ExpandBufferSize) 655309124Sdim return false; 656309124Sdim 657309124Sdim SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); 658309124Sdim 659309124Sdim if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), 660309124Sdim ExpandBuffer.data(), 661309124Sdim ExpandBufferSize)) 662309124Sdim return false; 663309124Sdim 664309124Sdim if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) 665309124Sdim return false; 666309124Sdim 667309124Sdim return true; 668309124Sdim} 669309124Sdim 670341825Sdim/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of 671309124Sdim/// "DumpType" for a given Windows Registry key. 672309124Sdim/// 673309124Sdim/// According to 674309124Sdim/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx 675309124Sdim/// valid values for DumpType are: 676309124Sdim/// * 0: Custom dump 677309124Sdim/// * 1: Mini dump 678309124Sdim/// * 2: Full dump 679309124Sdim/// If "Custom dump" is specified then the "CustomDumpFlags" field is read 680309124Sdim/// containing a bitwise combination of MINIDUMP_TYPE values. 681309124Sdim/// 682309124Sdim/// \returns true if a valid value for ResultType can be set, false otherwise. 683309124Sdimstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { 684309124Sdim if (!Key) 685309124Sdim return false; 686309124Sdim 687309124Sdim DWORD DumpType; 688309124Sdim DWORD TypeSize = sizeof(DumpType); 689309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, 690309124Sdim NULL, &DumpType, 691309124Sdim &TypeSize)) 692309124Sdim return false; 693309124Sdim 694309124Sdim switch (DumpType) { 695309124Sdim case 0: { 696309124Sdim DWORD Flags = 0; 697309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", 698309124Sdim RRF_RT_REG_DWORD, NULL, &Flags, 699309124Sdim &TypeSize)) 700309124Sdim return false; 701309124Sdim 702309124Sdim ResultType = static_cast<MINIDUMP_TYPE>(Flags); 703309124Sdim break; 704309124Sdim } 705309124Sdim case 1: 706309124Sdim ResultType = MiniDumpNormal; 707309124Sdim break; 708309124Sdim case 2: 709309124Sdim ResultType = MiniDumpWithFullMemory; 710309124Sdim break; 711309124Sdim default: 712309124Sdim return false; 713309124Sdim } 714309124Sdim return true; 715309124Sdim} 716309124Sdim 717341825Sdim/// Write a Windows dump file containing process information that can be 718309124Sdim/// used for post-mortem debugging. 719309124Sdim/// 720309124Sdim/// \returns zero error code if a mini dump created, actual error code 721309124Sdim/// otherwise. 722309124Sdimstatic std::error_code WINAPI 723309124SdimWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { 724309124Sdim using namespace llvm; 725309124Sdim using namespace llvm::sys; 726309124Sdim 727309124Sdim std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); 728309124Sdim StringRef ProgramName; 729309124Sdim 730309124Sdim if (MainExecutableName.empty()) { 731309124Sdim // If we can't get the executable filename, 732309124Sdim // things are in worse shape than we realize 733309124Sdim // and we should just bail out. 734309124Sdim return mapWindowsError(::GetLastError()); 735309124Sdim } 736309124Sdim 737309124Sdim ProgramName = path::filename(MainExecutableName.c_str()); 738309124Sdim 739309124Sdim // The Windows Registry location as specified at 740309124Sdim // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx 741309124Sdim // "Collecting User-Mode Dumps" that may optionally be set to collect crash 742309124Sdim // dumps in a specified location. 743309124Sdim StringRef LocalDumpsRegistryLocation = 744309124Sdim "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; 745309124Sdim 746309124Sdim // The key pointing to the Registry location that may contain global crash 747309124Sdim // dump settings. This will be NULL if the location can not be found. 748309124Sdim ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); 749309124Sdim 750309124Sdim // The key pointing to the Registry location that may contain 751309124Sdim // application-specific crash dump settings. This will be NULL if the 752309124Sdim // location can not be found. 753309124Sdim ScopedRegHandle AppSpecificKey( 754309124Sdim FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); 755309124Sdim 756309124Sdim // Look to see if a dump type is specified in the registry; first with the 757309124Sdim // app-specific key and failing that with the global key. If none are found 758309124Sdim // default to a normal dump (GetDumpType will return false either if the key 759309124Sdim // is NULL or if there is no valid DumpType value at its location). 760309124Sdim MINIDUMP_TYPE DumpType; 761309124Sdim if (!GetDumpType(AppSpecificKey, DumpType)) 762309124Sdim if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) 763309124Sdim DumpType = MiniDumpNormal; 764309124Sdim 765309124Sdim // Look to see if a dump location is specified in the registry; first with the 766309124Sdim // app-specific key and failing that with the global key. If none are found 767309124Sdim // we'll just create the dump file in the default temporary file location 768309124Sdim // (GetDumpFolder will return false either if the key is NULL or if there is 769309124Sdim // no valid DumpFolder value at its location). 770309124Sdim bool ExplicitDumpDirectorySet = true; 771309124Sdim SmallString<MAX_PATH> DumpDirectory; 772309124Sdim if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) 773309124Sdim if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) 774309124Sdim ExplicitDumpDirectorySet = false; 775309124Sdim 776309124Sdim int FD; 777309124Sdim SmallString<MAX_PATH> DumpPath; 778309124Sdim 779309124Sdim if (ExplicitDumpDirectorySet) { 780309124Sdim if (std::error_code EC = fs::create_directories(DumpDirectory)) 781309124Sdim return EC; 782309124Sdim if (std::error_code EC = fs::createUniqueFile( 783309124Sdim Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, 784309124Sdim DumpPath)) 785309124Sdim return EC; 786309124Sdim } else if (std::error_code EC = 787309124Sdim fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) 788309124Sdim return EC; 789309124Sdim 790309124Sdim // Our support functions return a file descriptor but Windows wants a handle. 791309124Sdim ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); 792309124Sdim 793309124Sdim if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), 794309124Sdim FileHandle, DumpType, ExceptionInfo, NULL, NULL)) 795309124Sdim return mapWindowsError(::GetLastError()); 796309124Sdim 797309124Sdim llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; 798309124Sdim return std::error_code(); 799309124Sdim} 800309124Sdim 801360784Sdimvoid sys::CleanupOnSignal(uintptr_t Context) { 802360784Sdim LLVMUnhandledExceptionFilter((LPEXCEPTION_POINTERS)Context); 803360784Sdim} 804360784Sdim 805218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 806218885Sdim Cleanup(); 807218885Sdim 808309124Sdim // We'll automatically write a Minidump file here to help diagnose 809309124Sdim // the nasty sorts of crashes that aren't 100% reproducible from a set of 810309124Sdim // inputs (or in the event that the user is unable or unwilling to provide a 811309124Sdim // reproducible case). 812321369Sdim if (!llvm::sys::Process::AreCoreFilesPrevented()) { 813309124Sdim MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; 814309124Sdim ExceptionInfo.ThreadId = ::GetCurrentThreadId(); 815309124Sdim ExceptionInfo.ExceptionPointers = ep; 816309124Sdim ExceptionInfo.ClientPointers = FALSE; 817309124Sdim 818309124Sdim if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) 819309124Sdim llvm::errs() << "Could not write crash dump file: " << EC.message() 820309124Sdim << "\n"; 821309124Sdim } 822309124Sdim 823360784Sdim // Stack unwinding appears to modify the context. Copy it to preserve the 824360784Sdim // caller's context. 825360784Sdim CONTEXT ContextCopy; 826360784Sdim if (ep) 827360784Sdim memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); 828218885Sdim 829360784Sdim LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); 830218885Sdim 831360784Sdim return EXCEPTION_EXECUTE_HANDLER; 832218885Sdim} 833218885Sdim 834218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 835218885Sdim // We are running in our very own thread, courtesy of Windows. 836218885Sdim EnterCriticalSection(&CriticalSection); 837218885Sdim Cleanup(); 838218885Sdim 839218885Sdim // If an interrupt function has been set, go and run one it; otherwise, 840218885Sdim // the process dies. 841218885Sdim void (*IF)() = InterruptFunction; 842218885Sdim InterruptFunction = 0; // Don't run it on another CTRL-C. 843218885Sdim 844218885Sdim if (IF) { 845218885Sdim // Note: if the interrupt function throws an exception, there is nothing 846218885Sdim // to catch it in this thread so it will kill the process. 847218885Sdim IF(); // Run it now. 848218885Sdim LeaveCriticalSection(&CriticalSection); 849218885Sdim return TRUE; // Don't kill the process. 850218885Sdim } 851218885Sdim 852218885Sdim // Allow normal processing to take place; i.e., the process dies. 853218885Sdim LeaveCriticalSection(&CriticalSection); 854218885Sdim return FALSE; 855218885Sdim} 856226633Sdim 857226633Sdim#if __MINGW32__ 858226633Sdim // We turned these warnings off for this file so that MinGW-g++ doesn't 859226633Sdim // complain about the ll format specifiers used. Now we are turning the 860226633Sdim // warnings back on. If MinGW starts to support diagnostic stacks, we can 861226633Sdim // replace this with a pop. 862226633Sdim #pragma GCC diagnostic warning "-Wformat" 863226633Sdim #pragma GCC diagnostic warning "-Wformat-extra-args" 864226633Sdim#endif 865