Signals.inc revision 341825
1170263Sdarrenr//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 2170263Sdarrenr// 3170263Sdarrenr// The LLVM Compiler Infrastructure 4170263Sdarrenr// 5170263Sdarrenr// This file is distributed under the University of Illinois Open Source 6170263Sdarrenr// License. See LICENSE.TXT for details. 7170263Sdarrenr// 8170263Sdarrenr//===----------------------------------------------------------------------===// 9170263Sdarrenr// 10170263Sdarrenr// This file provides the Win32 specific implementation of the Signals class. 11170263Sdarrenr// 12170263Sdarrenr//===----------------------------------------------------------------------===// 13170263Sdarrenr#include "llvm/Support/ConvertUTF.h" 14170263Sdarrenr#include "llvm/Support/FileSystem.h" 15170263Sdarrenr#include "llvm/Support/Path.h" 16170263Sdarrenr#include "llvm/Support/Process.h" 17170263Sdarrenr#include "llvm/Support/WindowsError.h" 18170263Sdarrenr#include <algorithm> 19170263Sdarrenr#include <io.h> 20170263Sdarrenr#include <signal.h> 21170263Sdarrenr#include <stdio.h> 22170263Sdarrenr 23170263Sdarrenr#include "llvm/Support/Format.h" 24170263Sdarrenr#include "llvm/Support/raw_ostream.h" 25170263Sdarrenr 26170263Sdarrenr// The Windows.h header must be after LLVM and standard headers. 27170263Sdarrenr#include "WindowsSupport.h" 28170263Sdarrenr 29170263Sdarrenr#ifdef __MINGW32__ 30170263Sdarrenr #include <imagehlp.h> 31170263Sdarrenr#else 32170263Sdarrenr #include <crtdbg.h> 33170263Sdarrenr #include <dbghelp.h> 34170263Sdarrenr#endif 35170263Sdarrenr#include <psapi.h> 36170263Sdarrenr 37170263Sdarrenr#ifdef _MSC_VER 38170263Sdarrenr #pragma comment(lib, "psapi.lib") 39170263Sdarrenr#elif __MINGW32__ 40170263Sdarrenr // The version of g++ that comes with MinGW does *not* properly understand 41170263Sdarrenr // the ll format specifier for printf. However, MinGW passes the format 42170263Sdarrenr // specifiers on to the MSVCRT entirely, and the CRT understands the ll 43170263Sdarrenr // specifier. So these warnings are spurious in this case. Since we compile 44170263Sdarrenr // with -Wall, this will generate these warnings which should be ignored. So 45170263Sdarrenr // we will turn off the warnings for this just file. However, MinGW also does 46170263Sdarrenr // not support push and pop for diagnostics, so we have to manually turn it 47170263Sdarrenr // back on at the end of the file. 48170263Sdarrenr #pragma GCC diagnostic ignored "-Wformat" 49170263Sdarrenr #pragma GCC diagnostic ignored "-Wformat-extra-args" 50170263Sdarrenr 51170263Sdarrenr #if !defined(__MINGW64_VERSION_MAJOR) 52170263Sdarrenr // MinGW.org does not have updated support for the 64-bit versions of the 53170263Sdarrenr // DebugHlp APIs. So we will have to load them manually. The structures and 54170263Sdarrenr // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 55170263Sdarrenr // and adjusted for brevity. 56170263Sdarrenr typedef struct _IMAGEHLP_LINE64 { 57170263Sdarrenr DWORD SizeOfStruct; 58170263Sdarrenr PVOID Key; 59170263Sdarrenr DWORD LineNumber; 60170263Sdarrenr PCHAR FileName; 61170263Sdarrenr DWORD64 Address; 62170263Sdarrenr } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 63170263Sdarrenr 64170263Sdarrenr typedef struct _IMAGEHLP_SYMBOL64 { 65170263Sdarrenr DWORD SizeOfStruct; 66170263Sdarrenr DWORD64 Address; 67170263Sdarrenr DWORD Size; 68170263Sdarrenr DWORD Flags; 69170263Sdarrenr DWORD MaxNameLength; 70170263Sdarrenr CHAR Name[1]; 71170263Sdarrenr } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 72170263Sdarrenr 73170263Sdarrenr typedef struct _tagADDRESS64 { 74170263Sdarrenr DWORD64 Offset; 75170263Sdarrenr WORD Segment; 76170263Sdarrenr ADDRESS_MODE Mode; 77170263Sdarrenr } ADDRESS64, *LPADDRESS64; 78170263Sdarrenr 79170263Sdarrenr typedef struct _KDHELP64 { 80170263Sdarrenr DWORD64 Thread; 81170263Sdarrenr DWORD ThCallbackStack; 82170263Sdarrenr DWORD ThCallbackBStore; 83170263Sdarrenr DWORD NextCallback; 84170263Sdarrenr DWORD FramePointer; 85170263Sdarrenr DWORD64 KiCallUserMode; 86170263Sdarrenr DWORD64 KeUserCallbackDispatcher; 87170263Sdarrenr DWORD64 SystemRangeStart; 88170263Sdarrenr DWORD64 KiUserExceptionDispatcher; 89170263Sdarrenr DWORD64 StackBase; 90170263Sdarrenr DWORD64 StackLimit; 91170263Sdarrenr DWORD64 Reserved[5]; 92170263Sdarrenr } KDHELP64, *PKDHELP64; 93170263Sdarrenr 94170263Sdarrenr typedef struct _tagSTACKFRAME64 { 95170263Sdarrenr ADDRESS64 AddrPC; 96170263Sdarrenr ADDRESS64 AddrReturn; 97170263Sdarrenr ADDRESS64 AddrFrame; 98170263Sdarrenr ADDRESS64 AddrStack; 99170263Sdarrenr ADDRESS64 AddrBStore; 100170263Sdarrenr PVOID FuncTableEntry; 101170263Sdarrenr DWORD64 Params[4]; 102170263Sdarrenr BOOL Far; 103170263Sdarrenr BOOL Virtual; 104170263Sdarrenr DWORD64 Reserved[3]; 105170263Sdarrenr KDHELP64 KdHelp; 106170263Sdarrenr } STACKFRAME64, *LPSTACKFRAME64; 107170263Sdarrenr #endif // !defined(__MINGW64_VERSION_MAJOR) 108170263Sdarrenr#endif // __MINGW32__ 109170263Sdarrenr 110170263Sdarrenrtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, 111170263Sdarrenr DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 112170263Sdarrenr LPDWORD lpNumberOfBytesRead); 113 114typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, 115 DWORD64 AddrBase); 116 117typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 118 DWORD64 Address); 119 120typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 121 HANDLE hThread, LPADDRESS64 lpaddr); 122 123typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, 124 PMINIDUMP_EXCEPTION_INFORMATION, 125 PMINIDUMP_USER_STREAM_INFORMATION, 126 PMINIDUMP_CALLBACK_INFORMATION); 127static fpMiniDumpWriteDump fMiniDumpWriteDump; 128 129typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 130 PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 131 PFUNCTION_TABLE_ACCESS_ROUTINE64, 132 PGET_MODULE_BASE_ROUTINE64, 133 PTRANSLATE_ADDRESS_ROUTINE64); 134static fpStackWalk64 fStackWalk64; 135 136typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 137static fpSymGetModuleBase64 fSymGetModuleBase64; 138 139typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, 140 PDWORD64, PIMAGEHLP_SYMBOL64); 141static fpSymGetSymFromAddr64 fSymGetSymFromAddr64; 142 143typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, 144 PDWORD, PIMAGEHLP_LINE64); 145static fpSymGetLineFromAddr64 fSymGetLineFromAddr64; 146 147typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, 148 PIMAGEHLP_MODULE64 ModuleInfo); 149static fpSymGetModuleInfo64 fSymGetModuleInfo64; 150 151typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 152static fpSymFunctionTableAccess64 fSymFunctionTableAccess64; 153 154typedef DWORD (WINAPI *fpSymSetOptions)(DWORD); 155static fpSymSetOptions fSymSetOptions; 156 157typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); 158static fpSymInitialize fSymInitialize; 159 160typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); 161static fpEnumerateLoadedModules fEnumerateLoadedModules; 162 163static bool load64BitDebugHelp(void) { 164 HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 165 if (hLib) { 166 fMiniDumpWriteDump = (fpMiniDumpWriteDump) 167 ::GetProcAddress(hLib, "MiniDumpWriteDump"); 168 fStackWalk64 = (fpStackWalk64) 169 ::GetProcAddress(hLib, "StackWalk64"); 170 fSymGetModuleBase64 = (fpSymGetModuleBase64) 171 ::GetProcAddress(hLib, "SymGetModuleBase64"); 172 fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) 173 ::GetProcAddress(hLib, "SymGetSymFromAddr64"); 174 fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) 175 ::GetProcAddress(hLib, "SymGetLineFromAddr64"); 176 fSymGetModuleInfo64 = (fpSymGetModuleInfo64) 177 ::GetProcAddress(hLib, "SymGetModuleInfo64"); 178 fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) 179 ::GetProcAddress(hLib, "SymFunctionTableAccess64"); 180 fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); 181 fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); 182 fEnumerateLoadedModules = (fpEnumerateLoadedModules) 183 ::GetProcAddress(hLib, "EnumerateLoadedModules64"); 184 } 185 return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; 186} 187 188using namespace llvm; 189 190// Forward declare. 191static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 192static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 193 194// The function to call if ctrl-c is pressed. 195static void (*InterruptFunction)() = 0; 196 197static std::vector<std::string> *FilesToRemove = NULL; 198static bool RegisteredUnhandledExceptionFilter = false; 199static bool CleanupExecuted = false; 200static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 201 202// Windows creates a new thread to execute the console handler when an event 203// (such as CTRL/C) occurs. This causes concurrency issues with the above 204// globals which this critical section addresses. 205static CRITICAL_SECTION CriticalSection; 206static bool CriticalSectionInitialized = false; 207 208static StringRef Argv0; 209 210enum { 211#if defined(_M_X64) 212 NativeMachineType = IMAGE_FILE_MACHINE_AMD64 213#elif defined(_M_ARM64) 214 NativeMachineType = IMAGE_FILE_MACHINE_ARM64 215#elif defined(_M_IX86) 216 NativeMachineType = IMAGE_FILE_MACHINE_I386 217#elif defined(_M_ARM) 218 NativeMachineType = IMAGE_FILE_MACHINE_ARMNT 219#else 220 NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN 221#endif 222}; 223 224static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, 225 HANDLE hProcess, HANDLE hThread, 226 STACKFRAME64 &StackFrameOrig, 227 CONTEXT *ContextOrig) { 228 // StackWalk64 modifies the incoming stack frame and context, so copy them. 229 STACKFRAME64 StackFrame = StackFrameOrig; 230 231 // Copy the register context so that we don't modify it while we unwind. We 232 // could use InitializeContext + CopyContext, but that's only required to get 233 // at AVX registers, which typically aren't needed by StackWalk64. Reduce the 234 // flag set to indicate that there's less data. 235 CONTEXT Context = *ContextOrig; 236 Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; 237 238 static void *StackTrace[256]; 239 size_t Depth = 0; 240 while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 241 &Context, 0, fSymFunctionTableAccess64, 242 fSymGetModuleBase64, 0)) { 243 if (StackFrame.AddrFrame.Offset == 0) 244 break; 245 StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; 246 if (Depth >= array_lengthof(StackTrace)) 247 break; 248 } 249 250 return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); 251} 252 253namespace { 254struct FindModuleData { 255 void **StackTrace; 256 int Depth; 257 const char **Modules; 258 intptr_t *Offsets; 259 StringSaver *StrPool; 260}; 261} 262 263static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, 264 DWORD64 ModuleBase, ULONG ModuleSize, 265 void *VoidData) { 266 FindModuleData *Data = (FindModuleData*)VoidData; 267 intptr_t Beg = ModuleBase; 268 intptr_t End = Beg + ModuleSize; 269 for (int I = 0; I < Data->Depth; I++) { 270 if (Data->Modules[I]) 271 continue; 272 intptr_t Addr = (intptr_t)Data->StackTrace[I]; 273 if (Beg <= Addr && Addr < End) { 274 Data->Modules[I] = Data->StrPool->save(ModuleName).data(); 275 Data->Offsets[I] = Addr - Beg; 276 } 277 } 278 return TRUE; 279} 280 281static bool findModulesAndOffsets(void **StackTrace, int Depth, 282 const char **Modules, intptr_t *Offsets, 283 const char *MainExecutableName, 284 StringSaver &StrPool) { 285 if (!fEnumerateLoadedModules) 286 return false; 287 FindModuleData Data; 288 Data.StackTrace = StackTrace; 289 Data.Depth = Depth; 290 Data.Modules = Modules; 291 Data.Offsets = Offsets; 292 Data.StrPool = &StrPool; 293 fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); 294 return true; 295} 296 297static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, 298 HANDLE hThread, STACKFRAME64 &StackFrame, 299 CONTEXT *Context) { 300 // Initialize the symbol handler. 301 fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); 302 fSymInitialize(hProcess, NULL, TRUE); 303 304 // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs 305 // and DWARF, so it should do a good job regardless of what debug info or 306 // linker is in use. 307 if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, 308 Context)) { 309 return; 310 } 311 312 while (true) { 313 if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, 314 Context, 0, fSymFunctionTableAccess64, 315 fSymGetModuleBase64, 0)) { 316 break; 317 } 318 319 if (StackFrame.AddrFrame.Offset == 0) 320 break; 321 322 using namespace llvm; 323 // Print the PC in hexadecimal. 324 DWORD64 PC = StackFrame.AddrPC.Offset; 325#if defined(_M_X64) || defined(_M_ARM64) 326 OS << format("0x%016llX", PC); 327#elif defined(_M_IX86) || defined(_M_ARM) 328 OS << format("0x%08lX", static_cast<DWORD>(PC)); 329#endif 330 331// Print the parameters. Assume there are four. 332#if defined(_M_X64) || defined(_M_ARM64) 333 OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", 334 StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], 335 StackFrame.Params[3]); 336#elif defined(_M_IX86) || defined(_M_ARM) 337 OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", 338 static_cast<DWORD>(StackFrame.Params[0]), 339 static_cast<DWORD>(StackFrame.Params[1]), 340 static_cast<DWORD>(StackFrame.Params[2]), 341 static_cast<DWORD>(StackFrame.Params[3])); 342#endif 343 // Verify the PC belongs to a module in this process. 344 if (!fSymGetModuleBase64(hProcess, PC)) { 345 OS << " <unknown module>\n"; 346 continue; 347 } 348 349 // Print the symbol name. 350 char buffer[512]; 351 IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 352 memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 353 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 354 symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 355 356 DWORD64 dwDisp; 357 if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 358 OS << '\n'; 359 continue; 360 } 361 362 buffer[511] = 0; 363 if (dwDisp > 0) 364 OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, 365 dwDisp); 366 else 367 OS << format(", %s", (const char*)symbol->Name); 368 369 // Print the source file and line number information. 370 IMAGEHLP_LINE64 line = {}; 371 DWORD dwLineDisp; 372 line.SizeOfStruct = sizeof(line); 373 if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 374 OS << format(", %s, line %lu", line.FileName, line.LineNumber); 375 if (dwLineDisp > 0) 376 OS << format(" + 0x%lX byte(s)", dwLineDisp); 377 } 378 379 OS << '\n'; 380 } 381} 382 383namespace llvm { 384 385//===----------------------------------------------------------------------===// 386//=== WARNING: Implementation here must contain only Win32 specific code 387//=== and must not be UNIX code 388//===----------------------------------------------------------------------===// 389 390#ifdef _MSC_VER 391/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report 392/// dialog. "retry" raises an exception which ultimately triggers our stack 393/// dumper. 394static LLVM_ATTRIBUTE_UNUSED int 395AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 396 // Set *Return to the retry code for the return value of _CrtDbgReport: 397 // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 398 // This may also trigger just-in-time debugging via DebugBreak(). 399 if (Return) 400 *Return = 1; 401 // Don't call _CrtDbgReport. 402 return TRUE; 403} 404 405#endif 406 407extern "C" void HandleAbort(int Sig) { 408 if (Sig == SIGABRT) { 409 LLVM_BUILTIN_TRAP; 410 } 411} 412 413static void InitializeThreading() { 414 if (CriticalSectionInitialized) 415 return; 416 417 // Now's the time to create the critical section. This is the first time 418 // through here, and there's only one thread. 419 InitializeCriticalSection(&CriticalSection); 420 CriticalSectionInitialized = true; 421} 422 423static void RegisterHandler() { 424 // If we cannot load up the APIs (which would be unexpected as they should 425 // exist on every version of Windows we support), we will bail out since 426 // there would be nothing to report. 427 if (!load64BitDebugHelp()) { 428 assert(false && "These APIs should always be available"); 429 return; 430 } 431 432 if (RegisteredUnhandledExceptionFilter) { 433 EnterCriticalSection(&CriticalSection); 434 return; 435 } 436 437 InitializeThreading(); 438 439 // Enter it immediately. Now if someone hits CTRL/C, the console handler 440 // can't proceed until the globals are updated. 441 EnterCriticalSection(&CriticalSection); 442 443 RegisteredUnhandledExceptionFilter = true; 444 OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 445 SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 446 447 // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 448 // else multi-threading problems will ensue. 449} 450 451// The public API 452bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { 453 RegisterHandler(); 454 455 if (CleanupExecuted) { 456 if (ErrMsg) 457 *ErrMsg = "Process terminating -- cannot register for removal"; 458 return true; 459 } 460 461 if (FilesToRemove == NULL) 462 FilesToRemove = new std::vector<std::string>; 463 464 FilesToRemove->push_back(Filename); 465 466 LeaveCriticalSection(&CriticalSection); 467 return false; 468} 469 470// The public API 471void sys::DontRemoveFileOnSignal(StringRef Filename) { 472 if (FilesToRemove == NULL) 473 return; 474 475 RegisterHandler(); 476 477 std::vector<std::string>::reverse_iterator I = 478 find(reverse(*FilesToRemove), Filename); 479 if (I != FilesToRemove->rend()) 480 FilesToRemove->erase(I.base()-1); 481 482 LeaveCriticalSection(&CriticalSection); 483} 484 485void sys::DisableSystemDialogsOnCrash() { 486 // Crash to stack trace handler on abort. 487 signal(SIGABRT, HandleAbort); 488 489 // The following functions are not reliably accessible on MinGW. 490#ifdef _MSC_VER 491 // We're already handling writing a "something went wrong" message. 492 _set_abort_behavior(0, _WRITE_ABORT_MSG); 493 // Disable Dr. Watson. 494 _set_abort_behavior(0, _CALL_REPORTFAULT); 495 _CrtSetReportHook(AvoidMessageBoxHook); 496#endif 497 498 // Disable standard error dialog box. 499 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 500 SEM_NOOPENFILEERRORBOX); 501 _set_error_mode(_OUT_TO_STDERR); 502} 503 504/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the 505/// process, print a stack trace and then exit. 506void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, 507 bool DisableCrashReporting) { 508 ::Argv0 = Argv0; 509 510 if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) 511 Process::PreventCoreFiles(); 512 513 DisableSystemDialogsOnCrash(); 514 RegisterHandler(); 515 LeaveCriticalSection(&CriticalSection); 516} 517} 518 519#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 520// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is 521// missing it but mingw-w64 has it. 522extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); 523#endif 524 525void llvm::sys::PrintStackTrace(raw_ostream &OS) { 526 STACKFRAME64 StackFrame = {}; 527 CONTEXT Context = {}; 528 ::RtlCaptureContext(&Context); 529#if defined(_M_X64) 530 StackFrame.AddrPC.Offset = Context.Rip; 531 StackFrame.AddrStack.Offset = Context.Rsp; 532 StackFrame.AddrFrame.Offset = Context.Rbp; 533#elif defined(_M_IX86) 534 StackFrame.AddrPC.Offset = Context.Eip; 535 StackFrame.AddrStack.Offset = Context.Esp; 536 StackFrame.AddrFrame.Offset = Context.Ebp; 537#elif defined(_M_ARM64) 538 StackFrame.AddrPC.Offset = Context.Pc; 539 StackFrame.AddrStack.Offset = Context.Sp; 540 StackFrame.AddrFrame.Offset = Context.Fp; 541#elif defined(_M_ARM) 542 StackFrame.AddrPC.Offset = Context.Pc; 543 StackFrame.AddrStack.Offset = Context.Sp; 544 StackFrame.AddrFrame.Offset = Context.R11; 545#endif 546 StackFrame.AddrPC.Mode = AddrModeFlat; 547 StackFrame.AddrStack.Mode = AddrModeFlat; 548 StackFrame.AddrFrame.Mode = AddrModeFlat; 549 PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), 550 StackFrame, &Context); 551} 552 553 554void llvm::sys::SetInterruptFunction(void (*IF)()) { 555 RegisterHandler(); 556 InterruptFunction = IF; 557 LeaveCriticalSection(&CriticalSection); 558} 559 560 561/// Add a function to be called when a signal is delivered to the process. The 562/// handler can have a cookie passed to it to identify what instance of the 563/// handler it is. 564void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, 565 void *Cookie) { 566 insertSignalHandler(FnPtr, Cookie); 567 RegisterHandler(); 568 LeaveCriticalSection(&CriticalSection); 569} 570 571static void Cleanup() { 572 if (CleanupExecuted) 573 return; 574 575 EnterCriticalSection(&CriticalSection); 576 577 // Prevent other thread from registering new files and directories for 578 // removal, should we be executing because of the console handler callback. 579 CleanupExecuted = true; 580 581 // FIXME: open files cannot be deleted. 582 if (FilesToRemove != NULL) 583 while (!FilesToRemove->empty()) { 584 llvm::sys::fs::remove(FilesToRemove->back()); 585 FilesToRemove->pop_back(); 586 } 587 llvm::sys::RunSignalHandlers(); 588 LeaveCriticalSection(&CriticalSection); 589} 590 591void llvm::sys::RunInterruptHandlers() { 592 // The interrupt handler may be called from an interrupt, but it may also be 593 // called manually (such as the case of report_fatal_error with no registered 594 // error handler). We must ensure that the critical section is properly 595 // initialized. 596 InitializeThreading(); 597 Cleanup(); 598} 599 600/// Find the Windows Registry Key for a given location. 601/// 602/// \returns a valid HKEY if the location exists, else NULL. 603static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { 604 HKEY Key; 605 if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, 606 RegistryLocation.str().c_str(), 0, 607 KEY_QUERY_VALUE | KEY_READ, &Key)) 608 return NULL; 609 610 return Key; 611} 612 613/// Populate ResultDirectory with the value for "DumpFolder" for a given 614/// Windows Registry key. 615/// 616/// \returns true if a valid value for DumpFolder exists, false otherwise. 617static bool GetDumpFolder(HKEY Key, 618 llvm::SmallVectorImpl<char> &ResultDirectory) { 619 using llvm::sys::windows::UTF16ToUTF8; 620 621 if (!Key) 622 return false; 623 624 DWORD BufferLengthBytes = 0; 625 626 if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 627 NULL, NULL, &BufferLengthBytes)) 628 return false; 629 630 SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); 631 632 if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, 633 NULL, Buffer.data(), &BufferLengthBytes)) 634 return false; 635 636 DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); 637 638 if (!ExpandBufferSize) 639 return false; 640 641 SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); 642 643 if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), 644 ExpandBuffer.data(), 645 ExpandBufferSize)) 646 return false; 647 648 if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) 649 return false; 650 651 return true; 652} 653 654/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of 655/// "DumpType" for a given Windows Registry key. 656/// 657/// According to 658/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx 659/// valid values for DumpType are: 660/// * 0: Custom dump 661/// * 1: Mini dump 662/// * 2: Full dump 663/// If "Custom dump" is specified then the "CustomDumpFlags" field is read 664/// containing a bitwise combination of MINIDUMP_TYPE values. 665/// 666/// \returns true if a valid value for ResultType can be set, false otherwise. 667static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { 668 if (!Key) 669 return false; 670 671 DWORD DumpType; 672 DWORD TypeSize = sizeof(DumpType); 673 if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, 674 NULL, &DumpType, 675 &TypeSize)) 676 return false; 677 678 switch (DumpType) { 679 case 0: { 680 DWORD Flags = 0; 681 if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", 682 RRF_RT_REG_DWORD, NULL, &Flags, 683 &TypeSize)) 684 return false; 685 686 ResultType = static_cast<MINIDUMP_TYPE>(Flags); 687 break; 688 } 689 case 1: 690 ResultType = MiniDumpNormal; 691 break; 692 case 2: 693 ResultType = MiniDumpWithFullMemory; 694 break; 695 default: 696 return false; 697 } 698 return true; 699} 700 701/// Write a Windows dump file containing process information that can be 702/// used for post-mortem debugging. 703/// 704/// \returns zero error code if a mini dump created, actual error code 705/// otherwise. 706static std::error_code WINAPI 707WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { 708 using namespace llvm; 709 using namespace llvm::sys; 710 711 std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); 712 StringRef ProgramName; 713 714 if (MainExecutableName.empty()) { 715 // If we can't get the executable filename, 716 // things are in worse shape than we realize 717 // and we should just bail out. 718 return mapWindowsError(::GetLastError()); 719 } 720 721 ProgramName = path::filename(MainExecutableName.c_str()); 722 723 // The Windows Registry location as specified at 724 // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx 725 // "Collecting User-Mode Dumps" that may optionally be set to collect crash 726 // dumps in a specified location. 727 StringRef LocalDumpsRegistryLocation = 728 "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; 729 730 // The key pointing to the Registry location that may contain global crash 731 // dump settings. This will be NULL if the location can not be found. 732 ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); 733 734 // The key pointing to the Registry location that may contain 735 // application-specific crash dump settings. This will be NULL if the 736 // location can not be found. 737 ScopedRegHandle AppSpecificKey( 738 FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); 739 740 // Look to see if a dump type is specified in the registry; first with the 741 // app-specific key and failing that with the global key. If none are found 742 // default to a normal dump (GetDumpType will return false either if the key 743 // is NULL or if there is no valid DumpType value at its location). 744 MINIDUMP_TYPE DumpType; 745 if (!GetDumpType(AppSpecificKey, DumpType)) 746 if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) 747 DumpType = MiniDumpNormal; 748 749 // Look to see if a dump location is specified in the registry; first with the 750 // app-specific key and failing that with the global key. If none are found 751 // we'll just create the dump file in the default temporary file location 752 // (GetDumpFolder will return false either if the key is NULL or if there is 753 // no valid DumpFolder value at its location). 754 bool ExplicitDumpDirectorySet = true; 755 SmallString<MAX_PATH> DumpDirectory; 756 if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) 757 if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) 758 ExplicitDumpDirectorySet = false; 759 760 int FD; 761 SmallString<MAX_PATH> DumpPath; 762 763 if (ExplicitDumpDirectorySet) { 764 if (std::error_code EC = fs::create_directories(DumpDirectory)) 765 return EC; 766 if (std::error_code EC = fs::createUniqueFile( 767 Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, 768 DumpPath)) 769 return EC; 770 } else if (std::error_code EC = 771 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) 772 return EC; 773 774 // Our support functions return a file descriptor but Windows wants a handle. 775 ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); 776 777 if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), 778 FileHandle, DumpType, ExceptionInfo, NULL, NULL)) 779 return mapWindowsError(::GetLastError()); 780 781 llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; 782 return std::error_code(); 783} 784 785static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 786 Cleanup(); 787 788 // We'll automatically write a Minidump file here to help diagnose 789 // the nasty sorts of crashes that aren't 100% reproducible from a set of 790 // inputs (or in the event that the user is unable or unwilling to provide a 791 // reproducible case). 792 if (!llvm::sys::Process::AreCoreFilesPrevented()) { 793 MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; 794 ExceptionInfo.ThreadId = ::GetCurrentThreadId(); 795 ExceptionInfo.ExceptionPointers = ep; 796 ExceptionInfo.ClientPointers = FALSE; 797 798 if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) 799 llvm::errs() << "Could not write crash dump file: " << EC.message() 800 << "\n"; 801 } 802 803 // Initialize the STACKFRAME structure. 804 STACKFRAME64 StackFrame = {}; 805 806#if defined(_M_X64) 807 StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; 808 StackFrame.AddrPC.Mode = AddrModeFlat; 809 StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; 810 StackFrame.AddrStack.Mode = AddrModeFlat; 811 StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; 812 StackFrame.AddrFrame.Mode = AddrModeFlat; 813#elif defined(_M_IX86) 814 StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 815 StackFrame.AddrPC.Mode = AddrModeFlat; 816 StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 817 StackFrame.AddrStack.Mode = AddrModeFlat; 818 StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 819 StackFrame.AddrFrame.Mode = AddrModeFlat; 820#elif defined(_M_ARM64) || defined(_M_ARM) 821 StackFrame.AddrPC.Offset = ep->ContextRecord->Pc; 822 StackFrame.AddrPC.Mode = AddrModeFlat; 823 StackFrame.AddrStack.Offset = ep->ContextRecord->Sp; 824 StackFrame.AddrStack.Mode = AddrModeFlat; 825#if defined(_M_ARM64) 826 StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp; 827#else 828 StackFrame.AddrFrame.Offset = ep->ContextRecord->R11; 829#endif 830 StackFrame.AddrFrame.Mode = AddrModeFlat; 831#endif 832 833 HANDLE hProcess = GetCurrentProcess(); 834 HANDLE hThread = GetCurrentThread(); 835 PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, 836 ep->ContextRecord); 837 838 _exit(ep->ExceptionRecord->ExceptionCode); 839} 840 841static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 842 // We are running in our very own thread, courtesy of Windows. 843 EnterCriticalSection(&CriticalSection); 844 Cleanup(); 845 846 // If an interrupt function has been set, go and run one it; otherwise, 847 // the process dies. 848 void (*IF)() = InterruptFunction; 849 InterruptFunction = 0; // Don't run it on another CTRL-C. 850 851 if (IF) { 852 // Note: if the interrupt function throws an exception, there is nothing 853 // to catch it in this thread so it will kill the process. 854 IF(); // Run it now. 855 LeaveCriticalSection(&CriticalSection); 856 return TRUE; // Don't kill the process. 857 } 858 859 // Allow normal processing to take place; i.e., the process dies. 860 LeaveCriticalSection(&CriticalSection); 861 return FALSE; 862} 863 864#if __MINGW32__ 865 // We turned these warnings off for this file so that MinGW-g++ doesn't 866 // complain about the ll format specifiers used. Now we are turning the 867 // warnings back on. If MinGW starts to support diagnostic stacks, we can 868 // replace this with a pop. 869 #pragma GCC diagnostic warning "-Wformat" 870 #pragma GCC diagnostic warning "-Wformat-extra-args" 871#endif 872