Signals.inc revision 321369
1218885Sdim//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file provides the Win32 specific implementation of the Signals class. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 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. 26276479Sdim#include "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__ 39288943Sdim #if (HAVE_LIBPSAPI != 1) 40288943Sdim #error "libpsapi.a should be present" 41218885Sdim #endif 42226633Sdim // The version of g++ that comes with MinGW does *not* properly understand 43226633Sdim // the ll format specifier for printf. However, MinGW passes the format 44226633Sdim // specifiers on to the MSVCRT entirely, and the CRT understands the ll 45226633Sdim // specifier. So these warnings are spurious in this case. Since we compile 46226633Sdim // with -Wall, this will generate these warnings which should be ignored. So 47226633Sdim // we will turn off the warnings for this just file. However, MinGW also does 48226633Sdim // not support push and pop for diagnostics, so we have to manually turn it 49226633Sdim // back on at the end of the file. 50226633Sdim #pragma GCC diagnostic ignored "-Wformat" 51226633Sdim #pragma GCC diagnostic ignored "-Wformat-extra-args" 52218885Sdim 53226633Sdim #if !defined(__MINGW64_VERSION_MAJOR) 54226633Sdim // MinGW.org does not have updated support for the 64-bit versions of the 55226633Sdim // DebugHlp APIs. So we will have to load them manually. The structures and 56226633Sdim // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 57226633Sdim // and adjusted for brevity. 58226633Sdim typedef struct _IMAGEHLP_LINE64 { 59226633Sdim DWORD SizeOfStruct; 60226633Sdim PVOID Key; 61226633Sdim DWORD LineNumber; 62226633Sdim PCHAR FileName; 63226633Sdim DWORD64 Address; 64226633Sdim } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 65226633Sdim 66226633Sdim typedef struct _IMAGEHLP_SYMBOL64 { 67226633Sdim DWORD SizeOfStruct; 68226633Sdim DWORD64 Address; 69226633Sdim DWORD Size; 70226633Sdim DWORD Flags; 71226633Sdim DWORD MaxNameLength; 72226633Sdim CHAR Name[1]; 73226633Sdim } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 74226633Sdim 75226633Sdim typedef struct _tagADDRESS64 { 76226633Sdim DWORD64 Offset; 77226633Sdim WORD Segment; 78226633Sdim ADDRESS_MODE Mode; 79226633Sdim } ADDRESS64, *LPADDRESS64; 80226633Sdim 81226633Sdim typedef struct _KDHELP64 { 82226633Sdim DWORD64 Thread; 83226633Sdim DWORD ThCallbackStack; 84226633Sdim DWORD ThCallbackBStore; 85226633Sdim DWORD NextCallback; 86226633Sdim DWORD FramePointer; 87226633Sdim DWORD64 KiCallUserMode; 88226633Sdim DWORD64 KeUserCallbackDispatcher; 89226633Sdim DWORD64 SystemRangeStart; 90226633Sdim DWORD64 KiUserExceptionDispatcher; 91226633Sdim DWORD64 StackBase; 92226633Sdim DWORD64 StackLimit; 93226633Sdim DWORD64 Reserved[5]; 94226633Sdim } KDHELP64, *PKDHELP64; 95226633Sdim 96226633Sdim typedef struct _tagSTACKFRAME64 { 97226633Sdim ADDRESS64 AddrPC; 98226633Sdim ADDRESS64 AddrReturn; 99226633Sdim ADDRESS64 AddrFrame; 100226633Sdim ADDRESS64 AddrStack; 101226633Sdim ADDRESS64 AddrBStore; 102226633Sdim PVOID FuncTableEntry; 103226633Sdim DWORD64 Params[4]; 104226633Sdim BOOL Far; 105226633Sdim BOOL Virtual; 106226633Sdim DWORD64 Reserved[3]; 107226633Sdim KDHELP64 KdHelp; 108226633Sdim } STACKFRAME64, *LPSTACKFRAME64; 109288943Sdim #endif // !defined(__MINGW64_VERSION_MAJOR) 110288943Sdim#endif // __MINGW32__ 111226633Sdim 112226633Sdimtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, 113226633Sdim DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 114226633Sdim LPDWORD lpNumberOfBytesRead); 115226633Sdim 116226633Sdimtypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, 117226633Sdim DWORD64 AddrBase); 118226633Sdim 119226633Sdimtypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 120226633Sdim DWORD64 Address); 121226633Sdim 122226633Sdimtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 123226633Sdim HANDLE hThread, LPADDRESS64 lpaddr); 124226633Sdim 125309124Sdimtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, 126309124Sdim PMINIDUMP_EXCEPTION_INFORMATION, 127309124Sdim PMINIDUMP_USER_STREAM_INFORMATION, 128309124Sdim PMINIDUMP_CALLBACK_INFORMATION); 129309124Sdimstatic fpMiniDumpWriteDump fMiniDumpWriteDump; 130309124Sdim 131226633Sdimtypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 132226633Sdim PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 133226633Sdim PFUNCTION_TABLE_ACCESS_ROUTINE64, 134226633Sdim PGET_MODULE_BASE_ROUTINE64, 135226633Sdim PTRANSLATE_ADDRESS_ROUTINE64); 136288943Sdimstatic fpStackWalk64 fStackWalk64; 137226633Sdim 138226633Sdimtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 139288943Sdimstatic fpSymGetModuleBase64 fSymGetModuleBase64; 140226633Sdim 141226633Sdimtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, 142226633Sdim PDWORD64, PIMAGEHLP_SYMBOL64); 143288943Sdimstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64; 144226633Sdim 145226633Sdimtypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, 146226633Sdim PDWORD, PIMAGEHLP_LINE64); 147288943Sdimstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64; 148226633Sdim 149296417Sdimtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, 150296417Sdim PIMAGEHLP_MODULE64 ModuleInfo); 151296417Sdimstatic fpSymGetModuleInfo64 fSymGetModuleInfo64; 152296417Sdim 153226633Sdimtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 154288943Sdimstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64; 155226633Sdim 156288943Sdimtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD); 157288943Sdimstatic fpSymSetOptions fSymSetOptions; 158288943Sdim 159288943Sdimtypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); 160288943Sdimstatic fpSymInitialize fSymInitialize; 161288943Sdim 162296417Sdimtypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); 163296417Sdimstatic fpEnumerateLoadedModules fEnumerateLoadedModules; 164296417Sdim 165226633Sdimstatic bool load64BitDebugHelp(void) { 166261991Sdim HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 167226633Sdim if (hLib) { 168309124Sdim fMiniDumpWriteDump = (fpMiniDumpWriteDump) 169309124Sdim ::GetProcAddress(hLib, "MiniDumpWriteDump"); 170288943Sdim fStackWalk64 = (fpStackWalk64) 171226633Sdim ::GetProcAddress(hLib, "StackWalk64"); 172288943Sdim fSymGetModuleBase64 = (fpSymGetModuleBase64) 173226633Sdim ::GetProcAddress(hLib, "SymGetModuleBase64"); 174288943Sdim fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) 175226633Sdim ::GetProcAddress(hLib, "SymGetSymFromAddr64"); 176288943Sdim fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) 177226633Sdim ::GetProcAddress(hLib, "SymGetLineFromAddr64"); 178296417Sdim fSymGetModuleInfo64 = (fpSymGetModuleInfo64) 179296417Sdim ::GetProcAddress(hLib, "SymGetModuleInfo64"); 180288943Sdim fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) 181226633Sdim ::GetProcAddress(hLib, "SymFunctionTableAccess64"); 182288943Sdim fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); 183288943Sdim fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); 184296417Sdim fEnumerateLoadedModules = (fpEnumerateLoadedModules) 185296417Sdim ::GetProcAddress(hLib, "EnumerateLoadedModules64"); 186226633Sdim } 187309124Sdim return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; 188226633Sdim} 189226633Sdim 190296417Sdimusing namespace llvm; 191296417Sdim 192218885Sdim// Forward declare. 193218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 194218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 195218885Sdim 196218885Sdim// InterruptFunction - The function to call if ctrl-c is pressed. 197218885Sdimstatic void (*InterruptFunction)() = 0; 198218885Sdim 199261991Sdimstatic std::vector<std::string> *FilesToRemove = NULL; 200218885Sdimstatic bool RegisteredUnhandledExceptionFilter = false; 201218885Sdimstatic bool CleanupExecuted = false; 202218885Sdimstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 203218885Sdim 204218885Sdim// Windows creates a new thread to execute the console handler when an event 205218885Sdim// (such as CTRL/C) occurs. This causes concurrency issues with the above 206218885Sdim// globals which this critical section addresses. 207218885Sdimstatic CRITICAL_SECTION CriticalSection; 208288943Sdimstatic bool CriticalSectionInitialized = false; 209218885Sdim 210309124Sdimstatic StringRef Argv0; 211309124Sdim 212296417Sdimenum { 213288943Sdim#if defined(_M_X64) 214296417Sdim NativeMachineType = IMAGE_FILE_MACHINE_AMD64 215288943Sdim#else 216296417Sdim NativeMachineType = IMAGE_FILE_MACHINE_I386 217288943Sdim#endif 218296417Sdim}; 219288943Sdim 220296417Sdimstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, 221296417Sdim HANDLE hProcess, HANDLE hThread, 222296417Sdim STACKFRAME64 &StackFrameOrig, 223296417Sdim CONTEXT *ContextOrig) { 224296417Sdim // StackWalk64 modifies the incoming stack frame and context, so copy them. 225296417Sdim STACKFRAME64 StackFrame = StackFrameOrig; 226296417Sdim 227296417Sdim // Copy the register context so that we don't modify it while we unwind. We 228296417Sdim // could use InitializeContext + CopyContext, but that's only required to get 229296417Sdim // at AVX registers, which typically aren't needed by StackWalk64. Reduce the 230296417Sdim // flag set to indicate that there's less data. 231296417Sdim CONTEXT Context = *ContextOrig; 232296417Sdim Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; 233296417Sdim 234296417Sdim static void *StackTrace[256]; 235296417Sdim size_t Depth = 0; 236296417Sdim while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 237296417Sdim &Context, 0, fSymFunctionTableAccess64, 238296417Sdim fSymGetModuleBase64, 0)) { 239296417Sdim if (StackFrame.AddrFrame.Offset == 0) 240296417Sdim break; 241296417Sdim StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; 242296417Sdim if (Depth >= array_lengthof(StackTrace)) 243296417Sdim break; 244296417Sdim } 245296417Sdim 246309124Sdim return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); 247296417Sdim} 248296417Sdim 249296417Sdimnamespace { 250296417Sdimstruct FindModuleData { 251296417Sdim void **StackTrace; 252296417Sdim int Depth; 253296417Sdim const char **Modules; 254296417Sdim intptr_t *Offsets; 255296417Sdim StringSaver *StrPool; 256296417Sdim}; 257296417Sdim} 258296417Sdim 259309124Sdimstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName, 260296417Sdim DWORD64 ModuleBase, ULONG ModuleSize, 261296417Sdim void *VoidData) { 262296417Sdim FindModuleData *Data = (FindModuleData*)VoidData; 263296417Sdim intptr_t Beg = ModuleBase; 264296417Sdim intptr_t End = Beg + ModuleSize; 265296417Sdim for (int I = 0; I < Data->Depth; I++) { 266296417Sdim if (Data->Modules[I]) 267296417Sdim continue; 268296417Sdim intptr_t Addr = (intptr_t)Data->StackTrace[I]; 269296417Sdim if (Beg <= Addr && Addr < End) { 270314564Sdim Data->Modules[I] = Data->StrPool->save(ModuleName).data(); 271296417Sdim Data->Offsets[I] = Addr - Beg; 272296417Sdim } 273296417Sdim } 274296417Sdim return TRUE; 275296417Sdim} 276296417Sdim 277296417Sdimstatic bool findModulesAndOffsets(void **StackTrace, int Depth, 278296417Sdim const char **Modules, intptr_t *Offsets, 279296417Sdim const char *MainExecutableName, 280296417Sdim StringSaver &StrPool) { 281296417Sdim if (!fEnumerateLoadedModules) 282296417Sdim return false; 283296417Sdim FindModuleData Data; 284296417Sdim Data.StackTrace = StackTrace; 285296417Sdim Data.Depth = Depth; 286296417Sdim Data.Modules = Modules; 287296417Sdim Data.Offsets = Offsets; 288296417Sdim Data.StrPool = &StrPool; 289296417Sdim fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); 290296417Sdim return true; 291296417Sdim} 292296417Sdim 293296417Sdimstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, 294296417Sdim HANDLE hThread, STACKFRAME64 &StackFrame, 295296417Sdim CONTEXT *Context) { 296288943Sdim // Initialize the symbol handler. 297288943Sdim fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); 298288943Sdim fSymInitialize(hProcess, NULL, TRUE); 299288943Sdim 300296417Sdim // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs 301296417Sdim // and DWARF, so it should do a good job regardless of what debug info or 302296417Sdim // linker is in use. 303296417Sdim if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, 304296417Sdim Context)) { 305296417Sdim return; 306296417Sdim } 307296417Sdim 308288943Sdim while (true) { 309296417Sdim if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 310296417Sdim Context, 0, fSymFunctionTableAccess64, 311296417Sdim fSymGetModuleBase64, 0)) { 312288943Sdim break; 313288943Sdim } 314288943Sdim 315288943Sdim if (StackFrame.AddrFrame.Offset == 0) 316288943Sdim break; 317288943Sdim 318288943Sdim using namespace llvm; 319288943Sdim // Print the PC in hexadecimal. 320288943Sdim DWORD64 PC = StackFrame.AddrPC.Offset; 321288943Sdim#if defined(_M_X64) 322288943Sdim OS << format("0x%016llX", PC); 323288943Sdim#elif defined(_M_IX86) 324288943Sdim OS << format("0x%08lX", static_cast<DWORD>(PC)); 325288943Sdim#endif 326288943Sdim 327288943Sdim// Print the parameters. Assume there are four. 328288943Sdim#if defined(_M_X64) 329288943Sdim OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", 330288943Sdim StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], 331288943Sdim StackFrame.Params[3]); 332288943Sdim#elif defined(_M_IX86) 333288943Sdim OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", 334288943Sdim static_cast<DWORD>(StackFrame.Params[0]), 335288943Sdim static_cast<DWORD>(StackFrame.Params[1]), 336288943Sdim static_cast<DWORD>(StackFrame.Params[2]), 337288943Sdim static_cast<DWORD>(StackFrame.Params[3])); 338288943Sdim#endif 339288943Sdim // Verify the PC belongs to a module in this process. 340288943Sdim if (!fSymGetModuleBase64(hProcess, PC)) { 341288943Sdim OS << " <unknown module>\n"; 342288943Sdim continue; 343288943Sdim } 344288943Sdim 345288943Sdim // Print the symbol name. 346288943Sdim char buffer[512]; 347288943Sdim IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 348288943Sdim memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 349288943Sdim symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 350288943Sdim symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 351288943Sdim 352288943Sdim DWORD64 dwDisp; 353288943Sdim if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 354288943Sdim OS << '\n'; 355288943Sdim continue; 356288943Sdim } 357288943Sdim 358288943Sdim buffer[511] = 0; 359288943Sdim if (dwDisp > 0) 360288943Sdim OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, 361288943Sdim dwDisp); 362288943Sdim else 363288943Sdim OS << format(", %s", (const char*)symbol->Name); 364288943Sdim 365288943Sdim // Print the source file and line number information. 366288943Sdim IMAGEHLP_LINE64 line = {}; 367288943Sdim DWORD dwLineDisp; 368288943Sdim line.SizeOfStruct = sizeof(line); 369288943Sdim if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 370288943Sdim OS << format(", %s, line %lu", line.FileName, line.LineNumber); 371288943Sdim if (dwLineDisp > 0) 372288943Sdim OS << format(" + 0x%lX byte(s)", dwLineDisp); 373288943Sdim } 374288943Sdim 375288943Sdim OS << '\n'; 376288943Sdim } 377288943Sdim} 378288943Sdim 379218885Sdimnamespace llvm { 380218885Sdim 381218885Sdim//===----------------------------------------------------------------------===// 382218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code 383218885Sdim//=== and must not be UNIX code 384218885Sdim//===----------------------------------------------------------------------===// 385218885Sdim 386218885Sdim#ifdef _MSC_VER 387251662Sdim/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, 388251662Sdim/// ignore" CRT debug report dialog. "retry" raises an exception which 389251662Sdim/// ultimately triggers our stack dumper. 390288943Sdimstatic LLVM_ATTRIBUTE_UNUSED int 391288943SdimAvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 392251662Sdim // Set *Return to the retry code for the return value of _CrtDbgReport: 393251662Sdim // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 394251662Sdim // This may also trigger just-in-time debugging via DebugBreak(). 395251662Sdim if (Return) 396251662Sdim *Return = 1; 397251662Sdim // Don't call _CrtDbgReport. 398251662Sdim return TRUE; 399251662Sdim} 400251662Sdim 401218885Sdim#endif 402218885Sdim 403288943Sdimextern "C" void HandleAbort(int Sig) { 404288943Sdim if (Sig == SIGABRT) { 405288943Sdim LLVM_BUILTIN_TRAP; 406288943Sdim } 407288943Sdim} 408288943Sdim 409288943Sdimstatic void InitializeThreading() { 410288943Sdim if (CriticalSectionInitialized) 411288943Sdim return; 412288943Sdim 413288943Sdim // Now's the time to create the critical section. This is the first time 414288943Sdim // through here, and there's only one thread. 415288943Sdim InitializeCriticalSection(&CriticalSection); 416288943Sdim CriticalSectionInitialized = true; 417288943Sdim} 418288943Sdim 419218885Sdimstatic void RegisterHandler() { 420288943Sdim // If we cannot load up the APIs (which would be unexpected as they should 421288943Sdim // exist on every version of Windows we support), we will bail out since 422288943Sdim // there would be nothing to report. 423226633Sdim if (!load64BitDebugHelp()) { 424226633Sdim assert(false && "These APIs should always be available"); 425226633Sdim return; 426226633Sdim } 427226633Sdim 428218885Sdim if (RegisteredUnhandledExceptionFilter) { 429218885Sdim EnterCriticalSection(&CriticalSection); 430218885Sdim return; 431218885Sdim } 432218885Sdim 433288943Sdim InitializeThreading(); 434218885Sdim 435218885Sdim // Enter it immediately. Now if someone hits CTRL/C, the console handler 436218885Sdim // can't proceed until the globals are updated. 437218885Sdim EnterCriticalSection(&CriticalSection); 438218885Sdim 439218885Sdim RegisteredUnhandledExceptionFilter = true; 440218885Sdim OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 441218885Sdim SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 442218885Sdim 443218885Sdim // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 444218885Sdim // else multi-threading problems will ensue. 445218885Sdim} 446218885Sdim 447218885Sdim// RemoveFileOnSignal - The public API 448261991Sdimbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { 449218885Sdim RegisterHandler(); 450218885Sdim 451218885Sdim if (CleanupExecuted) { 452218885Sdim if (ErrMsg) 453218885Sdim *ErrMsg = "Process terminating -- cannot register for removal"; 454218885Sdim return true; 455218885Sdim } 456218885Sdim 457218885Sdim if (FilesToRemove == NULL) 458261991Sdim FilesToRemove = new std::vector<std::string>; 459218885Sdim 460218885Sdim FilesToRemove->push_back(Filename); 461218885Sdim 462218885Sdim LeaveCriticalSection(&CriticalSection); 463218885Sdim return false; 464218885Sdim} 465218885Sdim 466218885Sdim// DontRemoveFileOnSignal - The public API 467261991Sdimvoid sys::DontRemoveFileOnSignal(StringRef Filename) { 468218885Sdim if (FilesToRemove == NULL) 469218885Sdim return; 470218885Sdim 471218885Sdim RegisterHandler(); 472218885Sdim 473261991Sdim std::vector<std::string>::reverse_iterator I = 474314564Sdim find(reverse(*FilesToRemove), Filename); 475218885Sdim if (I != FilesToRemove->rend()) 476218885Sdim FilesToRemove->erase(I.base()-1); 477218885Sdim 478218885Sdim LeaveCriticalSection(&CriticalSection); 479218885Sdim} 480218885Sdim 481288943Sdimvoid sys::DisableSystemDialogsOnCrash() { 482288943Sdim // Crash to stack trace handler on abort. 483288943Sdim signal(SIGABRT, HandleAbort); 484288943Sdim 485288943Sdim // The following functions are not reliably accessible on MinGW. 486288943Sdim#ifdef _MSC_VER 487288943Sdim // We're already handling writing a "something went wrong" message. 488288943Sdim _set_abort_behavior(0, _WRITE_ABORT_MSG); 489288943Sdim // Disable Dr. Watson. 490288943Sdim _set_abort_behavior(0, _CALL_REPORTFAULT); 491288943Sdim _CrtSetReportHook(AvoidMessageBoxHook); 492288943Sdim#endif 493288943Sdim 494288943Sdim // Disable standard error dialog box. 495288943Sdim SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 496288943Sdim SEM_NOOPENFILEERRORBOX); 497288943Sdim _set_error_mode(_OUT_TO_STDERR); 498288943Sdim} 499288943Sdim 500218885Sdim/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 501218885Sdim/// SIGSEGV) is delivered to the process, print a stack trace and then exit. 502309124Sdimvoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0, 503309124Sdim bool DisableCrashReporting) { 504309124Sdim ::Argv0 = Argv0; 505309124Sdim 506309124Sdim if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) 507309124Sdim Process::PreventCoreFiles(); 508309124Sdim 509288943Sdim DisableSystemDialogsOnCrash(); 510218885Sdim RegisterHandler(); 511218885Sdim LeaveCriticalSection(&CriticalSection); 512218885Sdim} 513288943Sdim} 514218885Sdim 515288943Sdim#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 516288943Sdim// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is 517288943Sdim// missing it but mingw-w64 has it. 518288943Sdimextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); 519288943Sdim#endif 520288943Sdim 521288943Sdimvoid llvm::sys::PrintStackTrace(raw_ostream &OS) { 522288943Sdim STACKFRAME64 StackFrame = {}; 523288943Sdim CONTEXT Context = {}; 524288943Sdim ::RtlCaptureContext(&Context); 525288943Sdim#if defined(_M_X64) 526288943Sdim StackFrame.AddrPC.Offset = Context.Rip; 527288943Sdim StackFrame.AddrStack.Offset = Context.Rsp; 528288943Sdim StackFrame.AddrFrame.Offset = Context.Rbp; 529288943Sdim#else 530288943Sdim StackFrame.AddrPC.Offset = Context.Eip; 531288943Sdim StackFrame.AddrStack.Offset = Context.Esp; 532288943Sdim StackFrame.AddrFrame.Offset = Context.Ebp; 533288943Sdim#endif 534288943Sdim StackFrame.AddrPC.Mode = AddrModeFlat; 535288943Sdim StackFrame.AddrStack.Mode = AddrModeFlat; 536288943Sdim StackFrame.AddrFrame.Mode = AddrModeFlat; 537288943Sdim PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), 538288943Sdim StackFrame, &Context); 539249423Sdim} 540218885Sdim 541249423Sdim 542288943Sdimvoid llvm::sys::SetInterruptFunction(void (*IF)()) { 543218885Sdim RegisterHandler(); 544218885Sdim InterruptFunction = IF; 545218885Sdim LeaveCriticalSection(&CriticalSection); 546218885Sdim} 547218885Sdim 548218885Sdim 549218885Sdim/// AddSignalHandler - Add a function to be called when a signal is delivered 550218885Sdim/// to the process. The handler can have a cookie passed to it to identify 551218885Sdim/// what instance of the handler it is. 552288943Sdimvoid llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { 553218885Sdim CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); 554218885Sdim RegisterHandler(); 555218885Sdim LeaveCriticalSection(&CriticalSection); 556218885Sdim} 557218885Sdim 558218885Sdimstatic void Cleanup() { 559288943Sdim if (CleanupExecuted) 560288943Sdim return; 561288943Sdim 562218885Sdim EnterCriticalSection(&CriticalSection); 563218885Sdim 564218885Sdim // Prevent other thread from registering new files and directories for 565218885Sdim // removal, should we be executing because of the console handler callback. 566218885Sdim CleanupExecuted = true; 567218885Sdim 568218885Sdim // FIXME: open files cannot be deleted. 569218885Sdim if (FilesToRemove != NULL) 570218885Sdim while (!FilesToRemove->empty()) { 571276479Sdim llvm::sys::fs::remove(FilesToRemove->back()); 572218885Sdim FilesToRemove->pop_back(); 573218885Sdim } 574296417Sdim llvm::sys::RunSignalHandlers(); 575218885Sdim LeaveCriticalSection(&CriticalSection); 576218885Sdim} 577218885Sdim 578218885Sdimvoid llvm::sys::RunInterruptHandlers() { 579288943Sdim // The interrupt handler may be called from an interrupt, but it may also be 580288943Sdim // called manually (such as the case of report_fatal_error with no registered 581288943Sdim // error handler). We must ensure that the critical section is properly 582288943Sdim // initialized. 583288943Sdim InitializeThreading(); 584218885Sdim Cleanup(); 585218885Sdim} 586218885Sdim 587309124Sdim/// \brief Find the Windows Registry Key for a given location. 588309124Sdim/// 589309124Sdim/// \returns a valid HKEY if the location exists, else NULL. 590309124Sdimstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) { 591309124Sdim HKEY Key; 592309124Sdim if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, 593309124Sdim RegistryLocation.str().c_str(), 0, 594309124Sdim KEY_QUERY_VALUE | KEY_READ, &Key)) 595309124Sdim return NULL; 596309124Sdim 597309124Sdim return Key; 598309124Sdim} 599309124Sdim 600309124Sdim/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given 601309124Sdim/// Windows Registry key. 602309124Sdim/// 603309124Sdim/// \returns true if a valid value for DumpFolder exists, false otherwise. 604309124Sdimstatic bool GetDumpFolder(HKEY Key, 605309124Sdim llvm::SmallVectorImpl<char> &ResultDirectory) { 606309124Sdim using llvm::sys::windows::UTF16ToUTF8; 607309124Sdim 608309124Sdim if (!Key) 609309124Sdim return false; 610309124Sdim 611309124Sdim DWORD BufferLengthBytes = 0; 612309124Sdim 613309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 614309124Sdim NULL, NULL, &BufferLengthBytes)) 615309124Sdim return false; 616309124Sdim 617309124Sdim SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); 618309124Sdim 619309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 620309124Sdim NULL, Buffer.data(), &BufferLengthBytes)) 621309124Sdim return false; 622309124Sdim 623309124Sdim DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); 624309124Sdim 625309124Sdim if (!ExpandBufferSize) 626309124Sdim return false; 627309124Sdim 628309124Sdim SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); 629309124Sdim 630309124Sdim if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), 631309124Sdim ExpandBuffer.data(), 632309124Sdim ExpandBufferSize)) 633309124Sdim return false; 634309124Sdim 635309124Sdim if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) 636309124Sdim return false; 637309124Sdim 638309124Sdim return true; 639309124Sdim} 640309124Sdim 641309124Sdim/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of 642309124Sdim/// "DumpType" for a given Windows Registry key. 643309124Sdim/// 644309124Sdim/// According to 645309124Sdim/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx 646309124Sdim/// valid values for DumpType are: 647309124Sdim/// * 0: Custom dump 648309124Sdim/// * 1: Mini dump 649309124Sdim/// * 2: Full dump 650309124Sdim/// If "Custom dump" is specified then the "CustomDumpFlags" field is read 651309124Sdim/// containing a bitwise combination of MINIDUMP_TYPE values. 652309124Sdim/// 653309124Sdim/// \returns true if a valid value for ResultType can be set, false otherwise. 654309124Sdimstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { 655309124Sdim if (!Key) 656309124Sdim return false; 657309124Sdim 658309124Sdim DWORD DumpType; 659309124Sdim DWORD TypeSize = sizeof(DumpType); 660309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, 661309124Sdim NULL, &DumpType, 662309124Sdim &TypeSize)) 663309124Sdim return false; 664309124Sdim 665309124Sdim switch (DumpType) { 666309124Sdim case 0: { 667309124Sdim DWORD Flags = 0; 668309124Sdim if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", 669309124Sdim RRF_RT_REG_DWORD, NULL, &Flags, 670309124Sdim &TypeSize)) 671309124Sdim return false; 672309124Sdim 673309124Sdim ResultType = static_cast<MINIDUMP_TYPE>(Flags); 674309124Sdim break; 675309124Sdim } 676309124Sdim case 1: 677309124Sdim ResultType = MiniDumpNormal; 678309124Sdim break; 679309124Sdim case 2: 680309124Sdim ResultType = MiniDumpWithFullMemory; 681309124Sdim break; 682309124Sdim default: 683309124Sdim return false; 684309124Sdim } 685309124Sdim return true; 686309124Sdim} 687309124Sdim 688309124Sdim/// \brief Write a Windows dump file containing process information that can be 689309124Sdim/// used for post-mortem debugging. 690309124Sdim/// 691309124Sdim/// \returns zero error code if a mini dump created, actual error code 692309124Sdim/// otherwise. 693309124Sdimstatic std::error_code WINAPI 694309124SdimWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { 695309124Sdim using namespace llvm; 696309124Sdim using namespace llvm::sys; 697309124Sdim 698309124Sdim std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); 699309124Sdim StringRef ProgramName; 700309124Sdim 701309124Sdim if (MainExecutableName.empty()) { 702309124Sdim // If we can't get the executable filename, 703309124Sdim // things are in worse shape than we realize 704309124Sdim // and we should just bail out. 705309124Sdim return mapWindowsError(::GetLastError()); 706309124Sdim } 707309124Sdim 708309124Sdim ProgramName = path::filename(MainExecutableName.c_str()); 709309124Sdim 710309124Sdim // The Windows Registry location as specified at 711309124Sdim // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx 712309124Sdim // "Collecting User-Mode Dumps" that may optionally be set to collect crash 713309124Sdim // dumps in a specified location. 714309124Sdim StringRef LocalDumpsRegistryLocation = 715309124Sdim "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; 716309124Sdim 717309124Sdim // The key pointing to the Registry location that may contain global crash 718309124Sdim // dump settings. This will be NULL if the location can not be found. 719309124Sdim ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); 720309124Sdim 721309124Sdim // The key pointing to the Registry location that may contain 722309124Sdim // application-specific crash dump settings. This will be NULL if the 723309124Sdim // location can not be found. 724309124Sdim ScopedRegHandle AppSpecificKey( 725309124Sdim FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); 726309124Sdim 727309124Sdim // Look to see if a dump type is specified in the registry; first with the 728309124Sdim // app-specific key and failing that with the global key. If none are found 729309124Sdim // default to a normal dump (GetDumpType will return false either if the key 730309124Sdim // is NULL or if there is no valid DumpType value at its location). 731309124Sdim MINIDUMP_TYPE DumpType; 732309124Sdim if (!GetDumpType(AppSpecificKey, DumpType)) 733309124Sdim if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) 734309124Sdim DumpType = MiniDumpNormal; 735309124Sdim 736309124Sdim // Look to see if a dump location is specified in the registry; first with the 737309124Sdim // app-specific key and failing that with the global key. If none are found 738309124Sdim // we'll just create the dump file in the default temporary file location 739309124Sdim // (GetDumpFolder will return false either if the key is NULL or if there is 740309124Sdim // no valid DumpFolder value at its location). 741309124Sdim bool ExplicitDumpDirectorySet = true; 742309124Sdim SmallString<MAX_PATH> DumpDirectory; 743309124Sdim if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) 744309124Sdim if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) 745309124Sdim ExplicitDumpDirectorySet = false; 746309124Sdim 747309124Sdim int FD; 748309124Sdim SmallString<MAX_PATH> DumpPath; 749309124Sdim 750309124Sdim if (ExplicitDumpDirectorySet) { 751309124Sdim if (std::error_code EC = fs::create_directories(DumpDirectory)) 752309124Sdim return EC; 753309124Sdim if (std::error_code EC = fs::createUniqueFile( 754309124Sdim Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, 755309124Sdim DumpPath)) 756309124Sdim return EC; 757309124Sdim } else if (std::error_code EC = 758309124Sdim fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) 759309124Sdim return EC; 760309124Sdim 761309124Sdim // Our support functions return a file descriptor but Windows wants a handle. 762309124Sdim ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); 763309124Sdim 764309124Sdim if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), 765309124Sdim FileHandle, DumpType, ExceptionInfo, NULL, NULL)) 766309124Sdim return mapWindowsError(::GetLastError()); 767309124Sdim 768309124Sdim llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; 769309124Sdim return std::error_code(); 770309124Sdim} 771309124Sdim 772218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 773218885Sdim Cleanup(); 774218885Sdim 775309124Sdim // We'll automatically write a Minidump file here to help diagnose 776309124Sdim // the nasty sorts of crashes that aren't 100% reproducible from a set of 777309124Sdim // inputs (or in the event that the user is unable or unwilling to provide a 778309124Sdim // reproducible case). 779321369Sdim if (!llvm::sys::Process::AreCoreFilesPrevented()) { 780309124Sdim MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; 781309124Sdim ExceptionInfo.ThreadId = ::GetCurrentThreadId(); 782309124Sdim ExceptionInfo.ExceptionPointers = ep; 783309124Sdim ExceptionInfo.ClientPointers = FALSE; 784309124Sdim 785309124Sdim if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) 786309124Sdim llvm::errs() << "Could not write crash dump file: " << EC.message() 787309124Sdim << "\n"; 788309124Sdim } 789309124Sdim 790218885Sdim // Initialize the STACKFRAME structure. 791288943Sdim STACKFRAME64 StackFrame = {}; 792218885Sdim 793226633Sdim#if defined(_M_X64) 794226633Sdim StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; 795226633Sdim StackFrame.AddrPC.Mode = AddrModeFlat; 796226633Sdim StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; 797226633Sdim StackFrame.AddrStack.Mode = AddrModeFlat; 798226633Sdim StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; 799226633Sdim StackFrame.AddrFrame.Mode = AddrModeFlat; 800226633Sdim#elif defined(_M_IX86) 801218885Sdim StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 802218885Sdim StackFrame.AddrPC.Mode = AddrModeFlat; 803218885Sdim StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 804218885Sdim StackFrame.AddrStack.Mode = AddrModeFlat; 805218885Sdim StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 806218885Sdim StackFrame.AddrFrame.Mode = AddrModeFlat; 807226633Sdim#endif 808218885Sdim 809218885Sdim HANDLE hProcess = GetCurrentProcess(); 810218885Sdim HANDLE hThread = GetCurrentThread(); 811288943Sdim PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, 812288943Sdim ep->ContextRecord); 813218885Sdim 814288943Sdim _exit(ep->ExceptionRecord->ExceptionCode); 815218885Sdim} 816218885Sdim 817218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 818218885Sdim // We are running in our very own thread, courtesy of Windows. 819218885Sdim EnterCriticalSection(&CriticalSection); 820218885Sdim Cleanup(); 821218885Sdim 822218885Sdim // If an interrupt function has been set, go and run one it; otherwise, 823218885Sdim // the process dies. 824218885Sdim void (*IF)() = InterruptFunction; 825218885Sdim InterruptFunction = 0; // Don't run it on another CTRL-C. 826218885Sdim 827218885Sdim if (IF) { 828218885Sdim // Note: if the interrupt function throws an exception, there is nothing 829218885Sdim // to catch it in this thread so it will kill the process. 830218885Sdim IF(); // Run it now. 831218885Sdim LeaveCriticalSection(&CriticalSection); 832218885Sdim return TRUE; // Don't kill the process. 833218885Sdim } 834218885Sdim 835218885Sdim // Allow normal processing to take place; i.e., the process dies. 836218885Sdim LeaveCriticalSection(&CriticalSection); 837218885Sdim return FALSE; 838218885Sdim} 839226633Sdim 840226633Sdim#if __MINGW32__ 841226633Sdim // We turned these warnings off for this file so that MinGW-g++ doesn't 842226633Sdim // complain about the ll format specifiers used. Now we are turning the 843226633Sdim // warnings back on. If MinGW starts to support diagnostic stacks, we can 844226633Sdim // replace this with a pop. 845226633Sdim #pragma GCC diagnostic warning "-Wformat" 846226633Sdim #pragma GCC diagnostic warning "-Wformat-extra-args" 847226633Sdim#endif 848