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