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