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