11
11
//
12
12
// ===----------------------------------------------------------------------===//
13
13
#include " llvm/Support/FileSystem.h"
14
+ #include " llvm/Support/Path.h"
15
+ #include " llvm/Support/Process.h"
16
+ #include " llvm/Support/WindowsError.h"
14
17
#include < algorithm>
18
+ #include < io.h>
15
19
#include < signal.h>
16
20
#include < stdio.h>
17
21
@@ -117,6 +121,12 @@ typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,
117
121
typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
118
122
HANDLE hThread, LPADDRESS64 lpaddr);
119
123
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
+
120
130
typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
121
131
PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
122
132
PFUNCTION_TABLE_ACCESS_ROUTINE64,
@@ -154,6 +164,8 @@ static fpEnumerateLoadedModules fEnumerateLoadedModules;
154
164
static bool load64BitDebugHelp (void ) {
155
165
HMODULE hLib = ::LoadLibraryW (L" Dbghelp.dll" );
156
166
if (hLib) {
167
+ fMiniDumpWriteDump = (fpMiniDumpWriteDump)
168
+ ::GetProcAddress (hLib, " MiniDumpWriteDump" );
157
169
fStackWalk64 = (fpStackWalk64)
158
170
::GetProcAddress (hLib, " StackWalk64" );
159
171
fSymGetModuleBase64 = (fpSymGetModuleBase64)
@@ -171,7 +183,7 @@ static bool load64BitDebugHelp(void) {
171
183
fEnumerateLoadedModules = (fpEnumerateLoadedModules)
172
184
::GetProcAddress (hLib, " EnumerateLoadedModules64" );
173
185
}
174
- return fStackWalk64 && fSymInitialize && fSymSetOptions ;
186
+ return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump ;
175
187
}
176
188
177
189
using namespace llvm ;
@@ -485,6 +497,9 @@ void sys::DisableSystemDialogsOnCrash() {
485
497
// / PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
486
498
// / SIGSEGV) is delivered to the process, print a stack trace and then exit.
487
499
void sys::PrintStackTraceOnErrorSignal (bool DisableCrashReporting) {
500
+ if (DisableCrashReporting || getenv (" LLVM_DISABLE_CRASH_REPORT" ))
501
+ Process::PreventCoreFiles ();
502
+
488
503
DisableSystemDialogsOnCrash ();
489
504
RegisterHandler ();
490
505
LeaveCriticalSection (&CriticalSection);
@@ -563,9 +578,209 @@ void llvm::sys::RunInterruptHandlers() {
563
578
Cleanup ();
564
579
}
565
580
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
+
566
766
static LONG WINAPI LLVMUnhandledExceptionFilter (LPEXCEPTION_POINTERS ep) {
567
767
Cleanup ();
568
768
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
+
569
784
// Initialize the STACKFRAME structure.
570
785
STACKFRAME64 StackFrame = {};
571
786
0 commit comments