Index: lib/Support/Windows/Signals.inc =================================================================== --- lib/Support/Windows/Signals.inc +++ lib/Support/Windows/Signals.inc @@ -151,6 +151,12 @@ typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); static fpEnumerateLoadedModules fEnumerateLoadedModules; +typedef BOOL (WINAPI * fpMiniDumpWriteDump)(HANDLE,DWORD,HANDLE,MINIDUMP_TYPE, + CONST PMINIDUMP_EXCEPTION_INFORMATION, + CONST PMINIDUMP_USER_STREAM_INFORMATION, + CONST PMINIDUMP_CALLBACK_INFORMATION); +static fpMiniDumpWriteDump fMiniDumpWriteDump; + static bool load64BitDebugHelp(void) { HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); if (hLib) { @@ -170,8 +176,10 @@ fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); fEnumerateLoadedModules = (fpEnumerateLoadedModules) ::GetProcAddress(hLib, "EnumerateLoadedModules64"); + fMiniDumpWriteDump = (fpMiniDumpWriteDump) + ::GetProcAddress(hLib, "MiniDumpWriteDump"); } - return fStackWalk64 && fSymInitialize && fSymSetOptions; + return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; } using namespace llvm; @@ -361,6 +369,93 @@ } } +static void WINAPI CreateMiniDump(llvm::raw_ostream &OS, + _EXCEPTION_POINTERS *pExceptionInfo) { + char buffer[_MAX_PATH]; + + DWORD length = + ::GetModuleFileName(::GetModuleHandle(0), buffer, sizeof(buffer)); + + // If GetModuleHandle fails, we would get the current process executable file + // name, which is fine. + + if (length >= sizeof(buffer)) + strcpy(buffer, "clang.exe"); + + char appName[_MAX_PATH]; + + _splitpath(buffer, NULL, NULL, appName, NULL); + + DWORD tempPathLength = ::GetTempPath(sizeof(buffer), buffer); + + // If GetTempPath fails, we would write minidump to the current directory. + + if (tempPathLength >= sizeof(buffer)) + tempPathLength = 0; + + size_t maxPrefixLength = sizeof(buffer) - tempPathLength; + + int prefixLength = + _snprintf(buffer + tempPathLength, maxPrefixLength, "%s", appName); + + // If _snprintf fails, we would use 'minidump' as the prefix + // and write file to the current directory. + + if (prefixLength <= 0 || prefixLength >= int(maxPrefixLength)) { + strcpy(buffer, "minidump"); + prefixLength = strlen(buffer); + } else { + prefixLength += tempPathLength; + } + + SYSTEMTIME systemTime; + + ::GetSystemTime(&systemTime); + + int maxSuffixLength = sizeof(buffer) - prefixLength; + + int suffixLength = _snprintf( + buffer + prefixLength, maxSuffixLength, + ".%04d%02d%02d%02d%02d%02d%03d.dmp", systemTime.wYear, systemTime.wMonth, + systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds); + + if (suffixLength <= 0 || suffixLength >= maxSuffixLength) { + _snprintf(buffer, sizeof(buffer), + "minidump.%04d%02d%02d%02d%02d%02d%03d.dmp", systemTime.wYear, + systemTime.wMonth, systemTime.wDay, systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds); + } + + HANDLE hFile = ::CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_WRITE, 0, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + + bool writeMiniDumpSucceeded = false; + int errorCode = GetLastError(); + + if (hFile != INVALID_HANDLE_VALUE) { + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = pExceptionInfo; + ExInfo.ClientPointers = NULL; + + writeMiniDumpSucceeded = fMiniDumpWriteDump( + ::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, + (MINIDUMP_TYPE)(MiniDumpNormal | MiniDumpWithDataSegs), &ExInfo, 0, 0); + + errorCode = GetLastError(); + + ::CloseHandle(hFile); + } + + if (writeMiniDumpSucceeded) + OS << "Minidump successfully saved: " << buffer << '\n'; + else + OS << "Cannot create minidump file: " << buffer << " (error code " + << errorCode << ")\n"; +} + namespace llvm { //===----------------------------------------------------------------------===// @@ -587,9 +682,13 @@ HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); - PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, + llvm::raw_ostream &OS = llvm::errs(); + + PrintStackTraceForThread(OS, hProcess, hThread, StackFrame, ep->ContextRecord); + CreateMiniDump(OS, ep); + _exit(ep->ExceptionRecord->ExceptionCode); }