1111//
1212// ===----------------------------------------------------------------------===//
1313#include " llvm/Support/FileSystem.h"
14+ #include " llvm/Support/Path.h"
15+ #include " llvm/Support/Process.h"
16+ #include " llvm/Support/WindowsError.h"
1417#include < algorithm>
18+ #include < io.h>
1519#include < signal.h>
1620#include < stdio.h>
1721
@@ -117,6 +121,12 @@ typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
117121typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
118122 HANDLE hThread, LPADDRESS64 lpaddr);
119123
124+ typedef BOOL (WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
125+ PMINIDUMP_EXCEPTION_INFORMATION,
126+ PMINIDUMP_USER_STREAM_INFORMATION,
127+ PMINIDUMP_CALLBACK_INFORMATION);
128+ static fpMiniDumpWriteDump fMiniDumpWriteDump ;
129+
120130typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
121131 PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
122132 PFUNCTION_TABLE_ACCESS_ROUTINE64,
@@ -154,6 +164,8 @@ static fpEnumerateLoadedModules fEnumerateLoadedModules;
154164static bool load64BitDebugHelp (void ) {
155165 HMODULE hLib = ::LoadLibraryW (L" Dbghelp.dll" );
156166 if (hLib) {
167+ fMiniDumpWriteDump = (fpMiniDumpWriteDump)
168+ ::GetProcAddress (hLib, " MiniDumpWriteDump" );
157169 fStackWalk64 = (fpStackWalk64)
158170 ::GetProcAddress (hLib, " StackWalk64" );
159171 fSymGetModuleBase64 = (fpSymGetModuleBase64)
@@ -171,7 +183,7 @@ static bool load64BitDebugHelp(void) {
171183 fEnumerateLoadedModules = (fpEnumerateLoadedModules)
172184 ::GetProcAddress (hLib, " EnumerateLoadedModules64" );
173185 }
174- return fStackWalk64 && fSymInitialize && fSymSetOptions ;
186+ return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump ;
175187}
176188
177189using namespace llvm ;
@@ -485,6 +497,9 @@ void sys::DisableSystemDialogsOnCrash() {
485497// / PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
486498// / SIGSEGV) is delivered to the process, print a stack trace and then exit.
487499void sys::PrintStackTraceOnErrorSignal (bool DisableCrashReporting) {
500+ if (DisableCrashReporting || getenv (" LLVM_DISABLE_CRASH_REPORT" ))
501+ Process::PreventCoreFiles ();
502+
488503 DisableSystemDialogsOnCrash ();
489504 RegisterHandler ();
490505 LeaveCriticalSection (&CriticalSection);
@@ -563,9 +578,209 @@ void llvm::sys::RunInterruptHandlers() {
563578 Cleanup ();
564579}
565580
581+ // / \brief Find the Windows Registry Key for a given location.
582+ // /
583+ // / \returns a valid HKEY if the location exists, else NULL.
584+ static HKEY FindWERKey (const llvm::Twine &RegistryLocation) {
585+ HKEY Key;
586+ if (ERROR_SUCCESS != ::RegOpenKeyEx (HKEY_LOCAL_MACHINE,
587+ RegistryLocation.str ().c_str (), 0 ,
588+ KEY_QUERY_VALUE | KEY_READ, &Key))
589+ return NULL ;
590+
591+ return Key;
592+ }
593+
594+ // / \brief Populate ResultDirectory with the value for "DumpFolder" for a given
595+ // / Windows Registry key.
596+ // /
597+ // / \returns true if a valid value for DumpFolder exists, false otherwise.
598+ static bool GetDumpFolder (HKEY Key,
599+ llvm::SmallVectorImpl<char > &ResultDirectory) {
600+ using llvm::sys::windows::UTF16ToUTF8;
601+
602+ if (!Key)
603+ return false ;
604+
605+ DWORD BufferLengthBytes = 0 ;
606+
607+ if (ERROR_SUCCESS != ::RegGetValueW (Key, 0 , L" DumpFolder" , REG_EXPAND_SZ,
608+ NULL , NULL , &BufferLengthBytes))
609+ return false ;
610+
611+ SmallVector<wchar_t , MAX_PATH> Buffer (BufferLengthBytes);
612+
613+ if (ERROR_SUCCESS != ::RegGetValueW (Key, 0 , L" DumpFolder" , REG_EXPAND_SZ,
614+ NULL , Buffer.data (), &BufferLengthBytes))
615+ return false ;
616+
617+ DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW (Buffer.data (), NULL , 0 );
618+
619+ if (!ExpandBufferSize)
620+ return false ;
621+
622+ SmallVector<wchar_t , MAX_PATH> ExpandBuffer (ExpandBufferSize);
623+
624+ if (ExpandBufferSize != ::ExpandEnvironmentStringsW (Buffer.data (),
625+ ExpandBuffer.data (),
626+ ExpandBufferSize))
627+ return false ;
628+
629+ if (UTF16ToUTF8 (ExpandBuffer.data (), ExpandBufferSize - 1 , ResultDirectory))
630+ return false ;
631+
632+ return true ;
633+ }
634+
635+ // / \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
636+ // / "DumpType" for a given Windows Registry key.
637+ // /
638+ // / According to
639+ // / https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx
640+ // / valid values for DumpType are:
641+ // / * 0: Custom dump
642+ // / * 1: Mini dump
643+ // / * 2: Full dump
644+ // / If "Custom dump" is specified then the "CustomDumpFlags" field is read
645+ // / containing a bitwise combination of MINIDUMP_TYPE values.
646+ // /
647+ // / \returns true if a valid value for ResultType can be set, false otherwise.
648+ static bool GetDumpType (HKEY Key, MINIDUMP_TYPE &ResultType) {
649+ if (!Key)
650+ return false ;
651+
652+ DWORD DumpType;
653+ DWORD TypeSize = sizeof (DumpType);
654+ if (ERROR_SUCCESS != ::RegGetValueW (Key, NULL , L" DumpType" , RRF_RT_REG_DWORD,
655+ NULL , &DumpType,
656+ &TypeSize))
657+ return false ;
658+
659+ switch (DumpType) {
660+ case 0 : {
661+ DWORD Flags = 0 ;
662+ if (ERROR_SUCCESS != ::RegGetValueW (Key, NULL , L" CustomDumpFlags" ,
663+ RRF_RT_REG_DWORD, NULL , &Flags,
664+ &TypeSize))
665+ return false ;
666+
667+ ResultType = static_cast <MINIDUMP_TYPE>(Flags);
668+ break ;
669+ }
670+ case 1 :
671+ ResultType = MiniDumpNormal;
672+ break ;
673+ case 2 :
674+ ResultType = MiniDumpWithFullMemory;
675+ break ;
676+ default :
677+ return false ;
678+ }
679+ return true ;
680+ }
681+
682+ // / \brief Write a Windows dump file containing process information that can be
683+ // / used for post-mortem debugging.
684+ // /
685+ // / \returns zero error code if a mini dump created, actual error code
686+ // / otherwise.
687+ static std::error_code WINAPI
688+ WriteWindowsDumpFile (PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) {
689+ using namespace llvm ;
690+ using namespace llvm ::sys;
691+
692+ std::string MainExecutableName = fs::getMainExecutable (nullptr , nullptr );
693+ StringRef ProgramName;
694+
695+ if (MainExecutableName.empty ()) {
696+ // If we can't get the executable filename,
697+ // things are in worse shape than we realize
698+ // and we should just bail out.
699+ return mapWindowsError (::GetLastError ());
700+ }
701+
702+ ProgramName = path::filename (MainExecutableName.c_str ());
703+
704+ // The Windows Registry location as specified at
705+ // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx
706+ // "Collecting User-Mode Dumps" that may optionally be set to collect crash
707+ // dumps in a specified location.
708+ StringRef LocalDumpsRegistryLocation =
709+ " SOFTWARE\\ Microsoft\\ Windows\\ Windows Error Reporting\\ LocalDumps" ;
710+
711+ // The key pointing to the Registry location that may contain global crash
712+ // dump settings. This will be NULL if the location can not be found.
713+ ScopedRegHandle DefaultLocalDumpsKey (FindWERKey (LocalDumpsRegistryLocation));
714+
715+ // The key pointing to the Registry location that may contain
716+ // application-specific crash dump settings. This will be NULL if the
717+ // location can not be found.
718+ ScopedRegHandle AppSpecificKey (
719+ FindWERKey (Twine (LocalDumpsRegistryLocation) + " \\ " + ProgramName));
720+
721+ // Look to see if a dump type is specified in the registry; first with the
722+ // app-specific key and failing that with the global key. If none are found
723+ // default to a normal dump (GetDumpType will return false either if the key
724+ // is NULL or if there is no valid DumpType value at its location).
725+ MINIDUMP_TYPE DumpType;
726+ if (!GetDumpType (AppSpecificKey, DumpType))
727+ if (!GetDumpType (DefaultLocalDumpsKey, DumpType))
728+ DumpType = MiniDumpNormal;
729+
730+ // Look to see if a dump location is specified in the registry; first with the
731+ // app-specific key and failing that with the global key. If none are found
732+ // we'll just create the dump file in the default temporary file location
733+ // (GetDumpFolder will return false either if the key is NULL or if there is
734+ // no valid DumpFolder value at its location).
735+ bool ExplicitDumpDirectorySet = true ;
736+ SmallString<MAX_PATH> DumpDirectory;
737+ if (!GetDumpFolder (AppSpecificKey, DumpDirectory))
738+ if (!GetDumpFolder (DefaultLocalDumpsKey, DumpDirectory))
739+ ExplicitDumpDirectorySet = false ;
740+
741+ int FD;
742+ SmallString<MAX_PATH> DumpPath;
743+
744+ if (ExplicitDumpDirectorySet) {
745+ if (std::error_code EC = fs::create_directories (DumpDirectory))
746+ return EC;
747+ if (std::error_code EC = fs::createUniqueFile (
748+ Twine (DumpDirectory) + " \\ " + ProgramName + " .%%%%%%.dmp" , FD,
749+ DumpPath))
750+ return EC;
751+ } else if (std::error_code EC =
752+ fs::createTemporaryFile (ProgramName, " dmp" , FD, DumpPath))
753+ return EC;
754+
755+ // Our support functions return a file descriptor but Windows wants a handle.
756+ ScopedCommonHandle FileHandle (reinterpret_cast <HANDLE>(_get_osfhandle (FD)));
757+
758+ if (!fMiniDumpWriteDump (::GetCurrentProcess (), ::GetCurrentProcessId (),
759+ FileHandle, DumpType, ExceptionInfo, NULL , NULL ))
760+ return mapWindowsError (::GetLastError ());
761+
762+ llvm::errs () << " Wrote crash dump file \" " << DumpPath << " \"\n " ;
763+ return std::error_code ();
764+ }
765+
566766static LONG WINAPI LLVMUnhandledExceptionFilter (LPEXCEPTION_POINTERS ep) {
567767 Cleanup ();
568768
769+ // We'll automatically write a Minidump file here to help diagnose
770+ // the nasty sorts of crashes that aren't 100% reproducible from a set of
771+ // inputs (or in the event that the user is unable or unwilling to provide a
772+ // reproducible case).
773+ if (!llvm::Process::AreCoreFilesPrevented ()) {
774+ MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
775+ ExceptionInfo.ThreadId = ::GetCurrentThreadId ();
776+ ExceptionInfo.ExceptionPointers = ep;
777+ ExceptionInfo.ClientPointers = FALSE ;
778+
779+ if (std::error_code EC = WriteWindowsDumpFile (&ExceptionInfo))
780+ llvm::errs () << " Could not write crash dump file: " << EC.message ()
781+ << " \n " ;
782+ }
783+
569784 // Initialize the STACKFRAME structure.
570785 STACKFRAME64 StackFrame = {};
571786
0 commit comments