1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Added ability to catch llvm errs(), shared crashcatcher object

This commit is contained in:
Brian Fiete 2020-05-28 07:25:25 -07:00
parent 76e29d385b
commit f1eafa8d81
4 changed files with 274 additions and 113 deletions

View file

@ -1,5 +1,4 @@
#include "CrashCatcher.h"
#include "../util/CritSect.h"
#include "../util/Dictionary.h"
#include <commdlg.h>
#include <time.h>
@ -51,15 +50,7 @@ static SYMFUNCTIONTABLEACCESSPROC gSymFunctionTableAccess = NULL;
static SYMGETMODULEBASEPROC gSymGetModuleBase = NULL;
static SYMGETSYMFROMADDRPROC gSymGetSymFromAddr = NULL;
static SYMGETLINEFROMADDR gSymGetLineFromAddr = NULL;
static Array<CrashInfoFunc> 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,7 +161,6 @@ 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)
{
@ -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();
@ -859,10 +849,10 @@ static void DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP)
}
}
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++)
{
@ -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);
}
@ -1040,8 +1035,12 @@ 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();
@ -1110,5 +1112,68 @@ void CrashCatcher::Crash(const StringImpl& str)
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;
}

View file

@ -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<CrashInfoFunc> mCrashInfoFuncs;
StringT<0> mCrashInfo;
bool mCrashed;
bool mInitialized;
CritSect mBfpCritSect;
EXCEPTION_POINTERS* mExceptionPointers;
LPTOP_LEVEL_EXCEPTION_FILTER mPreviousFilter;
bool mDebugError;
BfpCrashReportKind mCrashReportKind;
public:
CrashCatcher();
@ -18,6 +30,8 @@ public:
void Test();
void Crash(const StringImpl& str);
void SetCrashReportKind(BfpCrashReportKind crashReportKind);
static CrashCatcher* Get();
};
NS_BF_END

View file

@ -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,10 +944,9 @@ 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);
}
}
@ -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)

View file

@ -2,6 +2,8 @@
#include "BfModule.h"
#include "BeefySysLib/util/BeefPerf.h"
#include "BeefySysLib/util/Hash.h"
#include <io.h>
#include <fcntl.h>
#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<llvm::DIScope>(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<llvm::DIScope>(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<uint8>& buffer)
{
struct InlineAsmErrorHook