Signals.inc revision 309124
125537Sdfr//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===//
225537Sdfr//
325537Sdfr//                     The LLVM Compiler Infrastructure
425537Sdfr//
525537Sdfr// This file is distributed under the University of Illinois Open Source
625537Sdfr// License. See LICENSE.TXT for details.
725537Sdfr//
825537Sdfr//===----------------------------------------------------------------------===//
925537Sdfr//
1025537Sdfr// This file provides the Win32 specific implementation of the Signals class.
1125537Sdfr//
1225537Sdfr//===----------------------------------------------------------------------===//
1325537Sdfr#include "llvm/Support/FileSystem.h"
1425537Sdfr#include "llvm/Support/Path.h"
1525537Sdfr#include "llvm/Support/Process.h"
1625537Sdfr#include "llvm/Support/WindowsError.h"
1725537Sdfr#include <algorithm>
1825537Sdfr#include <io.h>
1925537Sdfr#include <signal.h>
2025537Sdfr#include <stdio.h>
2125537Sdfr
2225537Sdfr#include "llvm/Support/Format.h"
2325537Sdfr#include "llvm/Support/raw_ostream.h"
2425537Sdfr
2525537Sdfr// The Windows.h header must be after LLVM and standard headers.
2643301Sdillon#include "WindowsSupport.h"
2725537Sdfr
2825537Sdfr#ifdef __MINGW32__
2940159Speter #include <imagehlp.h>
3040159Speter#else
3125537Sdfr #include <dbghelp.h>
3225537Sdfr#endif
3325537Sdfr#include <psapi.h>
3425537Sdfr
3525537Sdfr#ifdef _MSC_VER
3625537Sdfr #pragma comment(lib, "psapi.lib")
3725537Sdfr#elif __MINGW32__
3825537Sdfr #if (HAVE_LIBPSAPI != 1)
3925537Sdfr  #error "libpsapi.a should be present"
4040159Speter #endif
4125537Sdfr // The version of g++ that comes with MinGW does *not* properly understand
4225537Sdfr // the ll format specifier for printf. However, MinGW passes the format
4331675Sdyson // specifiers on to the MSVCRT entirely, and the CRT understands the ll
4440159Speter // specifier. So these warnings are spurious in this case. Since we compile
4540159Speter // with -Wall, this will generate these warnings which should be ignored. So
4640159Speter // we will turn off the warnings for this just file. However, MinGW also does
4740159Speter // not support push and pop for diagnostics, so we have to manually turn it
4840159Speter // back on at the end of the file.
4925537Sdfr #pragma GCC diagnostic ignored "-Wformat"
5040961Speter #pragma GCC diagnostic ignored "-Wformat-extra-args"
5140961Speter
5240961Speter #if !defined(__MINGW64_VERSION_MAJOR)
5340961Speter // MinGW.org does not have updated support for the 64-bit versions of the
5432153Sbde // DebugHlp APIs. So we will have to load them manually. The structures and
5531324Sbde // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
5640906Speter // and adjusted for brevity.
5731324Sbde typedef struct _IMAGEHLP_LINE64 {
5825537Sdfr   DWORD    SizeOfStruct;
5925537Sdfr   PVOID    Key;
6025537Sdfr   DWORD    LineNumber;
6125537Sdfr   PCHAR    FileName;
6225537Sdfr   DWORD64  Address;
6325537Sdfr } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
6425537Sdfr
6525537Sdfr typedef struct _IMAGEHLP_SYMBOL64 {
6625537Sdfr   DWORD   SizeOfStruct;
6725537Sdfr   DWORD64 Address;
6825537Sdfr   DWORD   Size;
6925537Sdfr   DWORD   Flags;
7025537Sdfr   DWORD   MaxNameLength;
7140159Speter   CHAR    Name[1];
7225537Sdfr } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
7325537Sdfr
7425537Sdfr typedef struct _tagADDRESS64 {
7525537Sdfr   DWORD64       Offset;
7625537Sdfr   WORD          Segment;
7725537Sdfr   ADDRESS_MODE  Mode;
7825537Sdfr } ADDRESS64, *LPADDRESS64;
7925537Sdfr
8025537Sdfr typedef struct _KDHELP64 {
8125537Sdfr   DWORD64   Thread;
8240395Speter   DWORD   ThCallbackStack;
8325537Sdfr   DWORD   ThCallbackBStore;
8425537Sdfr   DWORD   NextCallback;
8525537Sdfr   DWORD   FramePointer;
8625537Sdfr   DWORD64   KiCallUserMode;
8725537Sdfr   DWORD64   KeUserCallbackDispatcher;
8825537Sdfr   DWORD64   SystemRangeStart;
8925537Sdfr   DWORD64   KiUserExceptionDispatcher;
9025537Sdfr   DWORD64   StackBase;
9125537Sdfr   DWORD64   StackLimit;
9225537Sdfr   DWORD64   Reserved[5];
9325537Sdfr } KDHELP64, *PKDHELP64;
9425537Sdfr
9525537Sdfr typedef struct _tagSTACKFRAME64 {
9625537Sdfr   ADDRESS64   AddrPC;
9725537Sdfr   ADDRESS64   AddrReturn;
9825537Sdfr   ADDRESS64   AddrFrame;
9940159Speter   ADDRESS64   AddrStack;
10025537Sdfr   ADDRESS64   AddrBStore;
10125537Sdfr   PVOID       FuncTableEntry;
10225537Sdfr   DWORD64     Params[4];
10325537Sdfr   BOOL        Far;
10425537Sdfr   BOOL        Virtual;
10525537Sdfr   DWORD64     Reserved[3];
10640159Speter   KDHELP64    KdHelp;
10740159Speter } STACKFRAME64, *LPSTACKFRAME64;
10825537Sdfr #endif // !defined(__MINGW64_VERSION_MAJOR)
10925537Sdfr#endif // __MINGW32__
11025537Sdfr
11140159Spetertypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
11240159Speter                      DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
11340159Speter                      LPDWORD lpNumberOfBytesRead);
11440159Speter
11540159Spetertypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
11640159Speter                      DWORD64 AddrBase);
11740159Speter
11840159Spetertypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
11925537Sdfr                      DWORD64 Address);
12025537Sdfr
12125537Sdfrtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
12225537Sdfr                      HANDLE hThread, LPADDRESS64 lpaddr);
12325537Sdfr
12425537Sdfrtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
12525537Sdfr                                          PMINIDUMP_EXCEPTION_INFORMATION,
12641055Speter                                          PMINIDUMP_USER_STREAM_INFORMATION,
12741055Speter                                          PMINIDUMP_CALLBACK_INFORMATION);
12841055Speterstatic fpMiniDumpWriteDump fMiniDumpWriteDump;
12941055Speter
13041055Spetertypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
13125537Sdfr                      PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
13225537Sdfr                      PFUNCTION_TABLE_ACCESS_ROUTINE64,
13325537Sdfr                      PGET_MODULE_BASE_ROUTINE64,
13425537Sdfr                      PTRANSLATE_ADDRESS_ROUTINE64);
13525537Sdfrstatic fpStackWalk64 fStackWalk64;
13625537Sdfr
13725537Sdfrtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
13825537Sdfrstatic fpSymGetModuleBase64 fSymGetModuleBase64;
13925537Sdfr
14025537Sdfrtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
14125537Sdfr                      PDWORD64, PIMAGEHLP_SYMBOL64);
14225537Sdfrstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
14341055Speter
14441055Spetertypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
14525537Sdfr                      PDWORD, PIMAGEHLP_LINE64);
14625537Sdfrstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
14741055Speter
14825537Sdfrtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,
14925537Sdfr                                           PIMAGEHLP_MODULE64 ModuleInfo);
15041055Speterstatic fpSymGetModuleInfo64 fSymGetModuleInfo64;
15125537Sdfr
15225537Sdfrtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
15325537Sdfrstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
15431675Sdyson
15525537Sdfrtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
15631675Sdysonstatic fpSymSetOptions fSymSetOptions;
15731675Sdyson
15831675Sdysontypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
15931675Sdysonstatic fpSymInitialize fSymInitialize;
16031675Sdyson
16131675Sdysontypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
16231675Sdysonstatic fpEnumerateLoadedModules fEnumerateLoadedModules;
16331675Sdyson
16431675Sdysonstatic bool load64BitDebugHelp(void) {
16531675Sdyson  HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
16625537Sdfr  if (hLib) {
16730994Sphk    fMiniDumpWriteDump = (fpMiniDumpWriteDump)
16830994Sphk                      ::GetProcAddress(hLib, "MiniDumpWriteDump");
16925537Sdfr    fStackWalk64 = (fpStackWalk64)
17025537Sdfr                      ::GetProcAddress(hLib, "StackWalk64");
17125537Sdfr    fSymGetModuleBase64 = (fpSymGetModuleBase64)
17241055Speter                      ::GetProcAddress(hLib, "SymGetModuleBase64");
17325537Sdfr    fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
17425537Sdfr                      ::GetProcAddress(hLib, "SymGetSymFromAddr64");
17525537Sdfr    fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
17625537Sdfr                      ::GetProcAddress(hLib, "SymGetLineFromAddr64");
17741055Speter    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)
17841055Speter                      ::GetProcAddress(hLib, "SymGetModuleInfo64");
17941055Speter    fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
18041055Speter                     ::GetProcAddress(hLib, "SymFunctionTableAccess64");
18141055Speter    fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
18241055Speter    fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
18341055Speter    fEnumerateLoadedModules = (fpEnumerateLoadedModules)
18441055Speter      ::GetProcAddress(hLib, "EnumerateLoadedModules64");
18541055Speter  }
18641055Speter  return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
18741055Speter}
18841055Speter
18941055Speterusing namespace llvm;
19041055Speter
19141055Speter// Forward declare.
19241055Speterstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
19341055Speterstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
19441055Speter
19541055Speter// InterruptFunction - The function to call if ctrl-c is pressed.
19641055Speterstatic void (*InterruptFunction)() = 0;
19741055Speter
19841055Speterstatic std::vector<std::string> *FilesToRemove = NULL;
19941055Speterstatic bool RegisteredUnhandledExceptionFilter = false;
20041055Speterstatic bool CleanupExecuted = false;
20141055Speterstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
20241055Speter
20341055Speter// Windows creates a new thread to execute the console handler when an event
20441055Speter// (such as CTRL/C) occurs.  This causes concurrency issues with the above
20541055Speter// globals which this critical section addresses.
20641055Speterstatic CRITICAL_SECTION CriticalSection;
20741055Speterstatic bool CriticalSectionInitialized = false;
20841055Speter
20941055Speterstatic StringRef Argv0;
21041055Speter
21141055Speterenum {
21241055Speter#if defined(_M_X64)
21341055Speter  NativeMachineType = IMAGE_FILE_MACHINE_AMD64
21441055Speter#else
21541055Speter  NativeMachineType = IMAGE_FILE_MACHINE_I386
21641055Speter#endif
21741055Speter};
21841055Speter
21941055Speterstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
22041055Speter                                              HANDLE hProcess, HANDLE hThread,
22141055Speter                                              STACKFRAME64 &StackFrameOrig,
22241055Speter                                              CONTEXT *ContextOrig) {
22341055Speter  // StackWalk64 modifies the incoming stack frame and context, so copy them.
22441055Speter  STACKFRAME64 StackFrame = StackFrameOrig;
22541055Speter
22641055Speter  // Copy the register context so that we don't modify it while we unwind. We
22741055Speter  // could use InitializeContext + CopyContext, but that's only required to get
22841055Speter  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the
22941055Speter  // flag set to indicate that there's less data.
23041055Speter  CONTEXT Context = *ContextOrig;
23141055Speter  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
23241055Speter
23341055Speter  static void *StackTrace[256];
23441055Speter  size_t Depth = 0;
23525537Sdfr  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
23625537Sdfr                      &Context, 0, fSymFunctionTableAccess64,
23725537Sdfr                      fSymGetModuleBase64, 0)) {
23825537Sdfr    if (StackFrame.AddrFrame.Offset == 0)
23925537Sdfr      break;
24042755Speter    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;
24140861Speter    if (Depth >= array_lengthof(StackTrace))
24225537Sdfr      break;
24325537Sdfr  }
24425537Sdfr
24525537Sdfr  return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);
24625537Sdfr}
24725537Sdfr
24825537Sdfrnamespace {
24925537Sdfrstruct FindModuleData {
25025537Sdfr  void **StackTrace;
25140861Speter  int Depth;
25240861Speter  const char **Modules;
25340861Speter  intptr_t *Offsets;
25440861Speter  StringSaver *StrPool;
25540861Speter};
25640861Speter}
25725537Sdfr
25842755Speterstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName,
25925537Sdfr                                        DWORD64 ModuleBase, ULONG ModuleSize,
26025537Sdfr                                        void *VoidData) {
26125537Sdfr  FindModuleData *Data = (FindModuleData*)VoidData;
26242755Speter  intptr_t Beg = ModuleBase;
26342755Speter  intptr_t End = Beg + ModuleSize;
26442755Speter  for (int I = 0; I < Data->Depth; I++) {
26542755Speter    if (Data->Modules[I])
26642755Speter      continue;
26742755Speter    intptr_t Addr = (intptr_t)Data->StackTrace[I];
26842755Speter    if (Beg <= Addr && Addr < End) {
26942755Speter      Data->Modules[I] = Data->StrPool->save(ModuleName);
27042755Speter      Data->Offsets[I] = Addr - Beg;
27142755Speter    }
27225537Sdfr  }
27325537Sdfr  return TRUE;
27425537Sdfr}
27525537Sdfr
27640861Speterstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
27725537Sdfr                                  const char **Modules, intptr_t *Offsets,
27825537Sdfr                                  const char *MainExecutableName,
27925537Sdfr                                  StringSaver &StrPool) {
28042755Speter  if (!fEnumerateLoadedModules)
28142755Speter    return false;
28242755Speter  FindModuleData Data;
28342755Speter  Data.StackTrace = StackTrace;
28442755Speter  Data.Depth = Depth;
28542755Speter  Data.Modules = Modules;
28642755Speter  Data.Offsets = Offsets;
28742755Speter  Data.StrPool = &StrPool;
28825537Sdfr  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);
28925537Sdfr  return true;
29040861Speter}
29140861Speter
29225537Sdfrstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
29325537Sdfr                                     HANDLE hThread, STACKFRAME64 &StackFrame,
29425537Sdfr                                     CONTEXT *Context) {
29525537Sdfr  // Initialize the symbol handler.
29625537Sdfr  fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
29725537Sdfr  fSymInitialize(hProcess, NULL, TRUE);
29825537Sdfr
29940861Speter  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs
30025537Sdfr  // and DWARF, so it should do a good job regardless of what debug info or
30140861Speter  // linker is in use.
30240861Speter  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,
30340861Speter                                        Context)) {
30440861Speter    return;
30540861Speter  }
30625537Sdfr
30740861Speter  while (true) {
30840861Speter    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
30940861Speter                      Context, 0, fSymFunctionTableAccess64,
31025537Sdfr                      fSymGetModuleBase64, 0)) {
31125537Sdfr      break;
31240861Speter    }
31325537Sdfr
31425537Sdfr    if (StackFrame.AddrFrame.Offset == 0)
31540861Speter      break;
31640861Speter
31740861Speter    using namespace llvm;
31825537Sdfr    // Print the PC in hexadecimal.
31925537Sdfr    DWORD64 PC = StackFrame.AddrPC.Offset;
32025537Sdfr#if defined(_M_X64)
32125537Sdfr    OS << format("0x%016llX", PC);
32225537Sdfr#elif defined(_M_IX86)
32325537Sdfr    OS << format("0x%08lX", static_cast<DWORD>(PC));
32425537Sdfr#endif
32525537Sdfr
32625537Sdfr// Print the parameters.  Assume there are four.
32725537Sdfr#if defined(_M_X64)
32825537Sdfr    OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
32925537Sdfr            StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
33025537Sdfr            StackFrame.Params[3]);
33125537Sdfr#elif defined(_M_IX86)
33225537Sdfr    OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
33325537Sdfr            static_cast<DWORD>(StackFrame.Params[0]),
33425537Sdfr            static_cast<DWORD>(StackFrame.Params[1]),
33525537Sdfr            static_cast<DWORD>(StackFrame.Params[2]),
33640159Speter            static_cast<DWORD>(StackFrame.Params[3]));
33725537Sdfr#endif
33825537Sdfr    // Verify the PC belongs to a module in this process.
33925537Sdfr    if (!fSymGetModuleBase64(hProcess, PC)) {
34040159Speter      OS << " <unknown module>\n";
34125537Sdfr      continue;
34240159Speter    }
34340159Speter
34440159Speter    // Print the symbol name.
34540159Speter    char buffer[512];
34640159Speter    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
34740159Speter    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
34825537Sdfr    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
34925537Sdfr    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
35025537Sdfr
35125537Sdfr    DWORD64 dwDisp;
35225537Sdfr    if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
35325537Sdfr      OS << '\n';
35440395Speter      continue;
35525537Sdfr    }
35625537Sdfr
35725537Sdfr    buffer[511] = 0;
35843185Sdfr    if (dwDisp > 0)
35925537Sdfr      OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name,
36025537Sdfr                   dwDisp);
36125537Sdfr    else
36225537Sdfr      OS << format(", %s", (const char*)symbol->Name);
36325537Sdfr
36425537Sdfr    // Print the source file and line number information.
36525537Sdfr    IMAGEHLP_LINE64 line = {};
36625537Sdfr    DWORD dwLineDisp;
36725537Sdfr    line.SizeOfStruct = sizeof(line);
36825537Sdfr    if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
36925537Sdfr      OS << format(", %s, line %lu", line.FileName, line.LineNumber);
37025537Sdfr      if (dwLineDisp > 0)
37125537Sdfr        OS << format(" + 0x%lX byte(s)", dwLineDisp);
37225537Sdfr    }
37325537Sdfr
37425537Sdfr    OS << '\n';
37525537Sdfr  }
37625537Sdfr}
37725537Sdfr
37825537Sdfrnamespace llvm {
37925537Sdfr
38025537Sdfr//===----------------------------------------------------------------------===//
38125537Sdfr//=== WARNING: Implementation here must contain only Win32 specific code
38225537Sdfr//===          and must not be UNIX code
38325537Sdfr//===----------------------------------------------------------------------===//
38440159Speter
38525537Sdfr#ifdef _MSC_VER
38625537Sdfr/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry,
38725537Sdfr/// ignore" CRT debug report dialog.  "retry" raises an exception which
38825537Sdfr/// ultimately triggers our stack dumper.
38925537Sdfrstatic LLVM_ATTRIBUTE_UNUSED int
39025537SdfrAvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
39125537Sdfr  // Set *Return to the retry code for the return value of _CrtDbgReport:
39225537Sdfr  // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx
39325537Sdfr  // This may also trigger just-in-time debugging via DebugBreak().
39425537Sdfr  if (Return)
39525537Sdfr    *Return = 1;
39625537Sdfr  // Don't call _CrtDbgReport.
39743301Sdillon  return TRUE;
39825537Sdfr}
39925537Sdfr
40025537Sdfr#endif
40125537Sdfr
40225537Sdfrextern "C" void HandleAbort(int Sig) {
40325537Sdfr  if (Sig == SIGABRT) {
40425537Sdfr    LLVM_BUILTIN_TRAP;
40525537Sdfr  }
40625537Sdfr}
40725537Sdfr
40825537Sdfrstatic void InitializeThreading() {
40925537Sdfr  if (CriticalSectionInitialized)
41025537Sdfr    return;
41125537Sdfr
41225537Sdfr  // Now's the time to create the critical section. This is the first time
41325537Sdfr  // through here, and there's only one thread.
41443185Sdfr  InitializeCriticalSection(&CriticalSection);
41543185Sdfr  CriticalSectionInitialized = true;
41643185Sdfr}
41741055Speter
41825537Sdfrstatic void RegisterHandler() {
41925537Sdfr  // If we cannot load up the APIs (which would be unexpected as they should
42040159Speter  // exist on every version of Windows we support), we will bail out since
42125537Sdfr  // there would be nothing to report.
42225537Sdfr  if (!load64BitDebugHelp()) {
42325537Sdfr    assert(false && "These APIs should always be available");
42425537Sdfr    return;
42525537Sdfr  }
42625537Sdfr
42725537Sdfr  if (RegisteredUnhandledExceptionFilter) {
42825537Sdfr    EnterCriticalSection(&CriticalSection);
42925537Sdfr    return;
43025537Sdfr  }
43125537Sdfr
43225537Sdfr  InitializeThreading();
43325537Sdfr
43425537Sdfr  // Enter it immediately.  Now if someone hits CTRL/C, the console handler
43525537Sdfr  // can't proceed until the globals are updated.
43625537Sdfr  EnterCriticalSection(&CriticalSection);
43725537Sdfr
43825537Sdfr  RegisteredUnhandledExceptionFilter = true;
43925537Sdfr  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
44025537Sdfr  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
44125537Sdfr
44225537Sdfr  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
44325537Sdfr  // else multi-threading problems will ensue.
44425537Sdfr}
44525537Sdfr
44625537Sdfr// RemoveFileOnSignal - The public API
44740395Speterbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
44825537Sdfr  RegisterHandler();
44925537Sdfr
45025537Sdfr  if (CleanupExecuted) {
45125537Sdfr    if (ErrMsg)
45225537Sdfr      *ErrMsg = "Process terminating -- cannot register for removal";
45325537Sdfr    return true;
45425537Sdfr  }
45525537Sdfr
45625537Sdfr  if (FilesToRemove == NULL)
45725537Sdfr    FilesToRemove = new std::vector<std::string>;
45825537Sdfr
45925537Sdfr  FilesToRemove->push_back(Filename);
46025537Sdfr
46125537Sdfr  LeaveCriticalSection(&CriticalSection);
46225537Sdfr  return false;
46338275Sdfr}
46438275Sdfr
46542849Speter// DontRemoveFileOnSignal - The public API
46625537Sdfrvoid sys::DontRemoveFileOnSignal(StringRef Filename) {
46725537Sdfr  if (FilesToRemove == NULL)
46825537Sdfr    return;
46925537Sdfr
47040159Speter  RegisterHandler();
47125537Sdfr
47225537Sdfr  std::vector<std::string>::reverse_iterator I =
47338275Sdfr  std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
47438275Sdfr  if (I != FilesToRemove->rend())
47538275Sdfr    FilesToRemove->erase(I.base()-1);
47625537Sdfr
47725537Sdfr  LeaveCriticalSection(&CriticalSection);
47825537Sdfr}
47925537Sdfr
48038275Sdfrvoid sys::DisableSystemDialogsOnCrash() {
48140159Speter  // Crash to stack trace handler on abort.
48240159Speter  signal(SIGABRT, HandleAbort);
48338275Sdfr
48440159Speter  // The following functions are not reliably accessible on MinGW.
48538275Sdfr#ifdef _MSC_VER
48625537Sdfr  // We're already handling writing a "something went wrong" message.
48742849Speter  _set_abort_behavior(0, _WRITE_ABORT_MSG);
48825537Sdfr  // Disable Dr. Watson.
48925537Sdfr  _set_abort_behavior(0, _CALL_REPORTFAULT);
49040159Speter  _CrtSetReportHook(AvoidMessageBoxHook);
49140159Speter#endif
49225537Sdfr
49340159Speter  // Disable standard error dialog box.
49425537Sdfr  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
49525537Sdfr               SEM_NOOPENFILEERRORBOX);
49642849Speter  _set_error_mode(_OUT_TO_STDERR);
49742849Speter}
49842849Speter
49942849Speter/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
50042849Speter/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
50142849Spetervoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
50242849Speter                                       bool DisableCrashReporting) {
50342849Speter  ::Argv0 = Argv0;
50442849Speter
50542849Speter  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
50642849Speter    Process::PreventCoreFiles();
50742849Speter
50842849Speter  DisableSystemDialogsOnCrash();
50942849Speter  RegisterHandler();
51042849Speter  LeaveCriticalSection(&CriticalSection);
51142849Speter}
51242849Speter}
51342849Speter
51442849Speter#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
51525537Sdfr// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is
51625537Sdfr// missing it but mingw-w64 has it.
51725537Sdfrextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord);
51825537Sdfr#endif
51925537Sdfr
52025537Sdfrvoid llvm::sys::PrintStackTrace(raw_ostream &OS) {
52125537Sdfr  STACKFRAME64 StackFrame = {};
52225537Sdfr  CONTEXT Context = {};
52325537Sdfr  ::RtlCaptureContext(&Context);
52425537Sdfr#if defined(_M_X64)
52540159Speter  StackFrame.AddrPC.Offset = Context.Rip;
52640159Speter  StackFrame.AddrStack.Offset = Context.Rsp;
52725537Sdfr  StackFrame.AddrFrame.Offset = Context.Rbp;
52840159Speter#else
52925537Sdfr  StackFrame.AddrPC.Offset = Context.Eip;
53025537Sdfr  StackFrame.AddrStack.Offset = Context.Esp;
53125537Sdfr  StackFrame.AddrFrame.Offset = Context.Ebp;
53225537Sdfr#endif
53325537Sdfr  StackFrame.AddrPC.Mode = AddrModeFlat;
53425537Sdfr  StackFrame.AddrStack.Mode = AddrModeFlat;
53525537Sdfr  StackFrame.AddrFrame.Mode = AddrModeFlat;
53625537Sdfr  PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),
53725537Sdfr                           StackFrame, &Context);
53840159Speter}
53940159Speter
54025537Sdfr
54140159Spetervoid llvm::sys::SetInterruptFunction(void (*IF)()) {
54240395Speter  RegisterHandler();
54325537Sdfr  InterruptFunction = IF;
54425537Sdfr  LeaveCriticalSection(&CriticalSection);
54525537Sdfr}
54625537Sdfr
54725537Sdfr
54825537Sdfr/// AddSignalHandler - Add a function to be called when a signal is delivered
54925537Sdfr/// to the process.  The handler can have a cookie passed to it to identify
55040159Speter/// what instance of the handler it is.
55125537Sdfrvoid llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
55225537Sdfr  CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
55325537Sdfr  RegisterHandler();
55440159Speter  LeaveCriticalSection(&CriticalSection);
55525537Sdfr}
55625537Sdfr
55725537Sdfrstatic void Cleanup() {
55840159Speter  if (CleanupExecuted)
55925537Sdfr    return;
56040159Speter
56140159Speter  EnterCriticalSection(&CriticalSection);
56240159Speter
56340159Speter  // Prevent other thread from registering new files and directories for
56440159Speter  // removal, should we be executing because of the console handler callback.
56540159Speter  CleanupExecuted = true;
56640159Speter
56740159Speter  // FIXME: open files cannot be deleted.
56840159Speter  if (FilesToRemove != NULL)
56940159Speter    while (!FilesToRemove->empty()) {
57040159Speter      llvm::sys::fs::remove(FilesToRemove->back());
57140159Speter      FilesToRemove->pop_back();
57240159Speter    }
57340159Speter  llvm::sys::RunSignalHandlers();
57440159Speter  LeaveCriticalSection(&CriticalSection);
57540159Speter}
57640159Speter
57740159Spetervoid llvm::sys::RunInterruptHandlers() {
57840159Speter  // The interrupt handler may be called from an interrupt, but it may also be
57940159Speter  // called manually (such as the case of report_fatal_error with no registered
58040159Speter  // error handler). We must ensure that the critical section is properly
58140159Speter  // initialized.
58240159Speter  InitializeThreading();
58340159Speter  Cleanup();
58440159Speter}
58540159Speter
58640159Speter/// \brief Find the Windows Registry Key for a given location.
58740159Speter///
58840159Speter/// \returns a valid HKEY if the location exists, else NULL.
58940159Speterstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
59040159Speter  HKEY Key;
59140159Speter  if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
59240159Speter                                       RegistryLocation.str().c_str(), 0,
59340159Speter                                       KEY_QUERY_VALUE | KEY_READ, &Key))
59440159Speter    return NULL;
59540159Speter
59640159Speter  return Key;
59740159Speter}
59840159Speter
59940159Speter/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given
60040159Speter/// Windows Registry key.
60140159Speter///
60240159Speter/// \returns true if a valid value for DumpFolder exists, false otherwise.
60340159Speterstatic bool GetDumpFolder(HKEY Key,
60440159Speter                          llvm::SmallVectorImpl<char> &ResultDirectory) {
60540159Speter  using llvm::sys::windows::UTF16ToUTF8;
60640159Speter
60740159Speter  if (!Key)
60840159Speter    return false;
60940159Speter
61040159Speter  DWORD BufferLengthBytes = 0;
61140159Speter
61240159Speter  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
61340159Speter                                      NULL, NULL, &BufferLengthBytes))
61440159Speter    return false;
61540159Speter
61640159Speter  SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);
61740159Speter
61840159Speter  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
61940159Speter                                      NULL, Buffer.data(), &BufferLengthBytes))
62040159Speter    return false;
62140159Speter
62240159Speter  DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);
62340159Speter
62440159Speter  if (!ExpandBufferSize)
62540159Speter    return false;
62640159Speter
62725537Sdfr  SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);
62825537Sdfr
62925537Sdfr  if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),
63025537Sdfr                                                      ExpandBuffer.data(),
63130994Sphk                                                      ExpandBufferSize))
63225537Sdfr    return false;
63342316Smsmith
63425537Sdfr  if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))
63525537Sdfr    return false;
63625537Sdfr
63730994Sphk  return true;
63825537Sdfr}
63925537Sdfr
64025537Sdfr/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
64125537Sdfr/// "DumpType" for a given Windows Registry key.
64243301Sdillon///
64325537Sdfr/// According to
64425537Sdfr/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
64525537Sdfr/// valid values for DumpType are:
64643301Sdillon///   * 0: Custom dump
64725537Sdfr///   * 1: Mini dump
64825537Sdfr///   * 2: Full dump
64942316Smsmith/// If "Custom dump" is specified then the "CustomDumpFlags" field is read
65042316Smsmith/// containing a bitwise combination of MINIDUMP_TYPE values.
65142316Smsmith///
65242316Smsmith/// \returns true if a valid value for ResultType can be set, false otherwise.
65342316Smsmithstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
65442316Smsmith  if (!Key)
65542316Smsmith    return false;
65642316Smsmith
65742316Smsmith  DWORD DumpType;
65843301Sdillon  DWORD TypeSize = sizeof(DumpType);
65925537Sdfr  if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,
66025537Sdfr                                      NULL, &DumpType,
66125537Sdfr                                      &TypeSize))
66230994Sphk    return false;
66340159Speter
66425537Sdfr  switch (DumpType) {
66525537Sdfr  case 0: {
66625537Sdfr    DWORD Flags = 0;
66725537Sdfr    if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",
66825537Sdfr                                        RRF_RT_REG_DWORD, NULL, &Flags,
66925537Sdfr                                        &TypeSize))
67025537Sdfr      return false;
67130994Sphk
67225537Sdfr    ResultType = static_cast<MINIDUMP_TYPE>(Flags);
67325537Sdfr    break;
67425537Sdfr  }
67525537Sdfr  case 1:
67625537Sdfr    ResultType = MiniDumpNormal;
67725537Sdfr    break;
67825537Sdfr  case 2:
67943301Sdillon    ResultType = MiniDumpWithFullMemory;
68025537Sdfr    break;
68125537Sdfr  default:
68225537Sdfr    return false;
68325537Sdfr  }
68425537Sdfr  return true;
68525537Sdfr}
68643084Speter
68725537Sdfr/// \brief Write a Windows dump file containing process information that can be
68825537Sdfr/// used for post-mortem debugging.
68925537Sdfr///
69043084Speter/// \returns zero error code if a mini dump created, actual error code
69142837Speter/// otherwise.
69242837Speterstatic std::error_code WINAPI
69343084SpeterWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
69425537Sdfr  using namespace llvm;
69525537Sdfr  using namespace llvm::sys;
69625537Sdfr
69725537Sdfr  std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);
69825537Sdfr  StringRef ProgramName;
69925537Sdfr
70025537Sdfr  if (MainExecutableName.empty()) {
70125537Sdfr    // If we can't get the executable filename,
70230994Sphk    // things are in worse shape than we realize
70325537Sdfr    // and we should just bail out.
70442316Smsmith    return mapWindowsError(::GetLastError());
70525537Sdfr  }
70625537Sdfr
70725537Sdfr  ProgramName = path::filename(MainExecutableName.c_str());
70830994Sphk
70925537Sdfr  // The Windows Registry location as specified at
71025537Sdfr  // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
71143301Sdillon  // "Collecting User-Mode Dumps" that may optionally be set to collect crash
71225537Sdfr  // dumps in a specified location.
71325537Sdfr  StringRef LocalDumpsRegistryLocation =
71442316Smsmith      "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
71542316Smsmith
71642316Smsmith  // The key pointing to the Registry location that may contain global crash
71742316Smsmith  // dump settings.  This will be NULL if the location can not be found.
71842316Smsmith  ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));
71925537Sdfr
72030994Sphk  // The key pointing to the Registry location that may contain
72125537Sdfr  // application-specific crash dump settings.  This will be NULL if the
72225537Sdfr  // location can not be found.
72340159Speter  ScopedRegHandle AppSpecificKey(
72425537Sdfr      FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));
72525537Sdfr
72625537Sdfr  // Look to see if a dump type is specified in the registry; first with the
72725537Sdfr  // app-specific key and failing that with the global key.  If none are found
72825537Sdfr  // default to a normal dump (GetDumpType will return false either if the key
72925537Sdfr  // is NULL or if there is no valid DumpType value at its location).
73025537Sdfr  MINIDUMP_TYPE DumpType;
73130994Sphk  if (!GetDumpType(AppSpecificKey, DumpType))
73225537Sdfr    if (!GetDumpType(DefaultLocalDumpsKey, DumpType))
73325537Sdfr      DumpType = MiniDumpNormal;
73425537Sdfr
73525537Sdfr  // Look to see if a dump location is specified in the registry; first with the
73625537Sdfr  // app-specific key and failing that with the global key.  If none are found
73725537Sdfr  // we'll just create the dump file in the default temporary file location
73830994Sphk  // (GetDumpFolder will return false either if the key is NULL or if there is
73925537Sdfr  // no valid DumpFolder value at its location).
74030994Sphk  bool ExplicitDumpDirectorySet = true;
74125537Sdfr  SmallString<MAX_PATH> DumpDirectory;
74225537Sdfr  if (!GetDumpFolder(AppSpecificKey, DumpDirectory))
74340159Speter    if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))
74425537Sdfr      ExplicitDumpDirectorySet = false;
74525537Sdfr
74625537Sdfr  int FD;
74730994Sphk  SmallString<MAX_PATH> DumpPath;
74825537Sdfr
74930994Sphk  if (ExplicitDumpDirectorySet) {
75025537Sdfr    if (std::error_code EC = fs::create_directories(DumpDirectory))
75125537Sdfr      return EC;
75225537Sdfr    if (std::error_code EC = fs::createUniqueFile(
75325537Sdfr            Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,
75425537Sdfr            DumpPath))
75525537Sdfr      return EC;
75625537Sdfr  } else if (std::error_code EC =
75730994Sphk                 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))
75825537Sdfr    return EC;
75925537Sdfr
76025537Sdfr  // Our support functions return a file descriptor but Windows wants a handle.
76125537Sdfr  ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));
76225537Sdfr
76325537Sdfr  if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
76425537Sdfr                          FileHandle, DumpType, ExceptionInfo, NULL, NULL))
76525537Sdfr    return mapWindowsError(::GetLastError());
76625537Sdfr
76725537Sdfr  llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";
76825537Sdfr  return std::error_code();
76925537Sdfr}
77025537Sdfr
77125537Sdfrstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
77225537Sdfr  Cleanup();
77325537Sdfr
77425537Sdfr  // We'll automatically write a Minidump file here to help diagnose
77525537Sdfr  // the nasty sorts of crashes that aren't 100% reproducible from a set of
77643301Sdillon  // inputs (or in the event that the user is unable or unwilling to provide a
77725537Sdfr  // reproducible case).
77825537Sdfr  if (!llvm::Process::AreCoreFilesPrevented()) {
77925537Sdfr    MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
78025537Sdfr    ExceptionInfo.ThreadId = ::GetCurrentThreadId();
78125537Sdfr    ExceptionInfo.ExceptionPointers = ep;
78225537Sdfr    ExceptionInfo.ClientPointers = FALSE;
78325537Sdfr
78425537Sdfr    if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))
78525537Sdfr      llvm::errs() << "Could not write crash dump file: " << EC.message()
78643301Sdillon                   << "\n";
78725537Sdfr  }
78843301Sdillon
78925537Sdfr  // Initialize the STACKFRAME structure.
79043301Sdillon  STACKFRAME64 StackFrame = {};
79125537Sdfr
79243301Sdillon#if defined(_M_X64)
79325537Sdfr  StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
79443301Sdillon  StackFrame.AddrPC.Mode = AddrModeFlat;
79525537Sdfr  StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
79625537Sdfr  StackFrame.AddrStack.Mode = AddrModeFlat;
79730994Sphk  StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
79825537Sdfr  StackFrame.AddrFrame.Mode = AddrModeFlat;
79925537Sdfr#elif defined(_M_IX86)
80025537Sdfr  StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
80125537Sdfr  StackFrame.AddrPC.Mode = AddrModeFlat;
80225537Sdfr  StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
80325537Sdfr  StackFrame.AddrStack.Mode = AddrModeFlat;
80430994Sphk  StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
80525537Sdfr  StackFrame.AddrFrame.Mode = AddrModeFlat;
80625537Sdfr#endif
80725537Sdfr
80825537Sdfr  HANDLE hProcess = GetCurrentProcess();
80925537Sdfr  HANDLE hThread = GetCurrentThread();
81025537Sdfr  PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame,
81125537Sdfr                           ep->ContextRecord);
81230994Sphk
81325537Sdfr  _exit(ep->ExceptionRecord->ExceptionCode);
81430994Sphk}
81525537Sdfr
81625537Sdfrstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
81725537Sdfr  // We are running in our very own thread, courtesy of Windows.
81825537Sdfr  EnterCriticalSection(&CriticalSection);
81925537Sdfr  Cleanup();
82040159Speter
82141090Speter  // If an interrupt function has been set, go and run one it; otherwise,
82241090Speter  // the process dies.
82341090Speter  void (*IF)() = InterruptFunction;
82441090Speter  InterruptFunction = 0;      // Don't run it on another CTRL-C.
82541090Speter
82641090Speter  if (IF) {
82741090Speter    // Note: if the interrupt function throws an exception, there is nothing
82841090Speter    // to catch it in this thread so it will kill the process.
82941090Speter    IF();                     // Run it now.
83041090Speter    LeaveCriticalSection(&CriticalSection);
83143301Sdillon    return TRUE;              // Don't kill the process.
83241090Speter  }
83341090Speter
83441090Speter  // Allow normal processing to take place; i.e., the process dies.
83541090Speter  LeaveCriticalSection(&CriticalSection);
83641090Speter  return FALSE;
83741090Speter}
83841090Speter
83943301Sdillon#if __MINGW32__
84041090Speter // We turned these warnings off for this file so that MinGW-g++ doesn't
84141090Speter // complain about the ll format specifiers used.  Now we are turning the
84241090Speter // warnings back on.  If MinGW starts to support diagnostic stacks, we can
84341090Speter // replace this with a pop.
84441090Speter #pragma GCC diagnostic warning "-Wformat"
84541090Speter #pragma GCC diagnostic warning "-Wformat-extra-args"
84641090Speter#endif
84741090Speter