From f1eafa8d8120921ef42f6ee57de0918473587078 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 28 May 2020 07:25:25 -0700 Subject: [PATCH] Added ability to catch llvm errs(), shared crashcatcher object --- BeefySysLib/platform/win/CrashCatcher.cpp | 151 ++++++++++++----- BeefySysLib/platform/win/CrashCatcher.h | 16 +- BeefySysLib/platform/win/Platform.cpp | 23 +-- IDEHelper/Compiler/BfIRCodeGen.cpp | 197 ++++++++++++++++------ 4 files changed, 274 insertions(+), 113 deletions(-) diff --git a/BeefySysLib/platform/win/CrashCatcher.cpp b/BeefySysLib/platform/win/CrashCatcher.cpp index 62e9a6f7..6d41c067 100644 --- a/BeefySysLib/platform/win/CrashCatcher.cpp +++ b/BeefySysLib/platform/win/CrashCatcher.cpp @@ -1,5 +1,4 @@ #include "CrashCatcher.h" -#include "../util/CritSect.h" #include "../util/Dictionary.h" #include #include @@ -51,15 +50,7 @@ static SYMFUNCTIONTABLEACCESSPROC gSymFunctionTableAccess = NULL; static SYMGETMODULEBASEPROC gSymGetModuleBase = NULL; static SYMGETSYMFROMADDRPROC gSymGetSymFromAddr = NULL; static SYMGETLINEFROMADDR gSymGetLineFromAddr = NULL; -static Array gCrashInfoFuncs; -static StringT<0> gCrashInfo; -static bool gCrashed = false; -extern CritSect gBfpCritSect; -static EXCEPTION_POINTERS* gExceptionPointers = NULL; -static LPTOP_LEVEL_EXCEPTION_FILTER gPreviousFilter = NULL; - -static bool gDebugError = false; static bool CreateMiniDump(EXCEPTION_POINTERS* pep, const StringImpl& filePath); @@ -162,7 +153,6 @@ struct { 0xFFFFFFFF, "" } }; -static bool gUseDefaultFonts; static HFONT gDialogFont; static HFONT gBoldFont; static String gErrorTitle; @@ -171,10 +161,9 @@ static HWND gDebugButtonWindow = NULL; static HWND gYesButtonWindow = NULL; static HWND gNoButtonWindow = NULL; static bool gExiting = false; -static BfpCrashReportKind gCrashReportKind = BfpCrashReportKind_Default; static LRESULT CALLBACK SEHWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ +{ switch (uMsg) { case WM_COMMAND: @@ -198,7 +187,7 @@ static LRESULT CALLBACK SEHWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (::GetSaveFileNameW(&openFileName)) { - CreateMiniDump(gExceptionPointers, UTF8Encode(fileName)); + CreateMiniDump(CrashCatcher::Get()->mExceptionPointers, UTF8Encode(fileName)); } } else if (hwndCtl == gNoButtonWindow) @@ -207,7 +196,7 @@ static LRESULT CALLBACK SEHWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else if (hwndCtl == gDebugButtonWindow) { - gDebugError = true; + CrashCatcher::Get()->mDebugError = true; gExiting = true; } } @@ -222,6 +211,8 @@ static LRESULT CALLBACK SEHWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA static void ShowErrorDialog(const StringImpl& errorTitle, const StringImpl& errorText) { + bool gUseDefaultFonts; + HINSTANCE gHInstance = ::GetModuleHandle(NULL); OSVERSIONINFO aVersionInfo; @@ -247,7 +238,6 @@ static void ShowErrorDialog(const StringImpl& errorTitle, const StringImpl& erro gErrorTitle = errorTitle; gErrorText = errorText; - WNDCLASSW wc; wc.style = 0; wc.cbClsExtra = 0; @@ -810,18 +800,18 @@ static String GetVersion(const StringImpl& fileName) static void DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP) { - if (gCrashed) + if (CrashCatcher::Get()->mCrashed) return; - gCrashed = true; + CrashCatcher::Get()->mCrashed = true; HMODULE hMod = GetModuleHandleA(NULL); PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)((uint8*)hMod + pDosHdr->e_lfanew); bool isCLI = pNtHdr->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI; - if (gCrashReportKind == BfpCrashReportKind_GUI) + if (CrashCatcher::Get()->mCrashReportKind == BfpCrashReportKind_GUI) isCLI = false; - else if ((gCrashReportKind == BfpCrashReportKind_Console) || (gCrashReportKind == BfpCrashReportKind_PrintOnly)) + else if ((CrashCatcher::Get()->mCrashReportKind == BfpCrashReportKind_Console) || (CrashCatcher::Get()->mCrashReportKind == BfpCrashReportKind_PrintOnly)) isCLI = true; bool hasImageHelp = LoadImageHelp(); @@ -858,12 +848,12 @@ static void DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP) aDebugDump += StrFormat("Crash minidump saved as %s\n", crashPath.c_str()); } } - - for (auto func : gCrashInfoFuncs) + + for (auto func : CrashCatcher::Get()->mCrashInfoFuncs) func(); - aDebugDump.Append(gCrashInfo); - + aDebugDump.Append(CrashCatcher::Get()->mCrashInfo); + for (int i = 0; i < (int)aDebugDump.length(); i++) { char c = aDebugDump[i]; @@ -994,26 +984,31 @@ static void DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP) CrashCatcher::CrashCatcher() { - + mCrashed = false; + mInitialized = false; + mExceptionPointers = NULL; + mPreviousFilter = NULL; + mDebugError = false; + mCrashReportKind = BfpCrashReportKind_Default; } static long __stdcall SEHFilter(LPEXCEPTION_POINTERS lpExceptPtr) { - OutputDebugStrF("SEH Filter! CraskReportKind:%d\n", gCrashReportKind); + OutputDebugStrF("SEH Filter! CraskReportKind:%d\n", CrashCatcher::Get()->mCrashReportKind); - if (gCrashReportKind == BfpCrashReportKind_None) + if (CrashCatcher::Get()->mCrashReportKind == BfpCrashReportKind_None) { OutputDebugStrF("Silent Exiting\n"); ::TerminateProcess(GetCurrentProcess(), lpExceptPtr->ExceptionRecord->ExceptionCode); } - AutoCrit autoCrit(gBfpCritSect); + AutoCrit autoCrit(CrashCatcher::Get()->mBfpCritSect); //::ExitProcess(); //quick_exit(1); - if (!gCrashed) + if (!CrashCatcher::Get()->mCrashed) { - gExceptionPointers = lpExceptPtr; + CrashCatcher::Get()->mExceptionPointers = lpExceptPtr; //CreateMiniDump(lpExceptPtr); DoHandleDebugEvent(lpExceptPtr); } @@ -1021,7 +1016,7 @@ static long __stdcall SEHFilter(LPEXCEPTION_POINTERS lpExceptPtr) //if (!gDebugError) //SetErrorMode(SEM_NOGPFAULTERRORBOX); - if (gCrashReportKind == BfpCrashReportKind_PrintOnly) + if (CrashCatcher::Get()->mCrashReportKind == BfpCrashReportKind_PrintOnly) { ::TerminateProcess(GetCurrentProcess(), lpExceptPtr->ExceptionRecord->ExceptionCode); } @@ -1039,9 +1034,13 @@ static long __stdcall VectorExceptionHandler(LPEXCEPTION_POINTERS lpExceptPtr) void CrashCatcher::Init() -{ - gPreviousFilter = SetUnhandledExceptionFilter(SEHFilter); - OutputDebugStrF("Setting SEH filter %p\n", gPreviousFilter); +{ + if (mInitialized) + return; + + mPreviousFilter = SetUnhandledExceptionFilter(SEHFilter); + OutputDebugStrF("Setting SEH filter %p\n", mPreviousFilter); + mInitialized = true; // OutputDebugStrF("AddVectoredExceptionHandler 2\n"); // AddVectoredExceptionHandler(0, VectorExceptionHandler); @@ -1065,30 +1064,33 @@ void CrashCatcher::Test() void CrashCatcher::AddCrashInfoFunc(CrashInfoFunc crashInfoFunc) { - AutoCrit autoCrit(gBfpCritSect); - gCrashInfoFuncs.Add(crashInfoFunc); + AutoCrit autoCrit(mBfpCritSect); + mCrashInfoFuncs.Add(crashInfoFunc); } void CrashCatcher::AddInfo(const StringImpl& str) { - AutoCrit autoCrit(gBfpCritSect); - gCrashInfo.Append(str); + AutoCrit autoCrit(mBfpCritSect); + mCrashInfo.Append(str); + if (!str.EndsWith('\n')) + mCrashInfo.Append('\n'); } void CrashCatcher::Crash(const StringImpl& str) { OutputDebugStrF("CrashCatcher::Crash\n"); - gBfpCritSect.Lock(); - gCrashInfo.Append(str); + mBfpCritSect.Lock(); + mCrashInfo.Append(str); + mCrashInfo.Append("\n"); - if (gPreviousFilter == NULL) + if (mPreviousFilter == NULL) { // A little late, but install handler now so we can catch this crash Init(); } - gBfpCritSect.Unlock(); + mBfpCritSect.Unlock(); __debugbreak(); @@ -1104,11 +1106,74 @@ void CrashCatcher::Crash(const StringImpl& str) { }*/ - + exit(1); } void CrashCatcher::SetCrashReportKind(BfpCrashReportKind crashReportKind) { - gCrashReportKind = crashReportKind; + mCrashReportKind = crashReportKind; } + +struct CrashCatchMemory +{ +public: + CrashCatcher* mBpManager; + int mABIVersion; +}; + +#define CRASHCATCH_ABI_VERSION 1 + +static CrashCatcher* sCrashCatcher = NULL; +CrashCatcher* CrashCatcher::Get() +{ + if (sCrashCatcher != NULL) + return sCrashCatcher; + + char mutexName[128]; + sprintf(mutexName, "BfCrashCatch_mutex_%d", GetCurrentProcessId()); + char memName[128]; + sprintf(memName, "BfCrashCatch_mem_%d", GetCurrentProcessId()); + + auto mutex = ::CreateMutexA(NULL, TRUE, mutexName); + if (mutex != NULL) + { + HANDLE fileMapping = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, memName); + if (fileMapping != NULL) + { + CrashCatchMemory* sharedMem = (CrashCatchMemory*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CrashCatchMemory)); + if (sharedMem != NULL) + { + if (sharedMem->mABIVersion == CRASHCATCH_ABI_VERSION) + sCrashCatcher = sharedMem->mBpManager; + ::UnmapViewOfFile(sharedMem); + } + ::CloseHandle(fileMapping); + } + else + { + fileMapping = ::CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(CrashCatchMemory), memName); + if (fileMapping != NULL) + { + CrashCatchMemory* sharedMem = (CrashCatchMemory*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CrashCatchMemory)); + if (sharedMem != NULL) + { + sCrashCatcher = new CrashCatcher(); + sharedMem->mBpManager = sCrashCatcher; + sharedMem->mABIVersion = CRASHCATCH_ABI_VERSION; + ::UnmapViewOfFile(sharedMem); + ::ReleaseMutex(mutex); + } + else + { + ::CloseHandle(fileMapping); + ::CloseHandle(mutex); + } + } + } + } + + if (sCrashCatcher == NULL) + sCrashCatcher = new CrashCatcher(); + return sCrashCatcher; +} \ No newline at end of file diff --git a/BeefySysLib/platform/win/CrashCatcher.h b/BeefySysLib/platform/win/CrashCatcher.h index 37f5c9d7..1fd0ccd8 100644 --- a/BeefySysLib/platform/win/CrashCatcher.h +++ b/BeefySysLib/platform/win/CrashCatcher.h @@ -1,6 +1,7 @@ #pragma once #include "../../BeefySysLib/Common.h" +#include "../util/CritSect.h" NS_BF_BEGIN @@ -8,6 +9,17 @@ typedef void(*CrashInfoFunc)(); class CrashCatcher { +public: + Array mCrashInfoFuncs; + StringT<0> mCrashInfo; + bool mCrashed; + bool mInitialized; + CritSect mBfpCritSect; + EXCEPTION_POINTERS* mExceptionPointers; + LPTOP_LEVEL_EXCEPTION_FILTER mPreviousFilter; + bool mDebugError; + BfpCrashReportKind mCrashReportKind; + public: CrashCatcher(); @@ -17,7 +29,9 @@ public: void Test(); void Crash(const StringImpl& str); - void SetCrashReportKind(BfpCrashReportKind crashReportKind); + void SetCrashReportKind(BfpCrashReportKind crashReportKind); + + static CrashCatcher* Get(); }; NS_BF_END diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index 01984441..cf434429 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -23,8 +23,6 @@ #include "util/AllocDebug.h" -//kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - #pragma comment(lib, "ole32.lib") #pragma comment(lib, "shell32.lib") #pragma comment(lib, "user32.lib") @@ -47,10 +45,6 @@ struct WindowsSharedInfo static WindowsSharedInfo* gGlobalPlatformInfo = NULL; static HANDLE gGlobalMutex = 0; -static CrashCatcher gCrashCatcher; - -//#define HANDLE_TO_BFPFILE(val) ((BfpFile*)(val)) -//#define BFPFILE_TO_HANDLE(val) ((HANDLE)(val)) #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 typedef LONG KPRIORITY; @@ -950,11 +944,10 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flag // Then we install our abort handler. signal(SIGABRT, &AbortHandler); - gCrashCatcher.Init(); - + CrashCatcher::Get()->Init(); if ((flags & BfpSystemInitFlag_SilentCrash) != 0) - gCrashCatcher.SetCrashReportKind(BfpCrashReportKind_None); - } + CrashCatcher::Get()->SetCrashReportKind(BfpCrashReportKind_None); + } } BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) @@ -964,17 +957,17 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind) { - gCrashCatcher.SetCrashReportKind(crashReportKind); + CrashCatcher::Get()->SetCrashReportKind(crashReportKind); } BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc) { - gCrashCatcher.AddCrashInfoFunc(crashInfoFunc); + CrashCatcher::Get()->AddCrashInfoFunc(crashInfoFunc); } BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str) { - gCrashCatcher.AddInfo(str); + CrashCatcher::Get()->AddInfo(str); } BFP_EXPORT void BFP_CALLTYPE BfpSystem_Shutdown() @@ -1077,9 +1070,9 @@ BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* pt BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title) { if (title != NULL) - gCrashCatcher.Crash(String(title) + "\n" + String(error)); + CrashCatcher::Get()->Crash(String(title) + "\n" + String(error)); else - gCrashCatcher.Crash(error); + CrashCatcher::Get()->Crash(error); } BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 3c165566..41f6e8e5 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -2,6 +2,8 @@ #include "BfModule.h" #include "BeefySysLib/util/BeefPerf.h" #include "BeefySysLib/util/Hash.h" +#include +#include #pragma warning(push) #pragma warning(disable:4141) @@ -215,6 +217,147 @@ static llvm::Attribute::AttrKind LLVMMapAttribute(BfIRAttribute attr) return llvm::Attribute::None; } +#ifdef BF_PLATFORM_WINDOWS +struct BfTempFile +{ + String mContents; + String mFilePath; + CritSect mCritSect; + FILE* mFP; + + BfTempFile() + { + mFP = NULL; + } + + ~BfTempFile() + { + if (mFP != NULL) + fclose(mFP); + if (!mFilePath.IsEmpty()) + ::DeleteFileW(UTF8Decode(mFilePath).c_str()); + } + + bool Create() + { + AutoCrit autoCrit(mCritSect); + if (mFP != NULL) + return false; + + WCHAR wPath[4096]; + wPath[0] = 0; + ::GetTempPathW(4096, wPath); + + WCHAR wFilePath[4096]; + wFilePath[0] = 0; + GetTempFileNameW(wPath, L"bftmp", 0, wFilePath); + + mFilePath = UTF8Encode(wFilePath); + mFP = _wfopen(wFilePath, L"w+D"); + return mFP != NULL; + } + + String GetContents() + { + AutoCrit autoCrit(mCritSect); + + if (mFP != NULL) + { + fseek(mFP, 0, SEEK_END); + int size = (int)ftell(mFP); + fseek(mFP, 0, SEEK_SET); + + char* str = new char[size]; + int readSize = (int)fread(str, 1, size, mFP); + mContents.Append(str, readSize); + delete [] str; + fclose(mFP); + mFP = NULL; + + ::DeleteFileW(UTF8Decode(mFilePath).c_str()); + } + return mContents; + } +}; + +static BfTempFile gTempFile; + +static void AddStdErrCrashInfo() +{ + String tempContents = gTempFile.GetContents(); + if (!tempContents.IsEmpty()) + BfpSystem_AddCrashInfo(tempContents.c_str()); +} + +#endif + +/// + +BfIRCodeGen::BfIRCodeGen() +{ + mStream = NULL; + mBfIRBuilder = NULL; + + mNopInlineAsm = NULL; + mAsmObjectCheckAsm = NULL; + mHasDebugLoc = false; + mAttrSet = NULL; + mIRBuilder = NULL; + mDIBuilder = NULL; + mDICompileUnit = NULL; + mActiveFunction = NULL; + + mLLVMContext = new llvm::LLVMContext(); + mLLVMModule = NULL; + mIsCodeView = false; + mCmdCount = 0; + +#ifdef BF_PLATFORM_WINDOWS + if (::GetStdHandle(STD_ERROR_HANDLE) == 0) + { + if (gTempFile.Create()) + { + _dup2(fileno(gTempFile.mFP), 2); + BfpSystem_AddCrashInfoFunc(AddStdErrCrashInfo); + } + } +#endif +} + +BfIRCodeGen::~BfIRCodeGen() +{ + mDebugLoc = llvm::DebugLoc(); + mSavedDebugLocs.Clear(); + + delete mStream; + delete mIRBuilder; + delete mDIBuilder; + delete mLLVMModule; + delete mLLVMContext; +} + +void BfIRCodeGen::Fail(const StringImpl& error) +{ + if (mFailed) + return; + + if (mHasDebugLoc) + { + auto dbgLoc = mIRBuilder->getCurrentDebugLocation(); + if (dbgLoc) + { + llvm::DIFile* file = NULL; + if (llvm::DIScope* scope = llvm::dyn_cast(dbgLoc.getScope())) + { + BfIRCodeGenBase::Fail(StrFormat("%s at line %d:%d in %s/%s", error.c_str(), dbgLoc.getLine(), dbgLoc.getCol(), scope->getDirectory().data(), scope->getFilename().data())); + return; + } + } + } + + BfIRCodeGenBase::Fail(error); +} + void BfIRCodeGen::PrintModule() { Beefy::debug_ostream os; @@ -362,60 +505,6 @@ void BfIRCodeGen::SetResult(int id, llvm::MDNode* md) mResults.TryAdd(id, entry); } -BfIRCodeGen::BfIRCodeGen() -{ - mStream = NULL; - mBfIRBuilder = NULL; - - mNopInlineAsm = NULL; - mAsmObjectCheckAsm = NULL; - mHasDebugLoc = false; - mAttrSet = NULL; - mIRBuilder = NULL; - mDIBuilder = NULL; - mDICompileUnit = NULL; - mActiveFunction = NULL; - - mLLVMContext = new llvm::LLVMContext(); - mLLVMModule = NULL; - mIsCodeView = false; - mCmdCount = 0; -} - -BfIRCodeGen::~BfIRCodeGen() -{ - mDebugLoc = llvm::DebugLoc(); - mSavedDebugLocs.Clear(); - - delete mStream; - delete mIRBuilder; - delete mDIBuilder; - delete mLLVMModule; - delete mLLVMContext; -} - -void BfIRCodeGen::Fail(const StringImpl& error) -{ - if (mFailed) - return; - - if (mHasDebugLoc) - { - auto dbgLoc = mIRBuilder->getCurrentDebugLocation(); - if (dbgLoc) - { - llvm::DIFile* file = NULL; - if (llvm::DIScope* scope = llvm::dyn_cast(dbgLoc.getScope())) - { - BfIRCodeGenBase::Fail(StrFormat("%s at line %d:%d in %s/%s", error.c_str(), dbgLoc.getLine(), dbgLoc.getCol(), scope->getDirectory().data(), scope->getFilename().data())); - return; - } - } - } - - BfIRCodeGenBase::Fail(error); -} - void BfIRCodeGen::ProcessBfIRData(const BfSizedArray& buffer) { struct InlineAsmErrorHook