Signals.inc revision 321369
1218885Sdim//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the Win32 specific implementation of the Signals class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13261991Sdim#include "llvm/Support/FileSystem.h"
14309124Sdim#include "llvm/Support/Path.h"
15309124Sdim#include "llvm/Support/Process.h"
16309124Sdim#include "llvm/Support/WindowsError.h"
17249423Sdim#include <algorithm>
18309124Sdim#include <io.h>
19288943Sdim#include <signal.h>
20218885Sdim#include <stdio.h>
21218885Sdim
22288943Sdim#include "llvm/Support/Format.h"
23288943Sdim#include "llvm/Support/raw_ostream.h"
24288943Sdim
25276479Sdim// The Windows.h header must be after LLVM and standard headers.
26276479Sdim#include "WindowsSupport.h"
27276479Sdim
28218885Sdim#ifdef __MINGW32__
29218885Sdim #include <imagehlp.h>
30218885Sdim#else
31314564Sdim #include <crtdbg.h>
32218885Sdim #include <dbghelp.h>
33218885Sdim#endif
34218885Sdim#include <psapi.h>
35218885Sdim
36226633Sdim#ifdef _MSC_VER
37226633Sdim #pragma comment(lib, "psapi.lib")
38226633Sdim#elif __MINGW32__
39288943Sdim #if (HAVE_LIBPSAPI != 1)
40288943Sdim  #error "libpsapi.a should be present"
41218885Sdim #endif
42226633Sdim // The version of g++ that comes with MinGW does *not* properly understand
43226633Sdim // the ll format specifier for printf. However, MinGW passes the format
44226633Sdim // specifiers on to the MSVCRT entirely, and the CRT understands the ll
45226633Sdim // specifier. So these warnings are spurious in this case. Since we compile
46226633Sdim // with -Wall, this will generate these warnings which should be ignored. So
47226633Sdim // we will turn off the warnings for this just file. However, MinGW also does
48226633Sdim // not support push and pop for diagnostics, so we have to manually turn it
49226633Sdim // back on at the end of the file.
50226633Sdim #pragma GCC diagnostic ignored "-Wformat"
51226633Sdim #pragma GCC diagnostic ignored "-Wformat-extra-args"
52218885Sdim
53226633Sdim #if !defined(__MINGW64_VERSION_MAJOR)
54226633Sdim // MinGW.org does not have updated support for the 64-bit versions of the
55226633Sdim // DebugHlp APIs. So we will have to load them manually. The structures and
56226633Sdim // method signatures were pulled from DbgHelp.h in the Windows Platform SDK,
57226633Sdim // and adjusted for brevity.
58226633Sdim typedef struct _IMAGEHLP_LINE64 {
59226633Sdim   DWORD    SizeOfStruct;
60226633Sdim   PVOID    Key;
61226633Sdim   DWORD    LineNumber;
62226633Sdim   PCHAR    FileName;
63226633Sdim   DWORD64  Address;
64226633Sdim } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
65226633Sdim
66226633Sdim typedef struct _IMAGEHLP_SYMBOL64 {
67226633Sdim   DWORD   SizeOfStruct;
68226633Sdim   DWORD64 Address;
69226633Sdim   DWORD   Size;
70226633Sdim   DWORD   Flags;
71226633Sdim   DWORD   MaxNameLength;
72226633Sdim   CHAR    Name[1];
73226633Sdim } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
74226633Sdim
75226633Sdim typedef struct _tagADDRESS64 {
76226633Sdim   DWORD64       Offset;
77226633Sdim   WORD          Segment;
78226633Sdim   ADDRESS_MODE  Mode;
79226633Sdim } ADDRESS64, *LPADDRESS64;
80226633Sdim
81226633Sdim typedef struct _KDHELP64 {
82226633Sdim   DWORD64   Thread;
83226633Sdim   DWORD   ThCallbackStack;
84226633Sdim   DWORD   ThCallbackBStore;
85226633Sdim   DWORD   NextCallback;
86226633Sdim   DWORD   FramePointer;
87226633Sdim   DWORD64   KiCallUserMode;
88226633Sdim   DWORD64   KeUserCallbackDispatcher;
89226633Sdim   DWORD64   SystemRangeStart;
90226633Sdim   DWORD64   KiUserExceptionDispatcher;
91226633Sdim   DWORD64   StackBase;
92226633Sdim   DWORD64   StackLimit;
93226633Sdim   DWORD64   Reserved[5];
94226633Sdim } KDHELP64, *PKDHELP64;
95226633Sdim
96226633Sdim typedef struct _tagSTACKFRAME64 {
97226633Sdim   ADDRESS64   AddrPC;
98226633Sdim   ADDRESS64   AddrReturn;
99226633Sdim   ADDRESS64   AddrFrame;
100226633Sdim   ADDRESS64   AddrStack;
101226633Sdim   ADDRESS64   AddrBStore;
102226633Sdim   PVOID       FuncTableEntry;
103226633Sdim   DWORD64     Params[4];
104226633Sdim   BOOL        Far;
105226633Sdim   BOOL        Virtual;
106226633Sdim   DWORD64     Reserved[3];
107226633Sdim   KDHELP64    KdHelp;
108226633Sdim } STACKFRAME64, *LPSTACKFRAME64;
109288943Sdim #endif // !defined(__MINGW64_VERSION_MAJOR)
110288943Sdim#endif // __MINGW32__
111226633Sdim
112226633Sdimtypedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
113226633Sdim                      DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
114226633Sdim                      LPDWORD lpNumberOfBytesRead);
115226633Sdim
116226633Sdimtypedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess,
117226633Sdim                      DWORD64 AddrBase);
118226633Sdim
119226633Sdimtypedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
120226633Sdim                      DWORD64 Address);
121226633Sdim
122226633Sdimtypedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
123226633Sdim                      HANDLE hThread, LPADDRESS64 lpaddr);
124226633Sdim
125309124Sdimtypedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
126309124Sdim                                          PMINIDUMP_EXCEPTION_INFORMATION,
127309124Sdim                                          PMINIDUMP_USER_STREAM_INFORMATION,
128309124Sdim                                          PMINIDUMP_CALLBACK_INFORMATION);
129309124Sdimstatic fpMiniDumpWriteDump fMiniDumpWriteDump;
130309124Sdim
131226633Sdimtypedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
132226633Sdim                      PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
133226633Sdim                      PFUNCTION_TABLE_ACCESS_ROUTINE64,
134226633Sdim                      PGET_MODULE_BASE_ROUTINE64,
135226633Sdim                      PTRANSLATE_ADDRESS_ROUTINE64);
136288943Sdimstatic fpStackWalk64 fStackWalk64;
137226633Sdim
138226633Sdimtypedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
139288943Sdimstatic fpSymGetModuleBase64 fSymGetModuleBase64;
140226633Sdim
141226633Sdimtypedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
142226633Sdim                      PDWORD64, PIMAGEHLP_SYMBOL64);
143288943Sdimstatic fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
144226633Sdim
145226633Sdimtypedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
146226633Sdim                      PDWORD, PIMAGEHLP_LINE64);
147288943Sdimstatic fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
148226633Sdim
149296417Sdimtypedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,
150296417Sdim                                           PIMAGEHLP_MODULE64 ModuleInfo);
151296417Sdimstatic fpSymGetModuleInfo64 fSymGetModuleInfo64;
152296417Sdim
153226633Sdimtypedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
154288943Sdimstatic fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
155226633Sdim
156288943Sdimtypedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
157288943Sdimstatic fpSymSetOptions fSymSetOptions;
158288943Sdim
159288943Sdimtypedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
160288943Sdimstatic fpSymInitialize fSymInitialize;
161288943Sdim
162296417Sdimtypedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
163296417Sdimstatic fpEnumerateLoadedModules fEnumerateLoadedModules;
164296417Sdim
165226633Sdimstatic bool load64BitDebugHelp(void) {
166261991Sdim  HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
167226633Sdim  if (hLib) {
168309124Sdim    fMiniDumpWriteDump = (fpMiniDumpWriteDump)
169309124Sdim                      ::GetProcAddress(hLib, "MiniDumpWriteDump");
170288943Sdim    fStackWalk64 = (fpStackWalk64)
171226633Sdim                      ::GetProcAddress(hLib, "StackWalk64");
172288943Sdim    fSymGetModuleBase64 = (fpSymGetModuleBase64)
173226633Sdim                      ::GetProcAddress(hLib, "SymGetModuleBase64");
174288943Sdim    fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
175226633Sdim                      ::GetProcAddress(hLib, "SymGetSymFromAddr64");
176288943Sdim    fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
177226633Sdim                      ::GetProcAddress(hLib, "SymGetLineFromAddr64");
178296417Sdim    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)
179296417Sdim                      ::GetProcAddress(hLib, "SymGetModuleInfo64");
180288943Sdim    fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
181226633Sdim                     ::GetProcAddress(hLib, "SymFunctionTableAccess64");
182288943Sdim    fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
183288943Sdim    fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
184296417Sdim    fEnumerateLoadedModules = (fpEnumerateLoadedModules)
185296417Sdim      ::GetProcAddress(hLib, "EnumerateLoadedModules64");
186226633Sdim  }
187309124Sdim  return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
188226633Sdim}
189226633Sdim
190296417Sdimusing namespace llvm;
191296417Sdim
192218885Sdim// Forward declare.
193218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
194218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
195218885Sdim
196218885Sdim// InterruptFunction - The function to call if ctrl-c is pressed.
197218885Sdimstatic void (*InterruptFunction)() = 0;
198218885Sdim
199261991Sdimstatic std::vector<std::string> *FilesToRemove = NULL;
200218885Sdimstatic bool RegisteredUnhandledExceptionFilter = false;
201218885Sdimstatic bool CleanupExecuted = false;
202218885Sdimstatic PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
203218885Sdim
204218885Sdim// Windows creates a new thread to execute the console handler when an event
205218885Sdim// (such as CTRL/C) occurs.  This causes concurrency issues with the above
206218885Sdim// globals which this critical section addresses.
207218885Sdimstatic CRITICAL_SECTION CriticalSection;
208288943Sdimstatic bool CriticalSectionInitialized = false;
209218885Sdim
210309124Sdimstatic StringRef Argv0;
211309124Sdim
212296417Sdimenum {
213288943Sdim#if defined(_M_X64)
214296417Sdim  NativeMachineType = IMAGE_FILE_MACHINE_AMD64
215288943Sdim#else
216296417Sdim  NativeMachineType = IMAGE_FILE_MACHINE_I386
217288943Sdim#endif
218296417Sdim};
219288943Sdim
220296417Sdimstatic bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
221296417Sdim                                              HANDLE hProcess, HANDLE hThread,
222296417Sdim                                              STACKFRAME64 &StackFrameOrig,
223296417Sdim                                              CONTEXT *ContextOrig) {
224296417Sdim  // StackWalk64 modifies the incoming stack frame and context, so copy them.
225296417Sdim  STACKFRAME64 StackFrame = StackFrameOrig;
226296417Sdim
227296417Sdim  // Copy the register context so that we don't modify it while we unwind. We
228296417Sdim  // could use InitializeContext + CopyContext, but that's only required to get
229296417Sdim  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the
230296417Sdim  // flag set to indicate that there's less data.
231296417Sdim  CONTEXT Context = *ContextOrig;
232296417Sdim  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
233296417Sdim
234296417Sdim  static void *StackTrace[256];
235296417Sdim  size_t Depth = 0;
236296417Sdim  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
237296417Sdim                      &Context, 0, fSymFunctionTableAccess64,
238296417Sdim                      fSymGetModuleBase64, 0)) {
239296417Sdim    if (StackFrame.AddrFrame.Offset == 0)
240296417Sdim      break;
241296417Sdim    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;
242296417Sdim    if (Depth >= array_lengthof(StackTrace))
243296417Sdim      break;
244296417Sdim  }
245296417Sdim
246309124Sdim  return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS);
247296417Sdim}
248296417Sdim
249296417Sdimnamespace {
250296417Sdimstruct FindModuleData {
251296417Sdim  void **StackTrace;
252296417Sdim  int Depth;
253296417Sdim  const char **Modules;
254296417Sdim  intptr_t *Offsets;
255296417Sdim  StringSaver *StrPool;
256296417Sdim};
257296417Sdim}
258296417Sdim
259309124Sdimstatic BOOL CALLBACK findModuleCallback(PCSTR ModuleName,
260296417Sdim                                        DWORD64 ModuleBase, ULONG ModuleSize,
261296417Sdim                                        void *VoidData) {
262296417Sdim  FindModuleData *Data = (FindModuleData*)VoidData;
263296417Sdim  intptr_t Beg = ModuleBase;
264296417Sdim  intptr_t End = Beg + ModuleSize;
265296417Sdim  for (int I = 0; I < Data->Depth; I++) {
266296417Sdim    if (Data->Modules[I])
267296417Sdim      continue;
268296417Sdim    intptr_t Addr = (intptr_t)Data->StackTrace[I];
269296417Sdim    if (Beg <= Addr && Addr < End) {
270314564Sdim      Data->Modules[I] = Data->StrPool->save(ModuleName).data();
271296417Sdim      Data->Offsets[I] = Addr - Beg;
272296417Sdim    }
273296417Sdim  }
274296417Sdim  return TRUE;
275296417Sdim}
276296417Sdim
277296417Sdimstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
278296417Sdim                                  const char **Modules, intptr_t *Offsets,
279296417Sdim                                  const char *MainExecutableName,
280296417Sdim                                  StringSaver &StrPool) {
281296417Sdim  if (!fEnumerateLoadedModules)
282296417Sdim    return false;
283296417Sdim  FindModuleData Data;
284296417Sdim  Data.StackTrace = StackTrace;
285296417Sdim  Data.Depth = Depth;
286296417Sdim  Data.Modules = Modules;
287296417Sdim  Data.Offsets = Offsets;
288296417Sdim  Data.StrPool = &StrPool;
289296417Sdim  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);
290296417Sdim  return true;
291296417Sdim}
292296417Sdim
293296417Sdimstatic void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
294296417Sdim                                     HANDLE hThread, STACKFRAME64 &StackFrame,
295296417Sdim                                     CONTEXT *Context) {
296288943Sdim  // Initialize the symbol handler.
297288943Sdim  fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
298288943Sdim  fSymInitialize(hProcess, NULL, TRUE);
299288943Sdim
300296417Sdim  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs
301296417Sdim  // and DWARF, so it should do a good job regardless of what debug info or
302296417Sdim  // linker is in use.
303296417Sdim  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,
304296417Sdim                                        Context)) {
305296417Sdim    return;
306296417Sdim  }
307296417Sdim
308288943Sdim  while (true) {
309296417Sdim    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
310296417Sdim                      Context, 0, fSymFunctionTableAccess64,
311296417Sdim                      fSymGetModuleBase64, 0)) {
312288943Sdim      break;
313288943Sdim    }
314288943Sdim
315288943Sdim    if (StackFrame.AddrFrame.Offset == 0)
316288943Sdim      break;
317288943Sdim
318288943Sdim    using namespace llvm;
319288943Sdim    // Print the PC in hexadecimal.
320288943Sdim    DWORD64 PC = StackFrame.AddrPC.Offset;
321288943Sdim#if defined(_M_X64)
322288943Sdim    OS << format("0x%016llX", PC);
323288943Sdim#elif defined(_M_IX86)
324288943Sdim    OS << format("0x%08lX", static_cast<DWORD>(PC));
325288943Sdim#endif
326288943Sdim
327288943Sdim// Print the parameters.  Assume there are four.
328288943Sdim#if defined(_M_X64)
329288943Sdim    OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
330288943Sdim            StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
331288943Sdim            StackFrame.Params[3]);
332288943Sdim#elif defined(_M_IX86)
333288943Sdim    OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
334288943Sdim            static_cast<DWORD>(StackFrame.Params[0]),
335288943Sdim            static_cast<DWORD>(StackFrame.Params[1]),
336288943Sdim            static_cast<DWORD>(StackFrame.Params[2]),
337288943Sdim            static_cast<DWORD>(StackFrame.Params[3]));
338288943Sdim#endif
339288943Sdim    // Verify the PC belongs to a module in this process.
340288943Sdim    if (!fSymGetModuleBase64(hProcess, PC)) {
341288943Sdim      OS << " <unknown module>\n";
342288943Sdim      continue;
343288943Sdim    }
344288943Sdim
345288943Sdim    // Print the symbol name.
346288943Sdim    char buffer[512];
347288943Sdim    IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
348288943Sdim    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
349288943Sdim    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
350288943Sdim    symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
351288943Sdim
352288943Sdim    DWORD64 dwDisp;
353288943Sdim    if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
354288943Sdim      OS << '\n';
355288943Sdim      continue;
356288943Sdim    }
357288943Sdim
358288943Sdim    buffer[511] = 0;
359288943Sdim    if (dwDisp > 0)
360288943Sdim      OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name,
361288943Sdim                   dwDisp);
362288943Sdim    else
363288943Sdim      OS << format(", %s", (const char*)symbol->Name);
364288943Sdim
365288943Sdim    // Print the source file and line number information.
366288943Sdim    IMAGEHLP_LINE64 line = {};
367288943Sdim    DWORD dwLineDisp;
368288943Sdim    line.SizeOfStruct = sizeof(line);
369288943Sdim    if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
370288943Sdim      OS << format(", %s, line %lu", line.FileName, line.LineNumber);
371288943Sdim      if (dwLineDisp > 0)
372288943Sdim        OS << format(" + 0x%lX byte(s)", dwLineDisp);
373288943Sdim    }
374288943Sdim
375288943Sdim    OS << '\n';
376288943Sdim  }
377288943Sdim}
378288943Sdim
379218885Sdimnamespace llvm {
380218885Sdim
381218885Sdim//===----------------------------------------------------------------------===//
382218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
383218885Sdim//===          and must not be UNIX code
384218885Sdim//===----------------------------------------------------------------------===//
385218885Sdim
386218885Sdim#ifdef _MSC_VER
387251662Sdim/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry,
388251662Sdim/// ignore" CRT debug report dialog.  "retry" raises an exception which
389251662Sdim/// ultimately triggers our stack dumper.
390288943Sdimstatic LLVM_ATTRIBUTE_UNUSED int
391288943SdimAvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
392251662Sdim  // Set *Return to the retry code for the return value of _CrtDbgReport:
393251662Sdim  // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx
394251662Sdim  // This may also trigger just-in-time debugging via DebugBreak().
395251662Sdim  if (Return)
396251662Sdim    *Return = 1;
397251662Sdim  // Don't call _CrtDbgReport.
398251662Sdim  return TRUE;
399251662Sdim}
400251662Sdim
401218885Sdim#endif
402218885Sdim
403288943Sdimextern "C" void HandleAbort(int Sig) {
404288943Sdim  if (Sig == SIGABRT) {
405288943Sdim    LLVM_BUILTIN_TRAP;
406288943Sdim  }
407288943Sdim}
408288943Sdim
409288943Sdimstatic void InitializeThreading() {
410288943Sdim  if (CriticalSectionInitialized)
411288943Sdim    return;
412288943Sdim
413288943Sdim  // Now's the time to create the critical section. This is the first time
414288943Sdim  // through here, and there's only one thread.
415288943Sdim  InitializeCriticalSection(&CriticalSection);
416288943Sdim  CriticalSectionInitialized = true;
417288943Sdim}
418288943Sdim
419218885Sdimstatic void RegisterHandler() {
420288943Sdim  // If we cannot load up the APIs (which would be unexpected as they should
421288943Sdim  // exist on every version of Windows we support), we will bail out since
422288943Sdim  // there would be nothing to report.
423226633Sdim  if (!load64BitDebugHelp()) {
424226633Sdim    assert(false && "These APIs should always be available");
425226633Sdim    return;
426226633Sdim  }
427226633Sdim
428218885Sdim  if (RegisteredUnhandledExceptionFilter) {
429218885Sdim    EnterCriticalSection(&CriticalSection);
430218885Sdim    return;
431218885Sdim  }
432218885Sdim
433288943Sdim  InitializeThreading();
434218885Sdim
435218885Sdim  // Enter it immediately.  Now if someone hits CTRL/C, the console handler
436218885Sdim  // can't proceed until the globals are updated.
437218885Sdim  EnterCriticalSection(&CriticalSection);
438218885Sdim
439218885Sdim  RegisteredUnhandledExceptionFilter = true;
440218885Sdim  OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
441218885Sdim  SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
442218885Sdim
443218885Sdim  // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or
444218885Sdim  // else multi-threading problems will ensue.
445218885Sdim}
446218885Sdim
447218885Sdim// RemoveFileOnSignal - The public API
448261991Sdimbool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
449218885Sdim  RegisterHandler();
450218885Sdim
451218885Sdim  if (CleanupExecuted) {
452218885Sdim    if (ErrMsg)
453218885Sdim      *ErrMsg = "Process terminating -- cannot register for removal";
454218885Sdim    return true;
455218885Sdim  }
456218885Sdim
457218885Sdim  if (FilesToRemove == NULL)
458261991Sdim    FilesToRemove = new std::vector<std::string>;
459218885Sdim
460218885Sdim  FilesToRemove->push_back(Filename);
461218885Sdim
462218885Sdim  LeaveCriticalSection(&CriticalSection);
463218885Sdim  return false;
464218885Sdim}
465218885Sdim
466218885Sdim// DontRemoveFileOnSignal - The public API
467261991Sdimvoid sys::DontRemoveFileOnSignal(StringRef Filename) {
468218885Sdim  if (FilesToRemove == NULL)
469218885Sdim    return;
470218885Sdim
471218885Sdim  RegisterHandler();
472218885Sdim
473261991Sdim  std::vector<std::string>::reverse_iterator I =
474314564Sdim      find(reverse(*FilesToRemove), Filename);
475218885Sdim  if (I != FilesToRemove->rend())
476218885Sdim    FilesToRemove->erase(I.base()-1);
477218885Sdim
478218885Sdim  LeaveCriticalSection(&CriticalSection);
479218885Sdim}
480218885Sdim
481288943Sdimvoid sys::DisableSystemDialogsOnCrash() {
482288943Sdim  // Crash to stack trace handler on abort.
483288943Sdim  signal(SIGABRT, HandleAbort);
484288943Sdim
485288943Sdim  // The following functions are not reliably accessible on MinGW.
486288943Sdim#ifdef _MSC_VER
487288943Sdim  // We're already handling writing a "something went wrong" message.
488288943Sdim  _set_abort_behavior(0, _WRITE_ABORT_MSG);
489288943Sdim  // Disable Dr. Watson.
490288943Sdim  _set_abort_behavior(0, _CALL_REPORTFAULT);
491288943Sdim  _CrtSetReportHook(AvoidMessageBoxHook);
492288943Sdim#endif
493288943Sdim
494288943Sdim  // Disable standard error dialog box.
495288943Sdim  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
496288943Sdim               SEM_NOOPENFILEERRORBOX);
497288943Sdim  _set_error_mode(_OUT_TO_STDERR);
498288943Sdim}
499288943Sdim
500218885Sdim/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
501218885Sdim/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
502309124Sdimvoid sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
503309124Sdim                                       bool DisableCrashReporting) {
504309124Sdim  ::Argv0 = Argv0;
505309124Sdim
506309124Sdim  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
507309124Sdim    Process::PreventCoreFiles();
508309124Sdim
509288943Sdim  DisableSystemDialogsOnCrash();
510218885Sdim  RegisterHandler();
511218885Sdim  LeaveCriticalSection(&CriticalSection);
512218885Sdim}
513288943Sdim}
514218885Sdim
515288943Sdim#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
516288943Sdim// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is
517288943Sdim// missing it but mingw-w64 has it.
518288943Sdimextern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord);
519288943Sdim#endif
520288943Sdim
521288943Sdimvoid llvm::sys::PrintStackTrace(raw_ostream &OS) {
522288943Sdim  STACKFRAME64 StackFrame = {};
523288943Sdim  CONTEXT Context = {};
524288943Sdim  ::RtlCaptureContext(&Context);
525288943Sdim#if defined(_M_X64)
526288943Sdim  StackFrame.AddrPC.Offset = Context.Rip;
527288943Sdim  StackFrame.AddrStack.Offset = Context.Rsp;
528288943Sdim  StackFrame.AddrFrame.Offset = Context.Rbp;
529288943Sdim#else
530288943Sdim  StackFrame.AddrPC.Offset = Context.Eip;
531288943Sdim  StackFrame.AddrStack.Offset = Context.Esp;
532288943Sdim  StackFrame.AddrFrame.Offset = Context.Ebp;
533288943Sdim#endif
534288943Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
535288943Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
536288943Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
537288943Sdim  PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(),
538288943Sdim                           StackFrame, &Context);
539249423Sdim}
540218885Sdim
541249423Sdim
542288943Sdimvoid llvm::sys::SetInterruptFunction(void (*IF)()) {
543218885Sdim  RegisterHandler();
544218885Sdim  InterruptFunction = IF;
545218885Sdim  LeaveCriticalSection(&CriticalSection);
546218885Sdim}
547218885Sdim
548218885Sdim
549218885Sdim/// AddSignalHandler - Add a function to be called when a signal is delivered
550218885Sdim/// to the process.  The handler can have a cookie passed to it to identify
551218885Sdim/// what instance of the handler it is.
552288943Sdimvoid llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
553218885Sdim  CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
554218885Sdim  RegisterHandler();
555218885Sdim  LeaveCriticalSection(&CriticalSection);
556218885Sdim}
557218885Sdim
558218885Sdimstatic void Cleanup() {
559288943Sdim  if (CleanupExecuted)
560288943Sdim    return;
561288943Sdim
562218885Sdim  EnterCriticalSection(&CriticalSection);
563218885Sdim
564218885Sdim  // Prevent other thread from registering new files and directories for
565218885Sdim  // removal, should we be executing because of the console handler callback.
566218885Sdim  CleanupExecuted = true;
567218885Sdim
568218885Sdim  // FIXME: open files cannot be deleted.
569218885Sdim  if (FilesToRemove != NULL)
570218885Sdim    while (!FilesToRemove->empty()) {
571276479Sdim      llvm::sys::fs::remove(FilesToRemove->back());
572218885Sdim      FilesToRemove->pop_back();
573218885Sdim    }
574296417Sdim  llvm::sys::RunSignalHandlers();
575218885Sdim  LeaveCriticalSection(&CriticalSection);
576218885Sdim}
577218885Sdim
578218885Sdimvoid llvm::sys::RunInterruptHandlers() {
579288943Sdim  // The interrupt handler may be called from an interrupt, but it may also be
580288943Sdim  // called manually (such as the case of report_fatal_error with no registered
581288943Sdim  // error handler). We must ensure that the critical section is properly
582288943Sdim  // initialized.
583288943Sdim  InitializeThreading();
584218885Sdim  Cleanup();
585218885Sdim}
586218885Sdim
587309124Sdim/// \brief Find the Windows Registry Key for a given location.
588309124Sdim///
589309124Sdim/// \returns a valid HKEY if the location exists, else NULL.
590309124Sdimstatic HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
591309124Sdim  HKEY Key;
592309124Sdim  if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
593309124Sdim                                       RegistryLocation.str().c_str(), 0,
594309124Sdim                                       KEY_QUERY_VALUE | KEY_READ, &Key))
595309124Sdim    return NULL;
596309124Sdim
597309124Sdim  return Key;
598309124Sdim}
599309124Sdim
600309124Sdim/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given
601309124Sdim/// Windows Registry key.
602309124Sdim///
603309124Sdim/// \returns true if a valid value for DumpFolder exists, false otherwise.
604309124Sdimstatic bool GetDumpFolder(HKEY Key,
605309124Sdim                          llvm::SmallVectorImpl<char> &ResultDirectory) {
606309124Sdim  using llvm::sys::windows::UTF16ToUTF8;
607309124Sdim
608309124Sdim  if (!Key)
609309124Sdim    return false;
610309124Sdim
611309124Sdim  DWORD BufferLengthBytes = 0;
612309124Sdim
613309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
614309124Sdim                                      NULL, NULL, &BufferLengthBytes))
615309124Sdim    return false;
616309124Sdim
617309124Sdim  SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);
618309124Sdim
619309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
620309124Sdim                                      NULL, Buffer.data(), &BufferLengthBytes))
621309124Sdim    return false;
622309124Sdim
623309124Sdim  DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);
624309124Sdim
625309124Sdim  if (!ExpandBufferSize)
626309124Sdim    return false;
627309124Sdim
628309124Sdim  SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);
629309124Sdim
630309124Sdim  if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),
631309124Sdim                                                      ExpandBuffer.data(),
632309124Sdim                                                      ExpandBufferSize))
633309124Sdim    return false;
634309124Sdim
635309124Sdim  if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))
636309124Sdim    return false;
637309124Sdim
638309124Sdim  return true;
639309124Sdim}
640309124Sdim
641309124Sdim/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
642309124Sdim/// "DumpType" for a given Windows Registry key.
643309124Sdim///
644309124Sdim/// According to
645309124Sdim/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
646309124Sdim/// valid values for DumpType are:
647309124Sdim///   * 0: Custom dump
648309124Sdim///   * 1: Mini dump
649309124Sdim///   * 2: Full dump
650309124Sdim/// If "Custom dump" is specified then the "CustomDumpFlags" field is read
651309124Sdim/// containing a bitwise combination of MINIDUMP_TYPE values.
652309124Sdim///
653309124Sdim/// \returns true if a valid value for ResultType can be set, false otherwise.
654309124Sdimstatic bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
655309124Sdim  if (!Key)
656309124Sdim    return false;
657309124Sdim
658309124Sdim  DWORD DumpType;
659309124Sdim  DWORD TypeSize = sizeof(DumpType);
660309124Sdim  if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,
661309124Sdim                                      NULL, &DumpType,
662309124Sdim                                      &TypeSize))
663309124Sdim    return false;
664309124Sdim
665309124Sdim  switch (DumpType) {
666309124Sdim  case 0: {
667309124Sdim    DWORD Flags = 0;
668309124Sdim    if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",
669309124Sdim                                        RRF_RT_REG_DWORD, NULL, &Flags,
670309124Sdim                                        &TypeSize))
671309124Sdim      return false;
672309124Sdim
673309124Sdim    ResultType = static_cast<MINIDUMP_TYPE>(Flags);
674309124Sdim    break;
675309124Sdim  }
676309124Sdim  case 1:
677309124Sdim    ResultType = MiniDumpNormal;
678309124Sdim    break;
679309124Sdim  case 2:
680309124Sdim    ResultType = MiniDumpWithFullMemory;
681309124Sdim    break;
682309124Sdim  default:
683309124Sdim    return false;
684309124Sdim  }
685309124Sdim  return true;
686309124Sdim}
687309124Sdim
688309124Sdim/// \brief Write a Windows dump file containing process information that can be
689309124Sdim/// used for post-mortem debugging.
690309124Sdim///
691309124Sdim/// \returns zero error code if a mini dump created, actual error code
692309124Sdim/// otherwise.
693309124Sdimstatic std::error_code WINAPI
694309124SdimWriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
695309124Sdim  using namespace llvm;
696309124Sdim  using namespace llvm::sys;
697309124Sdim
698309124Sdim  std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);
699309124Sdim  StringRef ProgramName;
700309124Sdim
701309124Sdim  if (MainExecutableName.empty()) {
702309124Sdim    // If we can't get the executable filename,
703309124Sdim    // things are in worse shape than we realize
704309124Sdim    // and we should just bail out.
705309124Sdim    return mapWindowsError(::GetLastError());
706309124Sdim  }
707309124Sdim
708309124Sdim  ProgramName = path::filename(MainExecutableName.c_str());
709309124Sdim
710309124Sdim  // The Windows Registry location as specified at
711309124Sdim  // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
712309124Sdim  // "Collecting User-Mode Dumps" that may optionally be set to collect crash
713309124Sdim  // dumps in a specified location.
714309124Sdim  StringRef LocalDumpsRegistryLocation =
715309124Sdim      "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
716309124Sdim
717309124Sdim  // The key pointing to the Registry location that may contain global crash
718309124Sdim  // dump settings.  This will be NULL if the location can not be found.
719309124Sdim  ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));
720309124Sdim
721309124Sdim  // The key pointing to the Registry location that may contain
722309124Sdim  // application-specific crash dump settings.  This will be NULL if the
723309124Sdim  // location can not be found.
724309124Sdim  ScopedRegHandle AppSpecificKey(
725309124Sdim      FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));
726309124Sdim
727309124Sdim  // Look to see if a dump type is specified in the registry; first with the
728309124Sdim  // app-specific key and failing that with the global key.  If none are found
729309124Sdim  // default to a normal dump (GetDumpType will return false either if the key
730309124Sdim  // is NULL or if there is no valid DumpType value at its location).
731309124Sdim  MINIDUMP_TYPE DumpType;
732309124Sdim  if (!GetDumpType(AppSpecificKey, DumpType))
733309124Sdim    if (!GetDumpType(DefaultLocalDumpsKey, DumpType))
734309124Sdim      DumpType = MiniDumpNormal;
735309124Sdim
736309124Sdim  // Look to see if a dump location is specified in the registry; first with the
737309124Sdim  // app-specific key and failing that with the global key.  If none are found
738309124Sdim  // we'll just create the dump file in the default temporary file location
739309124Sdim  // (GetDumpFolder will return false either if the key is NULL or if there is
740309124Sdim  // no valid DumpFolder value at its location).
741309124Sdim  bool ExplicitDumpDirectorySet = true;
742309124Sdim  SmallString<MAX_PATH> DumpDirectory;
743309124Sdim  if (!GetDumpFolder(AppSpecificKey, DumpDirectory))
744309124Sdim    if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))
745309124Sdim      ExplicitDumpDirectorySet = false;
746309124Sdim
747309124Sdim  int FD;
748309124Sdim  SmallString<MAX_PATH> DumpPath;
749309124Sdim
750309124Sdim  if (ExplicitDumpDirectorySet) {
751309124Sdim    if (std::error_code EC = fs::create_directories(DumpDirectory))
752309124Sdim      return EC;
753309124Sdim    if (std::error_code EC = fs::createUniqueFile(
754309124Sdim            Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,
755309124Sdim            DumpPath))
756309124Sdim      return EC;
757309124Sdim  } else if (std::error_code EC =
758309124Sdim                 fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))
759309124Sdim    return EC;
760309124Sdim
761309124Sdim  // Our support functions return a file descriptor but Windows wants a handle.
762309124Sdim  ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));
763309124Sdim
764309124Sdim  if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
765309124Sdim                          FileHandle, DumpType, ExceptionInfo, NULL, NULL))
766309124Sdim    return mapWindowsError(::GetLastError());
767309124Sdim
768309124Sdim  llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";
769309124Sdim  return std::error_code();
770309124Sdim}
771309124Sdim
772218885Sdimstatic LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
773218885Sdim  Cleanup();
774218885Sdim
775309124Sdim  // We'll automatically write a Minidump file here to help diagnose
776309124Sdim  // the nasty sorts of crashes that aren't 100% reproducible from a set of
777309124Sdim  // inputs (or in the event that the user is unable or unwilling to provide a
778309124Sdim  // reproducible case).
779321369Sdim  if (!llvm::sys::Process::AreCoreFilesPrevented()) {
780309124Sdim    MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
781309124Sdim    ExceptionInfo.ThreadId = ::GetCurrentThreadId();
782309124Sdim    ExceptionInfo.ExceptionPointers = ep;
783309124Sdim    ExceptionInfo.ClientPointers = FALSE;
784309124Sdim
785309124Sdim    if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))
786309124Sdim      llvm::errs() << "Could not write crash dump file: " << EC.message()
787309124Sdim                   << "\n";
788309124Sdim  }
789309124Sdim
790218885Sdim  // Initialize the STACKFRAME structure.
791288943Sdim  STACKFRAME64 StackFrame = {};
792218885Sdim
793226633Sdim#if defined(_M_X64)
794226633Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
795226633Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
796226633Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
797226633Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
798226633Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
799226633Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
800226633Sdim#elif defined(_M_IX86)
801218885Sdim  StackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
802218885Sdim  StackFrame.AddrPC.Mode = AddrModeFlat;
803218885Sdim  StackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
804218885Sdim  StackFrame.AddrStack.Mode = AddrModeFlat;
805218885Sdim  StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
806218885Sdim  StackFrame.AddrFrame.Mode = AddrModeFlat;
807226633Sdim#endif
808218885Sdim
809218885Sdim  HANDLE hProcess = GetCurrentProcess();
810218885Sdim  HANDLE hThread = GetCurrentThread();
811288943Sdim  PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame,
812288943Sdim                           ep->ContextRecord);
813218885Sdim
814288943Sdim  _exit(ep->ExceptionRecord->ExceptionCode);
815218885Sdim}
816218885Sdim
817218885Sdimstatic BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
818218885Sdim  // We are running in our very own thread, courtesy of Windows.
819218885Sdim  EnterCriticalSection(&CriticalSection);
820218885Sdim  Cleanup();
821218885Sdim
822218885Sdim  // If an interrupt function has been set, go and run one it; otherwise,
823218885Sdim  // the process dies.
824218885Sdim  void (*IF)() = InterruptFunction;
825218885Sdim  InterruptFunction = 0;      // Don't run it on another CTRL-C.
826218885Sdim
827218885Sdim  if (IF) {
828218885Sdim    // Note: if the interrupt function throws an exception, there is nothing
829218885Sdim    // to catch it in this thread so it will kill the process.
830218885Sdim    IF();                     // Run it now.
831218885Sdim    LeaveCriticalSection(&CriticalSection);
832218885Sdim    return TRUE;              // Don't kill the process.
833218885Sdim  }
834218885Sdim
835218885Sdim  // Allow normal processing to take place; i.e., the process dies.
836218885Sdim  LeaveCriticalSection(&CriticalSection);
837218885Sdim  return FALSE;
838218885Sdim}
839226633Sdim
840226633Sdim#if __MINGW32__
841226633Sdim // We turned these warnings off for this file so that MinGW-g++ doesn't
842226633Sdim // complain about the ll format specifiers used.  Now we are turning the
843226633Sdim // warnings back on.  If MinGW starts to support diagnostic stacks, we can
844226633Sdim // replace this with a pop.
845226633Sdim #pragma GCC diagnostic warning "-Wformat"
846226633Sdim #pragma GCC diagnostic warning "-Wformat-extra-args"
847226633Sdim#endif
848