Signals.inc revision 309124
125537Sdfr//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 225537Sdfr// 325537Sdfr// The LLVM Compiler Infrastructure 425537Sdfr// 525537Sdfr// This file is distributed under the University of Illinois Open Source 625537Sdfr// License. See LICENSE.TXT for details. 725537Sdfr// 825537Sdfr//===----------------------------------------------------------------------===// 925537Sdfr// 1025537Sdfr// This file provides the Win32 specific implementation of the Signals class. 1125537Sdfr// 1225537Sdfr//===----------------------------------------------------------------------===// 1325537Sdfr#include "llvm/Support/FileSystem.h" 1425537Sdfr#include "llvm/Support/Path.h" 1525537Sdfr#include "llvm/Support/Process.h" 1625537Sdfr#include "llvm/Support/WindowsError.h" 1725537Sdfr#include <algorithm> 1825537Sdfr#include <io.h> 1925537Sdfr#include <signal.h> 2025537Sdfr#include <stdio.h> 2125537Sdfr 2225537Sdfr#include "llvm/Support/Format.h" 2325537Sdfr#include "llvm/Support/raw_ostream.h" 2425537Sdfr 2525537Sdfr// The Windows.h header must be after LLVM and standard headers. 2643301Sdillon#include "WindowsSupport.h" 2725537Sdfr 2825537Sdfr#ifdef __MINGW32__ 2940159Speter #include <imagehlp.h> 3040159Speter#else 3125537Sdfr #include <dbghelp.h> 3225537Sdfr#endif 3325537Sdfr#include <psapi.h> 3425537Sdfr 3525537Sdfr#ifdef _MSC_VER 3625537Sdfr #pragma comment(lib, "psapi.lib") 3725537Sdfr#elif __MINGW32__ 3825537Sdfr #if (HAVE_LIBPSAPI != 1) 3925537Sdfr #error "libpsapi.a should be present" 4040159Speter #endif 4125537Sdfr // The version of g++ that comes with MinGW does *not* properly understand 4225537Sdfr // the ll format specifier for printf. However, MinGW passes the format 4331675Sdyson // specifiers on to the MSVCRT entirely, and the CRT understands the ll 4440159Speter // specifier. So these warnings are spurious in this case. Since we compile 4540159Speter // with -Wall, this will generate these warnings which should be ignored. So 4640159Speter // we will turn off the warnings for this just file. However, MinGW also does 4740159Speter // not support push and pop for diagnostics, so we have to manually turn it 4840159Speter // back on at the end of the file. 4925537Sdfr #pragma GCC diagnostic ignored "-Wformat" 5040961Speter #pragma GCC diagnostic ignored "-Wformat-extra-args" 5140961Speter 5240961Speter #if !defined(__MINGW64_VERSION_MAJOR) 5340961Speter // MinGW.org does not have updated support for the 64-bit versions of the 5432153Sbde // DebugHlp APIs. So we will have to load them manually. The structures and 5531324Sbde // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 5640906Speter // and adjusted for brevity. 5731324Sbde typedef struct _IMAGEHLP_LINE64 { 5825537Sdfr DWORD SizeOfStruct; 5925537Sdfr PVOID Key; 6025537Sdfr DWORD LineNumber; 6125537Sdfr PCHAR FileName; 6225537Sdfr DWORD64 Address; 6325537Sdfr } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 6425537Sdfr 6525537Sdfr typedef struct _IMAGEHLP_SYMBOL64 { 6625537Sdfr DWORD SizeOfStruct; 6725537Sdfr DWORD64 Address; 6825537Sdfr DWORD Size; 6925537Sdfr DWORD Flags; 7025537Sdfr DWORD MaxNameLength; 7140159Speter CHAR Name[1]; 7225537Sdfr } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 7325537Sdfr 7425537Sdfr typedef struct _tagADDRESS64 { 7525537Sdfr DWORD64 Offset; 7625537Sdfr WORD Segment; 7725537Sdfr ADDRESS_MODE Mode; 7825537Sdfr } ADDRESS64, *LPADDRESS64; 7925537Sdfr 8025537Sdfr typedef struct _KDHELP64 { 8125537Sdfr DWORD64 Thread; 8240395Speter DWORD ThCallbackStack; 8325537Sdfr DWORD ThCallbackBStore; 8425537Sdfr DWORD NextCallback; 8525537Sdfr DWORD FramePointer; 8625537Sdfr DWORD64 KiCallUserMode; 8725537Sdfr DWORD64 KeUserCallbackDispatcher; 8825537Sdfr DWORD64 SystemRangeStart; 8925537Sdfr DWORD64 KiUserExceptionDispatcher; 9025537Sdfr DWORD64 StackBase; 9125537Sdfr DWORD64 StackLimit; 9225537Sdfr DWORD64 Reserved[5]; 9325537Sdfr } KDHELP64, *PKDHELP64; 9425537Sdfr 9525537Sdfr typedef struct _tagSTACKFRAME64 { 9625537Sdfr ADDRESS64 AddrPC; 9725537Sdfr ADDRESS64 AddrReturn; 9825537Sdfr ADDRESS64 AddrFrame; 9940159Speter ADDRESS64 AddrStack; 10025537Sdfr ADDRESS64 AddrBStore; 10125537Sdfr PVOID FuncTableEntry; 10225537Sdfr DWORD64 Params[4]; 10325537Sdfr BOOL Far; 10425537Sdfr BOOL Virtual; 10525537Sdfr DWORD64 Reserved[3]; 10640159Speter KDHELP64 KdHelp; 10740159Speter } STACKFRAME64, *LPSTACKFRAME64; 10825537Sdfr #endif // !defined(__MINGW64_VERSION_MAJOR) 10925537Sdfr#endif // __MINGW32__ 11025537Sdfr 11140159Spetertypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, 11240159Speter DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 11340159Speter LPDWORD lpNumberOfBytesRead); 11440159Speter 11540159Spetertypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, 11640159Speter DWORD64 AddrBase); 11740159Speter 11840159Spetertypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 11925537Sdfr DWORD64 Address); 12025537Sdfr 12125537Sdfrtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 12225537Sdfr HANDLE hThread, LPADDRESS64 lpaddr); 12325537Sdfr 12425537Sdfrtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, 12525537Sdfr PMINIDUMP_EXCEPTION_INFORMATION, 12641055Speter PMINIDUMP_USER_STREAM_INFORMATION, 12741055Speter PMINIDUMP_CALLBACK_INFORMATION); 12841055Speterstatic fpMiniDumpWriteDump fMiniDumpWriteDump; 12941055Speter 13041055Spetertypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 13125537Sdfr PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 13225537Sdfr PFUNCTION_TABLE_ACCESS_ROUTINE64, 13325537Sdfr PGET_MODULE_BASE_ROUTINE64, 13425537Sdfr PTRANSLATE_ADDRESS_ROUTINE64); 13525537Sdfrstatic fpStackWalk64 fStackWalk64; 13625537Sdfr 13725537Sdfrtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 13825537Sdfrstatic fpSymGetModuleBase64 fSymGetModuleBase64; 13925537Sdfr 14025537Sdfrtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, 14125537Sdfr PDWORD64, PIMAGEHLP_SYMBOL64); 14225537Sdfrstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64; 14341055Speter 14441055Spetertypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, 14525537Sdfr PDWORD, PIMAGEHLP_LINE64); 14625537Sdfrstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64; 14741055Speter 14825537Sdfrtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, 14925537Sdfr PIMAGEHLP_MODULE64 ModuleInfo); 15041055Speterstatic fpSymGetModuleInfo64 fSymGetModuleInfo64; 15125537Sdfr 15225537Sdfrtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 15325537Sdfrstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64; 15431675Sdyson 15525537Sdfrtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD); 15631675Sdysonstatic fpSymSetOptions fSymSetOptions; 15731675Sdyson 15831675Sdysontypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); 15931675Sdysonstatic fpSymInitialize fSymInitialize; 16031675Sdyson 16131675Sdysontypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); 16231675Sdysonstatic fpEnumerateLoadedModules fEnumerateLoadedModules; 16331675Sdyson 16431675Sdysonstatic bool load64BitDebugHelp(void) { 16531675Sdyson HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 16625537Sdfr if (hLib) { 16730994Sphk fMiniDumpWriteDump = (fpMiniDumpWriteDump) 16830994Sphk ::GetProcAddress(hLib, "MiniDumpWriteDump"); 16925537Sdfr fStackWalk64 = (fpStackWalk64) 17025537Sdfr ::GetProcAddress(hLib, "StackWalk64"); 17125537Sdfr fSymGetModuleBase64 = (fpSymGetModuleBase64) 17241055Speter ::GetProcAddress(hLib, "SymGetModuleBase64"); 17325537Sdfr fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) 17425537Sdfr ::GetProcAddress(hLib, "SymGetSymFromAddr64"); 17525537Sdfr fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) 17625537Sdfr ::GetProcAddress(hLib, "SymGetLineFromAddr64"); 17741055Speter fSymGetModuleInfo64 = (fpSymGetModuleInfo64) 17841055Speter ::GetProcAddress(hLib, "SymGetModuleInfo64"); 17941055Speter fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) 18041055Speter ::GetProcAddress(hLib, "SymFunctionTableAccess64"); 18141055Speter fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); 18241055Speter fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); 18341055Speter fEnumerateLoadedModules = (fpEnumerateLoadedModules) 18441055Speter ::GetProcAddress(hLib, "EnumerateLoadedModules64"); 18541055Speter } 18641055Speter return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; 18741055Speter} 18841055Speter 18941055Speterusing namespace llvm; 19041055Speter 19141055Speter// Forward declare. 19241055Speterstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 19341055Speterstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 19441055Speter 19541055Speter// InterruptFunction - The function to call if ctrl-c is pressed. 19641055Speterstatic void (*InterruptFunction)() = 0; 19741055Speter 19841055Speterstatic std::vector<std::string> *FilesToRemove = NULL; 19941055Speterstatic bool RegisteredUnhandledExceptionFilter = false; 20041055Speterstatic bool CleanupExecuted = false; 20141055Speterstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 20241055Speter 20341055Speter// Windows creates a new thread to execute the console handler when an event 20441055Speter// (such as CTRL/C) occurs. This causes concurrency issues with the above 20541055Speter// globals which this critical section addresses. 20641055Speterstatic CRITICAL_SECTION CriticalSection; 20741055Speterstatic bool CriticalSectionInitialized = false; 20841055Speter 20941055Speterstatic StringRef Argv0; 21041055Speter 21141055Speterenum { 21241055Speter#if defined(_M_X64) 21341055Speter NativeMachineType = IMAGE_FILE_MACHINE_AMD64 21441055Speter#else 21541055Speter NativeMachineType = IMAGE_FILE_MACHINE_I386 21641055Speter#endif 21741055Speter}; 21841055Speter 21941055Speterstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, 22041055Speter HANDLE hProcess, HANDLE hThread, 22141055Speter STACKFRAME64 &StackFrameOrig, 22241055Speter CONTEXT *ContextOrig) { 22341055Speter // StackWalk64 modifies the incoming stack frame and context, so copy them. 22441055Speter STACKFRAME64 StackFrame = StackFrameOrig; 22541055Speter 22641055Speter // Copy the register context so that we don't modify it while we unwind. We 22741055Speter // could use InitializeContext + CopyContext, but that's only required to get 22841055Speter // at AVX registers, which typically aren't needed by StackWalk64. Reduce the 22941055Speter // flag set to indicate that there's less data. 23041055Speter CONTEXT Context = *ContextOrig; 23141055Speter Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; 23241055Speter 23341055Speter static void *StackTrace[256]; 23441055Speter size_t Depth = 0; 23525537Sdfr while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 23625537Sdfr &Context, 0, fSymFunctionTableAccess64, 23725537Sdfr fSymGetModuleBase64, 0)) { 23825537Sdfr if (StackFrame.AddrFrame.Offset == 0) 23925537Sdfr break; 24042755Speter StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; 24140861Speter if (Depth >= array_lengthof(StackTrace)) 24225537Sdfr break; 24325537Sdfr } 24425537Sdfr 24525537Sdfr return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); 24625537Sdfr} 24725537Sdfr 24825537Sdfrnamespace { 24925537Sdfrstruct FindModuleData { 25025537Sdfr void **StackTrace; 25140861Speter int Depth; 25240861Speter const char **Modules; 25340861Speter intptr_t *Offsets; 25440861Speter StringSaver *StrPool; 25540861Speter}; 25640861Speter} 25725537Sdfr 25842755Speterstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName, 25925537Sdfr DWORD64 ModuleBase, ULONG ModuleSize, 26025537Sdfr void *VoidData) { 26125537Sdfr FindModuleData *Data = (FindModuleData*)VoidData; 26242755Speter intptr_t Beg = ModuleBase; 26342755Speter intptr_t End = Beg + ModuleSize; 26442755Speter for (int I = 0; I < Data->Depth; I++) { 26542755Speter if (Data->Modules[I]) 26642755Speter continue; 26742755Speter intptr_t Addr = (intptr_t)Data->StackTrace[I]; 26842755Speter if (Beg <= Addr && Addr < End) { 26942755Speter Data->Modules[I] = Data->StrPool->save(ModuleName); 27042755Speter Data->Offsets[I] = Addr - Beg; 27142755Speter } 27225537Sdfr } 27325537Sdfr return TRUE; 27425537Sdfr} 27525537Sdfr 27640861Speterstatic bool findModulesAndOffsets(void **StackTrace, int Depth, 27725537Sdfr const char **Modules, intptr_t *Offsets, 27825537Sdfr const char *MainExecutableName, 27925537Sdfr StringSaver &StrPool) { 28042755Speter if (!fEnumerateLoadedModules) 28142755Speter return false; 28242755Speter FindModuleData Data; 28342755Speter Data.StackTrace = StackTrace; 28442755Speter Data.Depth = Depth; 28542755Speter Data.Modules = Modules; 28642755Speter Data.Offsets = Offsets; 28742755Speter Data.StrPool = &StrPool; 28825537Sdfr fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); 28925537Sdfr return true; 29040861Speter} 29140861Speter 29225537Sdfrstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, 29325537Sdfr HANDLE hThread, STACKFRAME64 &StackFrame, 29425537Sdfr CONTEXT *Context) { 29525537Sdfr // Initialize the symbol handler. 29625537Sdfr fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); 29725537Sdfr fSymInitialize(hProcess, NULL, TRUE); 29825537Sdfr 29940861Speter // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs 30025537Sdfr // and DWARF, so it should do a good job regardless of what debug info or 30140861Speter // linker is in use. 30240861Speter if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, 30340861Speter Context)) { 30440861Speter return; 30540861Speter } 30625537Sdfr 30740861Speter while (true) { 30840861Speter if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 30940861Speter Context, 0, fSymFunctionTableAccess64, 31025537Sdfr fSymGetModuleBase64, 0)) { 31125537Sdfr break; 31240861Speter } 31325537Sdfr 31425537Sdfr if (StackFrame.AddrFrame.Offset == 0) 31540861Speter break; 31640861Speter 31740861Speter using namespace llvm; 31825537Sdfr // Print the PC in hexadecimal. 31925537Sdfr DWORD64 PC = StackFrame.AddrPC.Offset; 32025537Sdfr#if defined(_M_X64) 32125537Sdfr OS << format("0x%016llX", PC); 32225537Sdfr#elif defined(_M_IX86) 32325537Sdfr OS << format("0x%08lX", static_cast<DWORD>(PC)); 32425537Sdfr#endif 32525537Sdfr 32625537Sdfr// Print the parameters. Assume there are four. 32725537Sdfr#if defined(_M_X64) 32825537Sdfr OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", 32925537Sdfr StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], 33025537Sdfr StackFrame.Params[3]); 33125537Sdfr#elif defined(_M_IX86) 33225537Sdfr OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", 33325537Sdfr static_cast<DWORD>(StackFrame.Params[0]), 33425537Sdfr static_cast<DWORD>(StackFrame.Params[1]), 33525537Sdfr static_cast<DWORD>(StackFrame.Params[2]), 33640159Speter static_cast<DWORD>(StackFrame.Params[3])); 33725537Sdfr#endif 33825537Sdfr // Verify the PC belongs to a module in this process. 33925537Sdfr if (!fSymGetModuleBase64(hProcess, PC)) { 34040159Speter OS << " <unknown module>\n"; 34125537Sdfr continue; 34240159Speter } 34340159Speter 34440159Speter // Print the symbol name. 34540159Speter char buffer[512]; 34640159Speter IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 34740159Speter memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 34825537Sdfr symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 34925537Sdfr symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 35025537Sdfr 35125537Sdfr DWORD64 dwDisp; 35225537Sdfr if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 35325537Sdfr OS << '\n'; 35440395Speter continue; 35525537Sdfr } 35625537Sdfr 35725537Sdfr buffer[511] = 0; 35843185Sdfr if (dwDisp > 0) 35925537Sdfr OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, 36025537Sdfr dwDisp); 36125537Sdfr else 36225537Sdfr OS << format(", %s", (const char*)symbol->Name); 36325537Sdfr 36425537Sdfr // Print the source file and line number information. 36525537Sdfr IMAGEHLP_LINE64 line = {}; 36625537Sdfr DWORD dwLineDisp; 36725537Sdfr line.SizeOfStruct = sizeof(line); 36825537Sdfr if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 36925537Sdfr OS << format(", %s, line %lu", line.FileName, line.LineNumber); 37025537Sdfr if (dwLineDisp > 0) 37125537Sdfr OS << format(" + 0x%lX byte(s)", dwLineDisp); 37225537Sdfr } 37325537Sdfr 37425537Sdfr OS << '\n'; 37525537Sdfr } 37625537Sdfr} 37725537Sdfr 37825537Sdfrnamespace llvm { 37925537Sdfr 38025537Sdfr//===----------------------------------------------------------------------===// 38125537Sdfr//=== WARNING: Implementation here must contain only Win32 specific code 38225537Sdfr//=== and must not be UNIX code 38325537Sdfr//===----------------------------------------------------------------------===// 38440159Speter 38525537Sdfr#ifdef _MSC_VER 38625537Sdfr/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, 38725537Sdfr/// ignore" CRT debug report dialog. "retry" raises an exception which 38825537Sdfr/// ultimately triggers our stack dumper. 38925537Sdfrstatic LLVM_ATTRIBUTE_UNUSED int 39025537SdfrAvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 39125537Sdfr // Set *Return to the retry code for the return value of _CrtDbgReport: 39225537Sdfr // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 39325537Sdfr // This may also trigger just-in-time debugging via DebugBreak(). 39425537Sdfr if (Return) 39525537Sdfr *Return = 1; 39625537Sdfr // Don't call _CrtDbgReport. 39743301Sdillon return TRUE; 39825537Sdfr} 39925537Sdfr 40025537Sdfr#endif 40125537Sdfr 40225537Sdfrextern "C" void HandleAbort(int Sig) { 40325537Sdfr if (Sig == SIGABRT) { 40425537Sdfr LLVM_BUILTIN_TRAP; 40525537Sdfr } 40625537Sdfr} 40725537Sdfr 40825537Sdfrstatic void InitializeThreading() { 40925537Sdfr if (CriticalSectionInitialized) 41025537Sdfr return; 41125537Sdfr 41225537Sdfr // Now's the time to create the critical section. This is the first time 41325537Sdfr // through here, and there's only one thread. 41443185Sdfr InitializeCriticalSection(&CriticalSection); 41543185Sdfr CriticalSectionInitialized = true; 41643185Sdfr} 41741055Speter 41825537Sdfrstatic void RegisterHandler() { 41925537Sdfr // If we cannot load up the APIs (which would be unexpected as they should 42040159Speter // exist on every version of Windows we support), we will bail out since 42125537Sdfr // there would be nothing to report. 42225537Sdfr if (!load64BitDebugHelp()) { 42325537Sdfr assert(false && "These APIs should always be available"); 42425537Sdfr return; 42525537Sdfr } 42625537Sdfr 42725537Sdfr if (RegisteredUnhandledExceptionFilter) { 42825537Sdfr EnterCriticalSection(&CriticalSection); 42925537Sdfr return; 43025537Sdfr } 43125537Sdfr 43225537Sdfr InitializeThreading(); 43325537Sdfr 43425537Sdfr // Enter it immediately. Now if someone hits CTRL/C, the console handler 43525537Sdfr // can't proceed until the globals are updated. 43625537Sdfr EnterCriticalSection(&CriticalSection); 43725537Sdfr 43825537Sdfr RegisteredUnhandledExceptionFilter = true; 43925537Sdfr OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 44025537Sdfr SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 44125537Sdfr 44225537Sdfr // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 44325537Sdfr // else multi-threading problems will ensue. 44425537Sdfr} 44525537Sdfr 44625537Sdfr// RemoveFileOnSignal - The public API 44740395Speterbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { 44825537Sdfr RegisterHandler(); 44925537Sdfr 45025537Sdfr if (CleanupExecuted) { 45125537Sdfr if (ErrMsg) 45225537Sdfr *ErrMsg = "Process terminating -- cannot register for removal"; 45325537Sdfr return true; 45425537Sdfr } 45525537Sdfr 45625537Sdfr if (FilesToRemove == NULL) 45725537Sdfr FilesToRemove = new std::vector<std::string>; 45825537Sdfr 45925537Sdfr FilesToRemove->push_back(Filename); 46025537Sdfr 46125537Sdfr LeaveCriticalSection(&CriticalSection); 46225537Sdfr return false; 46338275Sdfr} 46438275Sdfr 46542849Speter// DontRemoveFileOnSignal - The public API 46625537Sdfrvoid sys::DontRemoveFileOnSignal(StringRef Filename) { 46725537Sdfr if (FilesToRemove == NULL) 46825537Sdfr return; 46925537Sdfr 47040159Speter RegisterHandler(); 47125537Sdfr 47225537Sdfr std::vector<std::string>::reverse_iterator I = 47338275Sdfr std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); 47438275Sdfr if (I != FilesToRemove->rend()) 47538275Sdfr FilesToRemove->erase(I.base()-1); 47625537Sdfr 47725537Sdfr LeaveCriticalSection(&CriticalSection); 47825537Sdfr} 47925537Sdfr 48038275Sdfrvoid sys::DisableSystemDialogsOnCrash() { 48140159Speter // Crash to stack trace handler on abort. 48240159Speter signal(SIGABRT, HandleAbort); 48338275Sdfr 48440159Speter // The following functions are not reliably accessible on MinGW. 48538275Sdfr#ifdef _MSC_VER 48625537Sdfr // We're already handling writing a "something went wrong" message. 48742849Speter _set_abort_behavior(0, _WRITE_ABORT_MSG); 48825537Sdfr // Disable Dr. Watson. 48925537Sdfr _set_abort_behavior(0, _CALL_REPORTFAULT); 49040159Speter _CrtSetReportHook(AvoidMessageBoxHook); 49140159Speter#endif 49225537Sdfr 49340159Speter // Disable standard error dialog box. 49425537Sdfr SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 49525537Sdfr SEM_NOOPENFILEERRORBOX); 49642849Speter _set_error_mode(_OUT_TO_STDERR); 49742849Speter} 49842849Speter 49942849Speter/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 50042849Speter/// SIGSEGV) is delivered to the process, print a stack trace and then exit. 50142849Spetervoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0, 50242849Speter bool DisableCrashReporting) { 50342849Speter ::Argv0 = Argv0; 50442849Speter 50542849Speter if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) 50642849Speter Process::PreventCoreFiles(); 50742849Speter 50842849Speter DisableSystemDialogsOnCrash(); 50942849Speter RegisterHandler(); 51042849Speter LeaveCriticalSection(&CriticalSection); 51142849Speter} 51242849Speter} 51342849Speter 51442849Speter#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 51525537Sdfr// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is 51625537Sdfr// missing it but mingw-w64 has it. 51725537Sdfrextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); 51825537Sdfr#endif 51925537Sdfr 52025537Sdfrvoid llvm::sys::PrintStackTrace(raw_ostream &OS) { 52125537Sdfr STACKFRAME64 StackFrame = {}; 52225537Sdfr CONTEXT Context = {}; 52325537Sdfr ::RtlCaptureContext(&Context); 52425537Sdfr#if defined(_M_X64) 52540159Speter StackFrame.AddrPC.Offset = Context.Rip; 52640159Speter StackFrame.AddrStack.Offset = Context.Rsp; 52725537Sdfr StackFrame.AddrFrame.Offset = Context.Rbp; 52840159Speter#else 52925537Sdfr StackFrame.AddrPC.Offset = Context.Eip; 53025537Sdfr StackFrame.AddrStack.Offset = Context.Esp; 53125537Sdfr StackFrame.AddrFrame.Offset = Context.Ebp; 53225537Sdfr#endif 53325537Sdfr StackFrame.AddrPC.Mode = AddrModeFlat; 53425537Sdfr StackFrame.AddrStack.Mode = AddrModeFlat; 53525537Sdfr StackFrame.AddrFrame.Mode = AddrModeFlat; 53625537Sdfr PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), 53725537Sdfr StackFrame, &Context); 53840159Speter} 53940159Speter 54025537Sdfr 54140159Spetervoid llvm::sys::SetInterruptFunction(void (*IF)()) { 54240395Speter RegisterHandler(); 54325537Sdfr InterruptFunction = IF; 54425537Sdfr LeaveCriticalSection(&CriticalSection); 54525537Sdfr} 54625537Sdfr 54725537Sdfr 54825537Sdfr/// AddSignalHandler - Add a function to be called when a signal is delivered 54925537Sdfr/// to the process. The handler can have a cookie passed to it to identify 55040159Speter/// what instance of the handler it is. 55125537Sdfrvoid llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { 55225537Sdfr CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); 55325537Sdfr RegisterHandler(); 55440159Speter LeaveCriticalSection(&CriticalSection); 55525537Sdfr} 55625537Sdfr 55725537Sdfrstatic void Cleanup() { 55840159Speter if (CleanupExecuted) 55925537Sdfr return; 56040159Speter 56140159Speter EnterCriticalSection(&CriticalSection); 56240159Speter 56340159Speter // Prevent other thread from registering new files and directories for 56440159Speter // removal, should we be executing because of the console handler callback. 56540159Speter CleanupExecuted = true; 56640159Speter 56740159Speter // FIXME: open files cannot be deleted. 56840159Speter if (FilesToRemove != NULL) 56940159Speter while (!FilesToRemove->empty()) { 57040159Speter llvm::sys::fs::remove(FilesToRemove->back()); 57140159Speter FilesToRemove->pop_back(); 57240159Speter } 57340159Speter llvm::sys::RunSignalHandlers(); 57440159Speter LeaveCriticalSection(&CriticalSection); 57540159Speter} 57640159Speter 57740159Spetervoid llvm::sys::RunInterruptHandlers() { 57840159Speter // The interrupt handler may be called from an interrupt, but it may also be 57940159Speter // called manually (such as the case of report_fatal_error with no registered 58040159Speter // error handler). We must ensure that the critical section is properly 58140159Speter // initialized. 58240159Speter InitializeThreading(); 58340159Speter Cleanup(); 58440159Speter} 58540159Speter 58640159Speter/// \brief Find the Windows Registry Key for a given location. 58740159Speter/// 58840159Speter/// \returns a valid HKEY if the location exists, else NULL. 58940159Speterstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) { 59040159Speter HKEY Key; 59140159Speter if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, 59240159Speter RegistryLocation.str().c_str(), 0, 59340159Speter KEY_QUERY_VALUE | KEY_READ, &Key)) 59440159Speter return NULL; 59540159Speter 59640159Speter return Key; 59740159Speter} 59840159Speter 59940159Speter/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given 60040159Speter/// Windows Registry key. 60140159Speter/// 60240159Speter/// \returns true if a valid value for DumpFolder exists, false otherwise. 60340159Speterstatic bool GetDumpFolder(HKEY Key, 60440159Speter llvm::SmallVectorImpl<char> &ResultDirectory) { 60540159Speter using llvm::sys::windows::UTF16ToUTF8; 60640159Speter 60740159Speter if (!Key) 60840159Speter return false; 60940159Speter 61040159Speter DWORD BufferLengthBytes = 0; 61140159Speter 61240159Speter if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 61340159Speter NULL, NULL, &BufferLengthBytes)) 61440159Speter return false; 61540159Speter 61640159Speter SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); 61740159Speter 61840159Speter if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 61940159Speter NULL, Buffer.data(), &BufferLengthBytes)) 62040159Speter return false; 62140159Speter 62240159Speter DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); 62340159Speter 62440159Speter if (!ExpandBufferSize) 62540159Speter return false; 62640159Speter 62725537Sdfr SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); 62825537Sdfr 62925537Sdfr if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), 63025537Sdfr ExpandBuffer.data(), 63130994Sphk ExpandBufferSize)) 63225537Sdfr return false; 63342316Smsmith 63425537Sdfr if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) 63525537Sdfr return false; 63625537Sdfr 63730994Sphk return true; 63825537Sdfr} 63925537Sdfr 64025537Sdfr/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of 64125537Sdfr/// "DumpType" for a given Windows Registry key. 64243301Sdillon/// 64325537Sdfr/// According to 64425537Sdfr/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx 64525537Sdfr/// valid values for DumpType are: 64643301Sdillon/// * 0: Custom dump 64725537Sdfr/// * 1: Mini dump 64825537Sdfr/// * 2: Full dump 64942316Smsmith/// If "Custom dump" is specified then the "CustomDumpFlags" field is read 65042316Smsmith/// containing a bitwise combination of MINIDUMP_TYPE values. 65142316Smsmith/// 65242316Smsmith/// \returns true if a valid value for ResultType can be set, false otherwise. 65342316Smsmithstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { 65442316Smsmith if (!Key) 65542316Smsmith return false; 65642316Smsmith 65742316Smsmith DWORD DumpType; 65843301Sdillon DWORD TypeSize = sizeof(DumpType); 65925537Sdfr if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, 66025537Sdfr NULL, &DumpType, 66125537Sdfr &TypeSize)) 66230994Sphk return false; 66340159Speter 66425537Sdfr switch (DumpType) { 66525537Sdfr case 0: { 66625537Sdfr DWORD Flags = 0; 66725537Sdfr if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", 66825537Sdfr RRF_RT_REG_DWORD, NULL, &Flags, 66925537Sdfr &TypeSize)) 67025537Sdfr return false; 67130994Sphk 67225537Sdfr ResultType = static_cast<MINIDUMP_TYPE>(Flags); 67325537Sdfr break; 67425537Sdfr } 67525537Sdfr case 1: 67625537Sdfr ResultType = MiniDumpNormal; 67725537Sdfr break; 67825537Sdfr case 2: 67943301Sdillon ResultType = MiniDumpWithFullMemory; 68025537Sdfr break; 68125537Sdfr default: 68225537Sdfr return false; 68325537Sdfr } 68425537Sdfr return true; 68525537Sdfr} 68643084Speter 68725537Sdfr/// \brief Write a Windows dump file containing process information that can be 68825537Sdfr/// used for post-mortem debugging. 68925537Sdfr/// 69043084Speter/// \returns zero error code if a mini dump created, actual error code 69142837Speter/// otherwise. 69242837Speterstatic std::error_code WINAPI 69343084SpeterWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { 69425537Sdfr using namespace llvm; 69525537Sdfr using namespace llvm::sys; 69625537Sdfr 69725537Sdfr std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); 69825537Sdfr StringRef ProgramName; 69925537Sdfr 70025537Sdfr if (MainExecutableName.empty()) { 70125537Sdfr // If we can't get the executable filename, 70230994Sphk // things are in worse shape than we realize 70325537Sdfr // and we should just bail out. 70442316Smsmith return mapWindowsError(::GetLastError()); 70525537Sdfr } 70625537Sdfr 70725537Sdfr ProgramName = path::filename(MainExecutableName.c_str()); 70830994Sphk 70925537Sdfr // The Windows Registry location as specified at 71025537Sdfr // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx 71143301Sdillon // "Collecting User-Mode Dumps" that may optionally be set to collect crash 71225537Sdfr // dumps in a specified location. 71325537Sdfr StringRef LocalDumpsRegistryLocation = 71442316Smsmith "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; 71542316Smsmith 71642316Smsmith // The key pointing to the Registry location that may contain global crash 71742316Smsmith // dump settings. This will be NULL if the location can not be found. 71842316Smsmith ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); 71925537Sdfr 72030994Sphk // The key pointing to the Registry location that may contain 72125537Sdfr // application-specific crash dump settings. This will be NULL if the 72225537Sdfr // location can not be found. 72340159Speter ScopedRegHandle AppSpecificKey( 72425537Sdfr FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); 72525537Sdfr 72625537Sdfr // Look to see if a dump type is specified in the registry; first with the 72725537Sdfr // app-specific key and failing that with the global key. If none are found 72825537Sdfr // default to a normal dump (GetDumpType will return false either if the key 72925537Sdfr // is NULL or if there is no valid DumpType value at its location). 73025537Sdfr MINIDUMP_TYPE DumpType; 73130994Sphk if (!GetDumpType(AppSpecificKey, DumpType)) 73225537Sdfr if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) 73325537Sdfr DumpType = MiniDumpNormal; 73425537Sdfr 73525537Sdfr // Look to see if a dump location is specified in the registry; first with the 73625537Sdfr // app-specific key and failing that with the global key. If none are found 73725537Sdfr // we'll just create the dump file in the default temporary file location 73830994Sphk // (GetDumpFolder will return false either if the key is NULL or if there is 73925537Sdfr // no valid DumpFolder value at its location). 74030994Sphk bool ExplicitDumpDirectorySet = true; 74125537Sdfr SmallString<MAX_PATH> DumpDirectory; 74225537Sdfr if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) 74340159Speter if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) 74425537Sdfr ExplicitDumpDirectorySet = false; 74525537Sdfr 74625537Sdfr int FD; 74730994Sphk SmallString<MAX_PATH> DumpPath; 74825537Sdfr 74930994Sphk if (ExplicitDumpDirectorySet) { 75025537Sdfr if (std::error_code EC = fs::create_directories(DumpDirectory)) 75125537Sdfr return EC; 75225537Sdfr if (std::error_code EC = fs::createUniqueFile( 75325537Sdfr Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, 75425537Sdfr DumpPath)) 75525537Sdfr return EC; 75625537Sdfr } else if (std::error_code EC = 75730994Sphk fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) 75825537Sdfr return EC; 75925537Sdfr 76025537Sdfr // Our support functions return a file descriptor but Windows wants a handle. 76125537Sdfr ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); 76225537Sdfr 76325537Sdfr if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), 76425537Sdfr FileHandle, DumpType, ExceptionInfo, NULL, NULL)) 76525537Sdfr return mapWindowsError(::GetLastError()); 76625537Sdfr 76725537Sdfr llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; 76825537Sdfr return std::error_code(); 76925537Sdfr} 77025537Sdfr 77125537Sdfrstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 77225537Sdfr Cleanup(); 77325537Sdfr 77425537Sdfr // We'll automatically write a Minidump file here to help diagnose 77525537Sdfr // the nasty sorts of crashes that aren't 100% reproducible from a set of 77643301Sdillon // inputs (or in the event that the user is unable or unwilling to provide a 77725537Sdfr // reproducible case). 77825537Sdfr if (!llvm::Process::AreCoreFilesPrevented()) { 77925537Sdfr MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; 78025537Sdfr ExceptionInfo.ThreadId = ::GetCurrentThreadId(); 78125537Sdfr ExceptionInfo.ExceptionPointers = ep; 78225537Sdfr ExceptionInfo.ClientPointers = FALSE; 78325537Sdfr 78425537Sdfr if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) 78525537Sdfr llvm::errs() << "Could not write crash dump file: " << EC.message() 78643301Sdillon << "\n"; 78725537Sdfr } 78843301Sdillon 78925537Sdfr // Initialize the STACKFRAME structure. 79043301Sdillon STACKFRAME64 StackFrame = {}; 79125537Sdfr 79243301Sdillon#if defined(_M_X64) 79325537Sdfr StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; 79443301Sdillon StackFrame.AddrPC.Mode = AddrModeFlat; 79525537Sdfr StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; 79625537Sdfr StackFrame.AddrStack.Mode = AddrModeFlat; 79730994Sphk StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; 79825537Sdfr StackFrame.AddrFrame.Mode = AddrModeFlat; 79925537Sdfr#elif defined(_M_IX86) 80025537Sdfr StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 80125537Sdfr StackFrame.AddrPC.Mode = AddrModeFlat; 80225537Sdfr StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 80325537Sdfr StackFrame.AddrStack.Mode = AddrModeFlat; 80430994Sphk StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 80525537Sdfr StackFrame.AddrFrame.Mode = AddrModeFlat; 80625537Sdfr#endif 80725537Sdfr 80825537Sdfr HANDLE hProcess = GetCurrentProcess(); 80925537Sdfr HANDLE hThread = GetCurrentThread(); 81025537Sdfr PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, 81125537Sdfr ep->ContextRecord); 81230994Sphk 81325537Sdfr _exit(ep->ExceptionRecord->ExceptionCode); 81430994Sphk} 81525537Sdfr 81625537Sdfrstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 81725537Sdfr // We are running in our very own thread, courtesy of Windows. 81825537Sdfr EnterCriticalSection(&CriticalSection); 81925537Sdfr Cleanup(); 82040159Speter 82141090Speter // If an interrupt function has been set, go and run one it; otherwise, 82241090Speter // the process dies. 82341090Speter void (*IF)() = InterruptFunction; 82441090Speter InterruptFunction = 0; // Don't run it on another CTRL-C. 82541090Speter 82641090Speter if (IF) { 82741090Speter // Note: if the interrupt function throws an exception, there is nothing 82841090Speter // to catch it in this thread so it will kill the process. 82941090Speter IF(); // Run it now. 83041090Speter LeaveCriticalSection(&CriticalSection); 83143301Sdillon return TRUE; // Don't kill the process. 83241090Speter } 83341090Speter 83441090Speter // Allow normal processing to take place; i.e., the process dies. 83541090Speter LeaveCriticalSection(&CriticalSection); 83641090Speter return FALSE; 83741090Speter} 83841090Speter 83943301Sdillon#if __MINGW32__ 84041090Speter // We turned these warnings off for this file so that MinGW-g++ doesn't 84141090Speter // complain about the ll format specifiers used. Now we are turning the 84241090Speter // warnings back on. If MinGW starts to support diagnostic stacks, we can 84341090Speter // replace this with a pop. 84441090Speter #pragma GCC diagnostic warning "-Wformat" 84541090Speter #pragma GCC diagnostic warning "-Wformat-extra-args" 84641090Speter#endif 84741090Speter