mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Report CLR errors through DalamudCrashHandler/VEH by hooking ReportEventW
This commit is contained in:
parent
ddc743aae1
commit
9c2d2b7c1d
3 changed files with 71 additions and 8 deletions
|
|
@ -331,6 +331,47 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
||||||
logging::I("VEH was disabled manually");
|
logging::I("VEH was disabled manually");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================== CLR Reporting =================================== //
|
||||||
|
|
||||||
|
// This is pretty horrible - CLR just doesn't provide a way for us to handle these events, and the API for it
|
||||||
|
// was pushed back to .NET 11, so we have to hook ReportEventW and catch them ourselves for now.
|
||||||
|
// Ideally all of this will go away once they get to it.
|
||||||
|
static std::shared_ptr<hooks::global_import_hook<decltype(ReportEventW)>> s_hook;
|
||||||
|
s_hook = std::make_shared<hooks::global_import_hook<decltype(ReportEventW)>>("advapi32.dll!ReportEventW (global import, hook_clr_report_event)", L"advapi32.dll", "ReportEventW");
|
||||||
|
s_hook->set_detour([hook = s_hook.get()]( HANDLE hEventLog,
|
||||||
|
WORD wType,
|
||||||
|
WORD wCategory,
|
||||||
|
DWORD dwEventID,
|
||||||
|
PSID lpUserSid,
|
||||||
|
WORD wNumStrings,
|
||||||
|
DWORD dwDataSize,
|
||||||
|
LPCWSTR* lpStrings,
|
||||||
|
LPVOID lpRawData)->BOOL {
|
||||||
|
|
||||||
|
// Check for CLR Error Event IDs
|
||||||
|
if (dwEventID != 1026 && // ERT_UnhandledException: The process was terminated due to an unhandled exception
|
||||||
|
dwEventID != 1025 && // ERT_ManagedFailFast: The application requested process termination through System.Environment.FailFast
|
||||||
|
dwEventID != 1023 && // ERT_UnmanagedFailFast: The process was terminated due to an internal error in the .NET Runtime
|
||||||
|
dwEventID != 1027 && // ERT_StackOverflow: The process was terminated due to a stack overflow
|
||||||
|
dwEventID != 1028) // ERT_CodeContractFailed: The application encountered a bug. A managed code contract (precondition, postcondition, object invariant, or assert) failed
|
||||||
|
{
|
||||||
|
return hook->call_original(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wNumStrings == 0 || lpStrings == nullptr) {
|
||||||
|
logging::W("ReportEventW called with no strings.");
|
||||||
|
return hook->call_original(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In most cases, DalamudCrashHandler will kill us now, so call original here to make sure we still write to the event log.
|
||||||
|
const BOOL original_ret = hook->call_original(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
|
||||||
|
|
||||||
|
const std::wstring error_details(lpStrings[0]);
|
||||||
|
veh::raise_external_event(error_details);
|
||||||
|
|
||||||
|
return original_ret;
|
||||||
|
});
|
||||||
|
|
||||||
// ============================== Dalamud ==================================== //
|
// ============================== Dalamud ==================================== //
|
||||||
|
|
||||||
if (static_cast<int>(g_startInfo.BootWaitMessageBox) & static_cast<int>(DalamudStartInfo::WaitMessageboxFlags::BeforeDalamudEntrypoint))
|
if (static_cast<int>(g_startInfo.BootWaitMessageBox) & static_cast<int>(DalamudStartInfo::WaitMessageboxFlags::BeforeDalamudEntrypoint))
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#include "crashhandler_shared.h"
|
#include "crashhandler_shared.h"
|
||||||
#include "DalamudStartInfo.h"
|
#include "DalamudStartInfo.h"
|
||||||
|
|
||||||
|
#define CUSTOM_EXCEPTION_EXTERNAL_EVENT 0x12345679
|
||||||
|
|
||||||
#pragma comment(lib, "comctl32.lib")
|
#pragma comment(lib, "comctl32.lib")
|
||||||
|
|
||||||
#if defined _M_IX86
|
#if defined _M_IX86
|
||||||
|
|
@ -31,6 +33,8 @@ HANDLE g_crashhandler_process = nullptr;
|
||||||
HANDLE g_crashhandler_event = nullptr;
|
HANDLE g_crashhandler_event = nullptr;
|
||||||
HANDLE g_crashhandler_pipe_write = nullptr;
|
HANDLE g_crashhandler_pipe_write = nullptr;
|
||||||
|
|
||||||
|
wchar_t g_external_event_info[16384] = L"";
|
||||||
|
|
||||||
std::recursive_mutex g_exception_handler_mutex;
|
std::recursive_mutex g_exception_handler_mutex;
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::system_clock> g_time_start;
|
std::chrono::time_point<std::chrono::system_clock> g_time_start;
|
||||||
|
|
@ -190,7 +194,11 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
|
||||||
DuplicateHandle(GetCurrentProcess(), g_crashhandler_event, g_crashhandler_process, &exinfo.hEventHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
DuplicateHandle(GetCurrentProcess(), g_crashhandler_event, g_crashhandler_process, &exinfo.hEventHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||||
|
|
||||||
std::wstring stackTrace;
|
std::wstring stackTrace;
|
||||||
if (!g_clr)
|
if (ex->ExceptionRecord->ExceptionCode == CUSTOM_EXCEPTION_EXTERNAL_EVENT)
|
||||||
|
{
|
||||||
|
stackTrace = std::wstring(g_external_event_info);
|
||||||
|
}
|
||||||
|
else if (!g_clr)
|
||||||
{
|
{
|
||||||
stackTrace = L"(no CLR stack trace available)";
|
stackTrace = L"(no CLR stack trace available)";
|
||||||
}
|
}
|
||||||
|
|
@ -251,6 +259,12 @@ LONG WINAPI structured_exception_handler(EXCEPTION_POINTERS* ex)
|
||||||
|
|
||||||
LONG WINAPI vectored_exception_handler(EXCEPTION_POINTERS* ex)
|
LONG WINAPI vectored_exception_handler(EXCEPTION_POINTERS* ex)
|
||||||
{
|
{
|
||||||
|
// special case for CLR exceptions, always trigger crash handler
|
||||||
|
if (ex->ExceptionRecord->ExceptionCode == CUSTOM_EXCEPTION_EXTERNAL_EVENT)
|
||||||
|
{
|
||||||
|
return exception_handler(ex);
|
||||||
|
}
|
||||||
|
|
||||||
if (ex->ExceptionRecord->ExceptionCode == 0x12345678)
|
if (ex->ExceptionRecord->ExceptionCode == 0x12345678)
|
||||||
{
|
{
|
||||||
// pass
|
// pass
|
||||||
|
|
@ -434,3 +448,10 @@ bool veh::remove_handler()
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void veh::raise_external_event(const std::wstring& errorMessage)
|
||||||
|
{
|
||||||
|
const auto info_size = std::min(errorMessage.size(), std::size(g_external_event_info) - 1);
|
||||||
|
wcsncpy_s(g_external_event_info, errorMessage.c_str(), info_size);
|
||||||
|
RaiseException(CUSTOM_EXCEPTION_EXTERNAL_EVENT, 0, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,5 @@ namespace veh
|
||||||
{
|
{
|
||||||
bool add_handler(bool doFullDump, const std::string& workingDirectory);
|
bool add_handler(bool doFullDump, const std::string& workingDirectory);
|
||||||
bool remove_handler();
|
bool remove_handler();
|
||||||
|
void raise_external_event(const std::wstring& info);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue