TeaSpeak-Client/native/crash_handler/src/win_crash_generator.cpp
2019-12-07 22:27:20 +01:00

117 lines
3.5 KiB
C++

#include <Windows.h>
#include <DbgHelp.h>
#include <tchar.h>
#include <string>
#include <algorithm>
#include <strsafe.h>
#ifdef WIN32
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
using namespace std;
extern void win_crash_callback(const fs::path& source_file, const std::string& error, bool success);
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
HANDLE hProcess,
DWORD dwPid,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
fs::path generate_temp_file(std::string& error) {
WCHAR szPath[MAX_PATH];
WCHAR szFileName[MAX_PATH];
DWORD dwBufferSize = MAX_PATH;
SYSTEMTIME stLocalTime;
GetLocalTime( &stLocalTime );
GetTempPathW( dwBufferSize, szPath );
CreateDirectoryW( szFileName, nullptr );
StringCchPrintfW(szFileName, MAX_PATH, L"%s\\%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
szPath,
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
GetCurrentProcessId(), GetCurrentThreadId());
return fs::path(szFileName);
}
void create_minidump(struct _EXCEPTION_POINTERS* apExceptionInfo)
{
string error;
HANDLE hDumpFile = nullptr;
fs::path file_path;
HMODULE mhLib = ::LoadLibrary(_T("dbghelp.dll"));
if(!mhLib) {
error = "failed to file dbghelp.dll";
goto error_handling;
}
auto pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(mhLib, "MiniDumpWriteDump");
if(!pDump) {
error = "failed to file find MiniDumpWriteDump handle";
goto error_handling;
}
file_path = generate_temp_file(error);
hDumpFile = CreateFileW(file_path.wstring().c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, nullptr, CREATE_ALWAYS, 0, nullptr);
if(!hDumpFile) {
error = "failed to open file";
goto error_handling;
}
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo{};
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = apExceptionInfo;
ExInfo.ClientPointers = FALSE;
if(!pDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &ExInfo, nullptr, nullptr)) {
error = "failed to generate dump file";
goto error_handling;
}
::CloseHandle(hDumpFile);
win_crash_callback(file_path, error, true);
return;
}
error_handling:
if(hDumpFile) {
::CloseHandle(hDumpFile);
}
win_crash_callback(file_path, error, false);
}
LONG WINAPI unhandled_handler(struct _EXCEPTION_POINTERS* apExceptionInfo) {
auto code = apExceptionInfo->ExceptionRecord->ExceptionCode;
auto crash = false;
switch(code) {
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_STACK_OVERFLOW:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_IN_PAGE_ERROR:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
crash = true;
break;
default:
crash = false;
}
if(!crash)
return EXCEPTION_CONTINUE_SEARCH;
create_minidump(apExceptionInfo);
exit(1);
return EXCEPTION_EXECUTE_HANDLER;
}