diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj
index 95eb9d12c..957bc4c10 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj
@@ -85,6 +85,7 @@
+
@@ -94,6 +95,7 @@
+
@@ -103,4 +105,4 @@
-
+
\ No newline at end of file
diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj.filters b/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
index afcc6e502..e357b90ea 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
@@ -27,6 +27,9 @@
Source Files
+
+ Source Files
+
@@ -50,6 +53,9 @@
Header Files
+
+ Header Files
+
diff --git a/Dalamud.Boot/dllmain.cpp b/Dalamud.Boot/dllmain.cpp
index d94e365de..62673173e 100644
--- a/Dalamud.Boot/dllmain.cpp
+++ b/Dalamud.Boot/dllmain.cpp
@@ -2,150 +2,12 @@
#define DllExport extern "C" __declspec(dllexport)
#include
-#include
#include
-#include
#include "..\lib\CoreCLR\CoreCLR.h"
#include "..\lib\CoreCLR\boot.h"
+#include "veh.h"
HMODULE g_hModule;
-PVOID g_hVEH; // VEH Handle to remove the handler later in DLL_PROCESS_DETACH
-
-std::vector g_exception_whitelist({
- STATUS_ACCESS_VIOLATION,
- STATUS_IN_PAGE_ERROR,
- STATUS_INVALID_HANDLE,
- STATUS_INVALID_PARAMETER,
- STATUS_NO_MEMORY,
- STATUS_ILLEGAL_INSTRUCTION,
- STATUS_NONCONTINUABLE_EXCEPTION,
- STATUS_INVALID_DISPOSITION,
- STATUS_ARRAY_BOUNDS_EXCEEDED,
- STATUS_FLOAT_DENORMAL_OPERAND,
- STATUS_FLOAT_DIVIDE_BY_ZERO,
- STATUS_FLOAT_INEXACT_RESULT,
- STATUS_FLOAT_INVALID_OPERATION,
- STATUS_FLOAT_OVERFLOW,
- STATUS_FLOAT_STACK_CHECK,
- STATUS_FLOAT_UNDERFLOW,
- STATUS_INTEGER_DIVIDE_BY_ZERO,
- STATUS_INTEGER_OVERFLOW,
- STATUS_PRIVILEGED_INSTRUCTION,
- STATUS_STACK_OVERFLOW,
- STATUS_DLL_NOT_FOUND,
- STATUS_ORDINAL_NOT_FOUND,
- STATUS_ENTRYPOINT_NOT_FOUND,
- STATUS_DLL_INIT_FAILED,
- STATUS_CONTROL_STACK_VIOLATION,
- STATUS_FLOAT_MULTIPLE_FAULTS,
- STATUS_FLOAT_MULTIPLE_TRAPS,
- STATUS_HEAP_CORRUPTION,
- STATUS_STACK_BUFFER_OVERRUN,
- STATUS_INVALID_CRUNTIME_PARAMETER,
- STATUS_THREAD_NOT_RUNNING,
- STATUS_ALREADY_REGISTERED
-});
-
-bool GetModuleFileAndBase(DWORD64 address, PDWORD64 moduleBase, std::filesystem::path& moduleFile)
-{
- HMODULE handle;
- if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(address), &handle))
- {
- if (wchar_t path[1024]; GetModuleFileNameW(handle, path, sizeof path / 2) > 0)
- {
- *moduleBase = reinterpret_cast(handle);
- moduleFile = path;
- return true;
- }
- }
- return false;
-}
-
-bool GetCallStack(PEXCEPTION_POINTERS ex, std::vector& addressList, DWORD frames = 10)
-{
- STACKFRAME64 sf;
- sf.AddrPC.Offset = ex->ContextRecord->Rip;
- sf.AddrPC.Mode = AddrModeFlat;
- sf.AddrStack.Offset = ex->ContextRecord->Rsp;
- sf.AddrStack.Mode = AddrModeFlat;
- sf.AddrFrame.Offset = ex->ContextRecord->Rbp;
- sf.AddrFrame.Mode = AddrModeFlat;
- CONTEXT ctx = *ex->ContextRecord;
- addressList.clear();
- do
- {
- if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &sf, &ctx, nullptr, nullptr, nullptr, nullptr))
- return false;
- addressList.push_back(sf.AddrPC.Offset);
- } while (sf.AddrReturn.Offset != 0 && --frames);
- return true;
-}
-
-LONG ExceptionHandler(PEXCEPTION_POINTERS ex)
-{
- // return if the exception is not in the whitelist
- if (std::ranges::find(g_exception_whitelist, ex->ExceptionRecord->ExceptionCode) == g_exception_whitelist.end())
- return EXCEPTION_CONTINUE_SEARCH;
-
- DWORD64 module_base;
- std::filesystem::path module_path;
-
- // return if the exception did not happen in ffxiv_dx11.exe
- if (!GetModuleFileAndBase(ex->ContextRecord->Rip, &module_base, module_path) || module_path.filename() != L"ffxiv_dx11.exe")
- return EXCEPTION_CONTINUE_SEARCH;
-
- wchar_t boot_mod_path[1024];
- GetModuleFileNameW(g_hModule, boot_mod_path, sizeof boot_mod_path / 2);
- std::filesystem::path fs_module_path(boot_mod_path);
-#ifndef NDEBUG
- std::wstring dmp_path = _wcsdup(fs_module_path.replace_filename(L"dalamud_appcrashd.dmp").wstring().c_str());
-#else
- std::wstring dmp_path = _wcsdup(fs_module_path.replace_filename(L"dalamud_appcrash.dmp").wstring().c_str());
-#endif
- std::wstring log_path = _wcsdup(fs_module_path.replace_filename(L"dalamud_appcrash.log").wstring().c_str());
-
- std::wofstream log;
- log.open(log_path, std::ios::app);
-
- std::wstring time_stamp;
-
- std::time_t t = std::time(nullptr);
- std::tm tm{};
- localtime_s(&tm, &t);
-
- log << L"[" << std::put_time(&tm, L"%d/%m/%Y %H:%M:%S") << L"] Exception " << std::uppercase << std::hex << ex->ExceptionRecord->ExceptionCode << " at ";
- if(GetModuleFileAndBase(ex->ContextRecord->Rip, &module_base, module_path))
- log << module_path.filename() << "+" << std::uppercase << std::hex << ex->ContextRecord->Rip - module_base << std::endl;
- else log << std::uppercase << std::hex << ex->ContextRecord->Rip << std::endl;
-
- std::vector callStack;
-
- if(GetCallStack(ex, callStack, -1))
- {
- log << L"Call Stack:" << std::endl;
- for(auto& addr : callStack)
- {
- if (GetModuleFileAndBase(addr, &module_base, module_path))
- log << L" " << module_path.filename().c_str() << "+" << std::uppercase << std::hex << addr - module_base << std::endl;
- else log << L" " << std::uppercase << std::hex << addr << std::endl;
- }
- }
-
- MINIDUMP_EXCEPTION_INFORMATION ex_info;
- ex_info.ClientPointers = true;
- ex_info.ExceptionPointers = ex;
- ex_info.ThreadId = GetCurrentThreadId();
-
- auto file = CreateFileW(dmp_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
- MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithDataSegs, &ex_info, nullptr, nullptr);
- CloseHandle(file);
-
- log << "Crash Dump: " << dmp_path << std::endl;
-
- log.close();
-
- return EXCEPTION_CONTINUE_SEARCH;
-}
DllExport DWORD WINAPI Initialize(LPVOID lpParam)
{
@@ -185,9 +47,8 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam)
// ============================== VEH ======================================== //
- g_hVEH = AddVectoredExceptionHandler(0, ExceptionHandler);
- if (g_hVEH)
- printf("VEH Installed [%p]\n", g_hVEH);
+ if (veh::add_handler())
+ printf("VEH Installed\n");
else printf("Failed to Install VEH\n");
// =========================================================================== //
@@ -212,8 +73,7 @@ BOOL APIENTRY DllMain(const HMODULE hModule, const DWORD dwReason, LPVOID lpRese
break;
case DLL_PROCESS_DETACH:
// remove the VEH on unload
- if (g_hVEH)
- RemoveVectoredExceptionHandler(g_hVEH);
+ veh::remove_handler();
break;
}
return TRUE;
diff --git a/Dalamud.Boot/veh.cpp b/Dalamud.Boot/veh.cpp
new file mode 100644
index 000000000..273ac001f
--- /dev/null
+++ b/Dalamud.Boot/veh.cpp
@@ -0,0 +1,163 @@
+#define WIN32_LEAN_AND_MEAN
+#include "veh.h"
+#include
+#include
+#include
+#include
+
+std::vector g_exception_whitelist({
+ STATUS_ACCESS_VIOLATION,
+ STATUS_IN_PAGE_ERROR,
+ STATUS_INVALID_HANDLE,
+ STATUS_INVALID_PARAMETER,
+ STATUS_NO_MEMORY,
+ STATUS_ILLEGAL_INSTRUCTION,
+ STATUS_NONCONTINUABLE_EXCEPTION,
+ STATUS_INVALID_DISPOSITION,
+ STATUS_ARRAY_BOUNDS_EXCEEDED,
+ STATUS_FLOAT_DENORMAL_OPERAND,
+ STATUS_FLOAT_DIVIDE_BY_ZERO,
+ STATUS_FLOAT_INEXACT_RESULT,
+ STATUS_FLOAT_INVALID_OPERATION,
+ STATUS_FLOAT_OVERFLOW,
+ STATUS_FLOAT_STACK_CHECK,
+ STATUS_FLOAT_UNDERFLOW,
+ STATUS_INTEGER_DIVIDE_BY_ZERO,
+ STATUS_INTEGER_OVERFLOW,
+ STATUS_PRIVILEGED_INSTRUCTION,
+ STATUS_STACK_OVERFLOW,
+ STATUS_DLL_NOT_FOUND,
+ STATUS_ORDINAL_NOT_FOUND,
+ STATUS_ENTRYPOINT_NOT_FOUND,
+ STATUS_DLL_INIT_FAILED,
+ STATUS_CONTROL_STACK_VIOLATION,
+ STATUS_FLOAT_MULTIPLE_FAULTS,
+ STATUS_FLOAT_MULTIPLE_TRAPS,
+ STATUS_HEAP_CORRUPTION,
+ STATUS_STACK_BUFFER_OVERRUN,
+ STATUS_INVALID_CRUNTIME_PARAMETER,
+ STATUS_THREAD_NOT_RUNNING,
+ STATUS_ALREADY_REGISTERED
+ });
+
+bool GetModuleFileAndBase(DWORD64 address, PDWORD64 moduleBase, std::filesystem::path& moduleFile)
+{
+ HMODULE handle;
+ if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(address), &handle))
+ {
+ if (wchar_t path[1024]; GetModuleFileNameW(handle, path, sizeof path / 2) > 0)
+ {
+ *moduleBase = reinterpret_cast(handle);
+ moduleFile = path;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GetCallStack(PEXCEPTION_POINTERS ex, std::vector& addressList, DWORD frames = 10)
+{
+ STACKFRAME64 sf;
+ sf.AddrPC.Offset = ex->ContextRecord->Rip;
+ sf.AddrPC.Mode = AddrModeFlat;
+ sf.AddrStack.Offset = ex->ContextRecord->Rsp;
+ sf.AddrStack.Mode = AddrModeFlat;
+ sf.AddrFrame.Offset = ex->ContextRecord->Rbp;
+ sf.AddrFrame.Mode = AddrModeFlat;
+ CONTEXT ctx = *ex->ContextRecord;
+ addressList.clear();
+ do
+ {
+ if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &sf, &ctx, nullptr, nullptr, nullptr, nullptr))
+ return false;
+ addressList.push_back(sf.AddrPC.Offset);
+ } while (sf.AddrReturn.Offset != 0 && --frames);
+ return true;
+}
+
+LONG ExceptionHandler(PEXCEPTION_POINTERS ex)
+{
+ // return if the exception is not in the whitelist
+ if (std::ranges::find(g_exception_whitelist, ex->ExceptionRecord->ExceptionCode) == g_exception_whitelist.end())
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ DWORD64 module_base;
+ std::filesystem::path module_path;
+
+ // return if the exception did not happen in ffxiv_dx11.exe
+ if (!GetModuleFileAndBase(ex->ContextRecord->Rip, &module_base, module_path) || module_path.filename() != L"ffxiv_dx11.exe")
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ GetModuleFileAndBase(reinterpret_cast(&ExceptionHandler), &module_base, module_path);
+#ifndef NDEBUG
+ std::wstring dmp_path = _wcsdup(module_path.replace_filename(L"dalamud_appcrashd.dmp").wstring().c_str());
+#else
+ std::wstring dmp_path = _wcsdup(module_path.replace_filename(L"dalamud_appcrash.dmp").wstring().c_str());
+#endif
+ std::wstring log_path = _wcsdup(module_path.replace_filename(L"dalamud_appcrash.log").wstring().c_str());
+
+ std::wofstream log;
+ log.open(log_path, std::ios::app);
+
+ std::wstring time_stamp;
+
+ std::time_t t = std::time(nullptr);
+ std::tm tm{};
+ localtime_s(&tm, &t);
+
+ log << L"[" << std::put_time(&tm, L"%d/%m/%Y %H:%M:%S") << L"] Exception " << std::uppercase << std::hex << ex->ExceptionRecord->ExceptionCode << " at ";
+ if (GetModuleFileAndBase(ex->ContextRecord->Rip, &module_base, module_path))
+ log << module_path.filename() << "+" << std::uppercase << std::hex << ex->ContextRecord->Rip - module_base << std::endl;
+ else log << std::uppercase << std::hex << ex->ContextRecord->Rip << std::endl;
+
+ if (std::vector call_stack; GetCallStack(ex, call_stack, -1))
+ {
+ log << L"Call Stack:" << std::endl;
+ for (auto& addr : call_stack)
+ {
+ if (GetModuleFileAndBase(addr, &module_base, module_path))
+ log << L" " << module_path.filename().c_str() << "+" << std::uppercase << std::hex << addr - module_base << std::endl;
+ else log << L" " << std::uppercase << std::hex << addr << std::endl;
+ }
+ }
+
+ MINIDUMP_EXCEPTION_INFORMATION ex_info;
+ ex_info.ClientPointers = true;
+ ex_info.ExceptionPointers = ex;
+ ex_info.ThreadId = GetCurrentThreadId();
+
+ auto file = CreateFileW(dmp_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithDataSegs, &ex_info, nullptr, nullptr);
+ CloseHandle(file);
+
+ log << "Crash Dump: " << dmp_path << std::endl;
+
+ log.close();
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+PVOID g_hVEH; // VEH Handle to remove the handler later in DLL_PROCESS_DETACH
+
+bool veh::add_handler()
+{
+ if (g_hVEH)
+ return false;
+ g_hVEH = AddVectoredExceptionHandler(0, ExceptionHandler);
+ return g_hVEH != nullptr;
+}
+
+bool veh::remove_handler()
+{
+ if (g_hVEH && RemoveVectoredExceptionHandler(g_hVEH) != 0)
+ {
+ g_hVEH = nullptr;
+ return true;
+ }
+ return false;
+}
+
+void* veh::get_handle()
+{
+ return g_hVEH;
+}
diff --git a/Dalamud.Boot/veh.h b/Dalamud.Boot/veh.h
new file mode 100644
index 000000000..ae199d70c
--- /dev/null
+++ b/Dalamud.Boot/veh.h
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace veh
+{
+ bool add_handler();
+ bool remove_handler();
+ void* get_handle();
+}