33 #pragma comment(lib, "psapi.lib")
35 #if (HAVE_LIBPSAPI != 1)
36 #error "libpsapi.a should be present"
46 #pragma GCC diagnostic ignored "-Wformat"
47 #pragma GCC diagnostic ignored "-Wformat-extra-args"
49 #if !defined(__MINGW64_VERSION_MAJOR)
54 typedef struct _IMAGEHLP_LINE64 {
60 } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
62 typedef struct _IMAGEHLP_SYMBOL64 {
69 } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
71 typedef struct _tagADDRESS64 {
75 } ADDRESS64, *LPADDRESS64;
77 typedef struct _KDHELP64 {
79 DWORD ThCallbackStack;
80 DWORD ThCallbackBStore;
83 DWORD64 KiCallUserMode;
84 DWORD64 KeUserCallbackDispatcher;
85 DWORD64 SystemRangeStart;
86 DWORD64 KiUserExceptionDispatcher;
90 } KDHELP64, *PKDHELP64;
92 typedef struct _tagSTACKFRAME64 {
104 } STACKFRAME64, *LPSTACKFRAME64;
105 #endif // !defined(__MINGW64_VERSION_MAJOR)
106 #endif // __MINGW32__
108 typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
109 DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
110 LPDWORD lpNumberOfBytesRead);
112 typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
115 typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
118 typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
119 HANDLE hThread, LPADDRESS64 lpaddr);
121 typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
122 PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
123 PFUNCTION_TABLE_ACCESS_ROUTINE64,
124 PGET_MODULE_BASE_ROUTINE64,
125 PTRANSLATE_ADDRESS_ROUTINE64);
126 static fpStackWalk64 fStackWalk64;
128 typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
129 static fpSymGetModuleBase64 fSymGetModuleBase64;
131 typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
132 PDWORD64, PIMAGEHLP_SYMBOL64);
133 static fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
135 typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
136 PDWORD, PIMAGEHLP_LINE64);
137 static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
139 typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
140 static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
142 typedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
143 static fpSymSetOptions fSymSetOptions;
145 typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
146 static fpSymInitialize fSymInitialize;
148 static bool load64BitDebugHelp(
void) {
149 HMODULE hLib = ::LoadLibraryW(L
"Dbghelp.dll");
151 fStackWalk64 = (fpStackWalk64)
152 ::GetProcAddress(hLib,
"StackWalk64");
153 fSymGetModuleBase64 = (fpSymGetModuleBase64)
154 ::GetProcAddress(hLib,
"SymGetModuleBase64");
155 fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
156 ::GetProcAddress(hLib,
"SymGetSymFromAddr64");
157 fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
158 ::GetProcAddress(hLib,
"SymGetLineFromAddr64");
159 fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
160 ::GetProcAddress(hLib,
"SymFunctionTableAccess64");
161 fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib,
"SymSetOptions");
162 fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib,
"SymInitialize");
164 return fStackWalk64 && fSymInitialize && fSymSetOptions;
168 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
169 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
172 static void (*InterruptFunction)() = 0;
174 static std::vector<std::string> *FilesToRemove = NULL;
175 static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
176 static bool RegisteredUnhandledExceptionFilter =
false;
177 static bool CleanupExecuted =
false;
178 static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
183 static CRITICAL_SECTION CriticalSection;
184 static bool CriticalSectionInitialized =
false;
187 HANDLE hThread, STACKFRAME64 &StackFrame,
197 fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
198 fSymInitialize(hProcess, NULL, TRUE);
201 if (!fStackWalk64(machineType, hProcess, hThread, &StackFrame, Context, 0,
202 fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) {
206 if (StackFrame.AddrFrame.Offset == 0)
209 using namespace llvm;
211 DWORD64 PC = StackFrame.AddrPC.Offset;
213 OS <<
format(
"0x%016llX", PC);
214 #elif defined(_M_IX86)
215 OS <<
format(
"0x%08lX", static_cast<DWORD>(PC));
220 OS <<
format(
" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
221 StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
222 StackFrame.Params[3]);
223 #elif defined(_M_IX86)
224 OS <<
format(
" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
225 static_cast<DWORD>(StackFrame.Params[0]),
226 static_cast<DWORD>(StackFrame.Params[1]),
227 static_cast<DWORD>(StackFrame.Params[2]),
228 static_cast<DWORD>(StackFrame.Params[3]));
231 if (!fSymGetModuleBase64(hProcess, PC)) {
232 OS <<
" <unknown module>\n";
238 IMAGEHLP_SYMBOL64 *symbol =
reinterpret_cast<IMAGEHLP_SYMBOL64 *
>(buffer);
239 memset(symbol, 0,
sizeof(IMAGEHLP_SYMBOL64));
240 symbol->SizeOfStruct =
sizeof(IMAGEHLP_SYMBOL64);
241 symbol->MaxNameLength = 512 -
sizeof(IMAGEHLP_SYMBOL64);
244 if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
251 OS <<
format(
", %s() + 0x%llX bytes(s)", (
const char*)symbol->Name,
254 OS <<
format(
", %s", (
const char*)symbol->Name);
257 IMAGEHLP_LINE64 line = {};
259 line.SizeOfStruct =
sizeof(line);
260 if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
261 OS <<
format(
", %s, line %lu", line.FileName, line.LineNumber);
263 OS <<
format(
" + 0x%lX byte(s)", dwLineDisp);
282 AvoidMessageBoxHook(
int ReportType,
char *Message,
int *
Return) {
294 extern "C" void HandleAbort(
int Sig) {
295 if (Sig == SIGABRT) {
300 static void InitializeThreading() {
301 if (CriticalSectionInitialized)
306 InitializeCriticalSection(&CriticalSection);
307 CriticalSectionInitialized =
true;
310 static void RegisterHandler() {
314 if (!load64BitDebugHelp()) {
315 assert(
false &&
"These APIs should always be available");
319 if (RegisteredUnhandledExceptionFilter) {
320 EnterCriticalSection(&CriticalSection);
324 InitializeThreading();
328 EnterCriticalSection(&CriticalSection);
330 RegisteredUnhandledExceptionFilter =
true;
331 OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
332 SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
342 if (CleanupExecuted) {
344 *ErrMsg =
"Process terminating -- cannot register for removal";
348 if (FilesToRemove == NULL)
349 FilesToRemove =
new std::vector<std::string>;
351 FilesToRemove->push_back(Filename);
353 LeaveCriticalSection(&CriticalSection);
359 if (FilesToRemove == NULL)
364 std::vector<std::string>::reverse_iterator
I =
365 std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
366 if (I != FilesToRemove->rend())
367 FilesToRemove->erase(I.base()-1);
369 LeaveCriticalSection(&CriticalSection);
374 signal(SIGABRT, HandleAbort);
379 _set_abort_behavior(0, _WRITE_ABORT_MSG);
381 _set_abort_behavior(0, _CALL_REPORTFAULT);
382 _CrtSetReportHook(AvoidMessageBoxHook);
386 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
387 SEM_NOOPENFILEERRORBOX);
388 _set_error_mode(_OUT_TO_STDERR);
396 LeaveCriticalSection(&CriticalSection);
400 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
403 extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord);
408 STACKFRAME64 StackFrame = {};
409 CONTEXT Context = {};
410 ::RtlCaptureContext(&Context);
412 StackFrame.AddrPC.Offset = Context.Rip;
413 StackFrame.AddrStack.Offset = Context.Rsp;
414 StackFrame.AddrFrame.Offset = Context.Rbp;
416 StackFrame.AddrPC.Offset = Context.Eip;
417 StackFrame.AddrStack.Offset = Context.Esp;
418 StackFrame.AddrFrame.Offset = Context.Ebp;
420 StackFrame.AddrPC.Mode = AddrModeFlat;
421 StackFrame.AddrStack.Mode = AddrModeFlat;
422 StackFrame.AddrFrame.Mode = AddrModeFlat;
423 PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),
424 StackFrame, &Context);
430 InterruptFunction = IF;
431 LeaveCriticalSection(&CriticalSection);
439 if (CallBacksToRun == 0)
440 CallBacksToRun =
new std::vector<std::pair<void(*)(void*), void*> >();
441 CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
443 LeaveCriticalSection(&CriticalSection);
450 EnterCriticalSection(&CriticalSection);
454 CleanupExecuted =
true;
458 if (FilesToRemove != NULL)
459 while (!FilesToRemove->empty()) {
461 FilesToRemove->pop_back();
465 for (
auto &I : *CallBacksToRun)
468 LeaveCriticalSection(&CriticalSection);
476 InitializeThreading();
480 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
484 STACKFRAME64 StackFrame = {};
487 StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
488 StackFrame.AddrPC.Mode = AddrModeFlat;
489 StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
490 StackFrame.AddrStack.Mode = AddrModeFlat;
491 StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
492 StackFrame.AddrFrame.Mode = AddrModeFlat;
493 #elif defined(_M_IX86)
494 StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
495 StackFrame.AddrPC.Mode = AddrModeFlat;
496 StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
497 StackFrame.AddrStack.Mode = AddrModeFlat;
498 StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
499 StackFrame.AddrFrame.Mode = AddrModeFlat;
502 HANDLE hProcess = GetCurrentProcess();
503 HANDLE hThread = GetCurrentThread();
504 PrintStackTraceForThread(
llvm::errs(), hProcess, hThread, StackFrame,
507 _exit(ep->ExceptionRecord->ExceptionCode);
510 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
512 EnterCriticalSection(&CriticalSection);
517 void (*IF)() = InterruptFunction;
518 InterruptFunction = 0;
524 LeaveCriticalSection(&CriticalSection);
529 LeaveCriticalSection(&CriticalSection);
538 #pragma GCC diagnostic warning "-Wformat"
539 #pragma GCC diagnostic warning "-Wformat-extra-args"
void PrintStackTraceOnErrorSignal(bool DisableCrashReporting=false)
When an error signal (such as SIBABRT or SIGSEGV) is delivered to the process, print a stack trace an...
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
void DisableSystemDialogsOnCrash()
Disable all system dialog boxes that appear when the process crashes.
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
void PrintStackTrace(raw_ostream &OS)
Print the stack trace using the given raw_ostream object.
void RunInterruptHandlers()
This function runs all the registered interrupt handlers, including the removal of files registered b...
#define LLVM_ATTRIBUTE_UNUSED
void DontRemoveFileOnSignal(StringRef Filename)
This function removes a file from the list of files to be removed on signal delivery.
#define LLVM_BUILTIN_TRAP
LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands to an expression which states that ...
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...
This class implements an extremely fast bulk output stream that can only output to a stream...
StringRef - Represent a constant reference to a string, i.e.
void SetInterruptFunction(void(*IF)())
This function registers a function to be called when the user "interrupts" the program (typically by ...
void AddSignalHandler(void(*FnPtr)(void *), void *Cookie)
AddSignalHandler - Add a function to be called when an abort/kill signal is delivered to the process...