summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeny Kholodov <lkholodov@accesssoftek.com>2016-05-04 16:56:51 +0000
committerLeny Kholodov <lkholodov@accesssoftek.com>2016-05-04 16:56:51 +0000
commit1b73e66b5dcfac87eb344401a853b1f7808d9d8b (patch)
treebc18262e726f2c2425461cf839bb3d57252d2718
parentb034526853cf5902932273077f43752d9f2fa90c (diff)
downloadbcm5719-llvm-1b73e66b5dcfac87eb344401a853b1f7808d9d8b.tar.gz
bcm5719-llvm-1b73e66b5dcfac87eb344401a853b1f7808d9d8b.zip
[Support] Creation of minidump after compiler crash on Windows
In the current implementation compiler only prints stack trace to console after crash. This patch adds saving of minidump files which contain a useful subset of the information for further debugging. Differential Revision: http://reviews.llvm.org/D18216 llvm-svn: 268519
-rw-r--r--llvm/include/llvm/Support/Process.h3
-rw-r--r--llvm/lib/Support/Process.cpp7
-rw-r--r--llvm/lib/Support/Unix/Process.inc2
-rw-r--r--llvm/lib/Support/Windows/Process.inc2
-rw-r--r--llvm/lib/Support/Windows/Signals.inc217
-rw-r--r--llvm/lib/Support/Windows/WindowsSupport.h17
6 files changed, 247 insertions, 1 deletions
diff --git a/llvm/include/llvm/Support/Process.h b/llvm/include/llvm/Support/Process.h
index 3e96ee9f450..06fd0af10aa 100644
--- a/llvm/include/llvm/Support/Process.h
+++ b/llvm/include/llvm/Support/Process.h
@@ -69,6 +69,9 @@ public:
/// @brief Prevent core file generation.
static void PreventCoreFiles();
+ /// \brief true if PreventCoreFiles has been called, false otherwise.
+ static bool AreCoreFilesPrevented();
+
// This function returns the environment variable \arg name's value as a UTF-8
// string. \arg Name is assumed to be in UTF-8 encoding too.
static Optional<std::string> GetEnv(StringRef name);
diff --git a/llvm/lib/Support/Process.cpp b/llvm/lib/Support/Process.cpp
index 6dcbb47e87d..290c30f4968 100644
--- a/llvm/lib/Support/Process.cpp
+++ b/llvm/lib/Support/Process.cpp
@@ -73,6 +73,13 @@ static const char colorcodes[2][2][8][10] = {
{ ALLCOLORS("4",""), ALLCOLORS("4","1;") }
};
+// This is set to true when Process::PreventCoreFiles() is called.
+static bool coreFilesPrevented = false;
+
+bool Process::AreCoreFilesPrevented() {
+ return coreFilesPrevented;
+}
+
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Process.inc"
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index cad81f8074f..d81836b92da 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -169,6 +169,8 @@ void Process::PreventCoreFiles() {
signal(SIGSEGV, _exit);
signal(SIGBUS, _exit);
#endif
+
+ coreFilesPrevented = true;
}
Optional<std::string> Process::GetEnv(StringRef Name) {
diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc
index dae35a88132..3aef79fee84 100644
--- a/llvm/lib/Support/Windows/Process.inc
+++ b/llvm/lib/Support/Windows/Process.inc
@@ -123,6 +123,8 @@ void Process::PreventCoreFiles() {
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
+
+ coreFilesPrevented = true;
}
/// Returns the environment variable \arg Name's value as a string encoded in
diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc
index 552bbff5b0c..3a0e5569f93 100644
--- a/llvm/lib/Support/Windows/Signals.inc
+++ b/llvm/lib/Support/Windows/Signals.inc
@@ -11,7 +11,11 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/WindowsError.h"
#include <algorithm>
+#include <io.h>
#include <signal.h>
#include <stdio.h>
@@ -117,6 +121,12 @@ typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
HANDLE hThread, LPADDRESS64 lpaddr);
+typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
+ PMINIDUMP_EXCEPTION_INFORMATION,
+ PMINIDUMP_USER_STREAM_INFORMATION,
+ PMINIDUMP_CALLBACK_INFORMATION);
+static fpMiniDumpWriteDump fMiniDumpWriteDump;
+
typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
PFUNCTION_TABLE_ACCESS_ROUTINE64,
@@ -154,6 +164,8 @@ static fpEnumerateLoadedModules fEnumerateLoadedModules;
static bool load64BitDebugHelp(void) {
HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
if (hLib) {
+ fMiniDumpWriteDump = (fpMiniDumpWriteDump)
+ ::GetProcAddress(hLib, "MiniDumpWriteDump");
fStackWalk64 = (fpStackWalk64)
::GetProcAddress(hLib, "StackWalk64");
fSymGetModuleBase64 = (fpSymGetModuleBase64)
@@ -171,7 +183,7 @@ static bool load64BitDebugHelp(void) {
fEnumerateLoadedModules = (fpEnumerateLoadedModules)
::GetProcAddress(hLib, "EnumerateLoadedModules64");
}
- return fStackWalk64 && fSymInitialize && fSymSetOptions;
+ return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump;
}
using namespace llvm;
@@ -485,6 +497,9 @@ void sys::DisableSystemDialogsOnCrash() {
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
void sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) {
+ if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT"))
+ Process::PreventCoreFiles();
+
DisableSystemDialogsOnCrash();
RegisterHandler();
LeaveCriticalSection(&CriticalSection);
@@ -563,9 +578,209 @@ void llvm::sys::RunInterruptHandlers() {
Cleanup();
}
+/// \brief Find the Windows Registry Key for a given location.
+///
+/// \returns a valid HKEY if the location exists, else NULL.
+static HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
+ HKEY Key;
+ if (ERROR_SUCCESS != ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ RegistryLocation.str().c_str(), 0,
+ KEY_QUERY_VALUE | KEY_READ, &Key))
+ return NULL;
+
+ return Key;
+}
+
+/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given
+/// Windows Registry key.
+///
+/// \returns true if a valid value for DumpFolder exists, false otherwise.
+static bool GetDumpFolder(HKEY Key,
+ llvm::SmallVectorImpl<char> &ResultDirectory) {
+ using llvm::sys::windows::UTF16ToUTF8;
+
+ if (!Key)
+ return false;
+
+ DWORD BufferLengthBytes = 0;
+
+ if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
+ NULL, NULL, &BufferLengthBytes))
+ return false;
+
+ SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes);
+
+ if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ,
+ NULL, Buffer.data(), &BufferLengthBytes))
+ return false;
+
+ DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0);
+
+ if (!ExpandBufferSize)
+ return false;
+
+ SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize);
+
+ if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(),
+ ExpandBuffer.data(),
+ ExpandBufferSize))
+ return false;
+
+ if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory))
+ return false;
+
+ return true;
+}
+
+/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
+/// "DumpType" for a given Windows Registry key.
+///
+/// According to
+/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
+/// valid values for DumpType are:
+/// * 0: Custom dump
+/// * 1: Mini dump
+/// * 2: Full dump
+/// If "Custom dump" is specified then the "CustomDumpFlags" field is read
+/// containing a bitwise combination of MINIDUMP_TYPE values.
+///
+/// \returns true if a valid value for ResultType can be set, false otherwise.
+static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
+ if (!Key)
+ return false;
+
+ DWORD DumpType;
+ DWORD TypeSize = sizeof(DumpType);
+ if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD,
+ NULL, &DumpType,
+ &TypeSize))
+ return false;
+
+ switch (DumpType) {
+ case 0: {
+ DWORD Flags = 0;
+ if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags",
+ RRF_RT_REG_DWORD, NULL, &Flags,
+ &TypeSize))
+ return false;
+
+ ResultType = static_cast<MINIDUMP_TYPE>(Flags);
+ break;
+ }
+ case 1:
+ ResultType = MiniDumpNormal;
+ break;
+ case 2:
+ ResultType = MiniDumpWithFullMemory;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/// \brief Write a Windows dump file containing process information that can be
+/// used for post-mortem debugging.
+///
+/// \returns zero error code if a mini dump created, actual error code
+/// otherwise.
+static std::error_code WINAPI
+WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
+ using namespace llvm;
+ using namespace llvm::sys;
+
+ std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr);
+ StringRef ProgramName;
+
+ if (MainExecutableName.empty()) {
+ // If we can't get the executable filename,
+ // things are in worse shape than we realize
+ // and we should just bail out.
+ return mapWindowsError(::GetLastError());
+ }
+
+ ProgramName = path::filename(MainExecutableName.c_str());
+
+ // The Windows Registry location as specified at
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
+ // "Collecting User-Mode Dumps" that may optionally be set to collect crash
+ // dumps in a specified location.
+ StringRef LocalDumpsRegistryLocation =
+ "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
+
+ // The key pointing to the Registry location that may contain global crash
+ // dump settings. This will be NULL if the location can not be found.
+ ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation));
+
+ // The key pointing to the Registry location that may contain
+ // application-specific crash dump settings. This will be NULL if the
+ // location can not be found.
+ ScopedRegHandle AppSpecificKey(
+ FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName));
+
+ // Look to see if a dump type is specified in the registry; first with the
+ // app-specific key and failing that with the global key. If none are found
+ // default to a normal dump (GetDumpType will return false either if the key
+ // is NULL or if there is no valid DumpType value at its location).
+ MINIDUMP_TYPE DumpType;
+ if (!GetDumpType(AppSpecificKey, DumpType))
+ if (!GetDumpType(DefaultLocalDumpsKey, DumpType))
+ DumpType = MiniDumpNormal;
+
+ // Look to see if a dump location is specified in the registry; first with the
+ // app-specific key and failing that with the global key. If none are found
+ // we'll just create the dump file in the default temporary file location
+ // (GetDumpFolder will return false either if the key is NULL or if there is
+ // no valid DumpFolder value at its location).
+ bool ExplicitDumpDirectorySet = true;
+ SmallString<MAX_PATH> DumpDirectory;
+ if (!GetDumpFolder(AppSpecificKey, DumpDirectory))
+ if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory))
+ ExplicitDumpDirectorySet = false;
+
+ int FD;
+ SmallString<MAX_PATH> DumpPath;
+
+ if (ExplicitDumpDirectorySet) {
+ if (std::error_code EC = fs::create_directories(DumpDirectory))
+ return EC;
+ if (std::error_code EC = fs::createUniqueFile(
+ Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD,
+ DumpPath))
+ return EC;
+ } else if (std::error_code EC =
+ fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath))
+ return EC;
+
+ // Our support functions return a file descriptor but Windows wants a handle.
+ ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD)));
+
+ if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
+ FileHandle, DumpType, ExceptionInfo, NULL, NULL))
+ return mapWindowsError(::GetLastError());
+
+ llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n";
+ return std::error_code();
+}
+
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
Cleanup();
+ // We'll automatically write a Minidump file here to help diagnose
+ // the nasty sorts of crashes that aren't 100% reproducible from a set of
+ // inputs (or in the event that the user is unable or unwilling to provide a
+ // reproducible case).
+ if (!llvm::Process::AreCoreFilesPrevented()) {
+ MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
+ ExceptionInfo.ThreadId = ::GetCurrentThreadId();
+ ExceptionInfo.ExceptionPointers = ep;
+ ExceptionInfo.ClientPointers = FALSE;
+
+ if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo))
+ llvm::errs() << "Could not write crash dump file: " << EC.message()
+ << "\n";
+ }
+
// Initialize the STACKFRAME structure.
STACKFRAME64 StackFrame = {};
diff --git a/llvm/lib/Support/Windows/WindowsSupport.h b/llvm/lib/Support/Windows/WindowsSupport.h
index a28c79f40da..fa611a955af 100644
--- a/llvm/lib/Support/Windows/WindowsSupport.h
+++ b/llvm/lib/Support/Windows/WindowsSupport.h
@@ -167,6 +167,22 @@ struct CryptContextTraits : CommonHandleTraits {
}
};
+struct RegTraits : CommonHandleTraits {
+ typedef HKEY handle_type;
+
+ static handle_type GetInvalid() {
+ return NULL;
+ }
+
+ static void Close(handle_type h) {
+ ::RegCloseKey(h);
+ }
+
+ static bool IsValid(handle_type h) {
+ return h != GetInvalid();
+ }
+};
+
struct FindHandleTraits : CommonHandleTraits {
static void Close(handle_type h) {
::FindClose(h);
@@ -178,6 +194,7 @@ struct FileHandleTraits : CommonHandleTraits {};
typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
+typedef ScopedHandle<RegTraits> ScopedRegHandle;
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
OpenPOWER on IntegriCloud