feat: new VEH experience

This commit is contained in:
goat 2022-07-23 20:25:05 +02:00
parent 379c52f5d4
commit 8bc4d362ad
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
10 changed files with 269 additions and 61 deletions

View file

@ -0,0 +1,71 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "dalamud.ico"
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -165,14 +165,21 @@
<ClInclude Include="DalamudStartInfo.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="logging.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="unicode.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="veh.h" />
<ClInclude Include="xivfixes.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Dalamud.Boot.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="dalamud.ico" />
</ItemGroup>
<Target Name="RemoveExtraFiles" AfterTargets="PostBuildEvent">
<Delete Files="$(OutDir)$(TargetName).lib" />
<Delete Files="$(OutDir)$(TargetName).exp" />
</Target>
</Project>
</Project>

View file

@ -138,5 +138,12 @@
<ClInclude Include="..\lib\TsudaKageyu-minhook\src\HDE\table64.h">
<Filter>MinHook</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
</ItemGroup>
</Project>
<ItemGroup>
<ResourceCompile Include="Dalamud.Boot.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="dalamud.ico" />
</ItemGroup>
</Project>

BIN
Dalamud.Boot/dalamud.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

16
Dalamud.Boot/resource.h Normal file
View file

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Dalamud.Boot.rc
//
#define IDI_ICON1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -1,10 +1,26 @@
#include "pch.h"
#include "resource.h"
#include "veh.h"
#include <shellapi.h>
#include "logging.h"
#include "utils.h"
#pragma comment(lib, "comctl32.lib")
#if defined _M_IX86
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
PVOID g_veh_handle = nullptr;
bool g_veh_do_full_dump = false;
@ -69,11 +85,11 @@ bool get_module_file_and_base(const DWORD64 address, DWORD64& module_base, std::
}
bool is_ffxiv_address(const DWORD64 address)
bool is_ffxiv_address(const wchar_t* module_name, const DWORD64 address)
{
DWORD64 module_base;
if (std::filesystem::path module_path; get_module_file_and_base(address, module_base, module_path))
return _wcsicmp(module_path.filename().c_str(), L"ffxiv_dx11.exe") == 0;
return _wcsicmp(module_path.filename().c_str(), module_name) == 0;
return false;
}
@ -118,53 +134,9 @@ std::wstring to_address_string(const DWORD64 address, const bool try_ptrderef =
return value != 0 ? std::format(L"{} [{}]", addr_str, to_address_string(value, false)) : addr_str;
}
void print_exception_info(const EXCEPTION_POINTERS* ex, std::wostringstream& log)
void print_exception_info_extended(const EXCEPTION_POINTERS* ex, std::wostringstream& log)
{
size_t rec_index = 0;
for (auto rec = ex->ExceptionRecord; rec; rec = rec->ExceptionRecord)
{
log << std::format(L"\nException Info #{}\n", ++rec_index);
log << std::format(L"Address: {:X}\n", rec->ExceptionCode);
log << std::format(L"Flags: {:X}\n", rec->ExceptionFlags);
log << std::format(L"Address: {:X}\n", reinterpret_cast<size_t>(rec->ExceptionAddress));
if (!rec->NumberParameters)
continue;
log << L"Parameters: ";
for (DWORD i = 0; i < rec->NumberParameters; ++i)
{
if (i != 0)
log << L", ";
log << std::format(L"{:X}", rec->ExceptionInformation[i]);
}
}
log << L"\nCall Stack\n{";
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;
int frame_index = 0;
log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
do
{
if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &sf, &ctx, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
break;
log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
} while (sf.AddrReturn.Offset != 0 && sf.AddrPC.Offset != sf.AddrReturn.Offset);
log << L"\n}\n";
ctx = *ex->ContextRecord;
log << L"\nRegisters\n{";
@ -219,6 +191,70 @@ void print_exception_info(const EXCEPTION_POINTERS* ex, std::wostringstream& log
log << L"\n}\n";
}
void print_exception_info(const EXCEPTION_POINTERS* ex, std::wostringstream& log)
{
size_t rec_index = 0;
for (auto rec = ex->ExceptionRecord; rec; rec = rec->ExceptionRecord)
{
log << std::format(L"\nException Info #{}\n", ++rec_index);
log << std::format(L"Address: {:X}\n", rec->ExceptionCode);
log << std::format(L"Flags: {:X}\n", rec->ExceptionFlags);
log << std::format(L"Address: {:X}\n", reinterpret_cast<size_t>(rec->ExceptionAddress));
if (!rec->NumberParameters)
continue;
log << L"Parameters: ";
for (DWORD i = 0; i < rec->NumberParameters; ++i)
{
if (i != 0)
log << L", ";
log << std::format(L"{:X}", rec->ExceptionInformation[i]);
}
}
log << L"\nCall Stack\n{";
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;
int frame_index = 0;
log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
do
{
if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &sf, &ctx, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
break;
log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
} while (sf.AddrReturn.Offset != 0 && sf.AddrPC.Offset != sf.AddrReturn.Offset);
log << L"\n}\n";
}
HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd,
UINT uNotification,
WPARAM wParam,
LPARAM lParam,
LONG_PTR dwRefData)
{
HRESULT hr = S_OK;
switch (uNotification)
{
case TDN_CREATED:
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
break;
}
return hr;
}
LONG exception_handler(EXCEPTION_POINTERS* ex)
{
static std::recursive_mutex s_exception_handler_mutex;
@ -226,7 +262,8 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
if (!is_whitelist_exception(ex->ExceptionRecord->ExceptionCode))
return EXCEPTION_CONTINUE_SEARCH;
if (!is_ffxiv_address(ex->ContextRecord->Rip))
if (!is_ffxiv_address(L"ffxiv_dx11.exe", ex->ContextRecord->Rip) &&
!is_ffxiv_address(L"cimgui.dll", ex->ContextRecord->Rip))
return EXCEPTION_CONTINUE_SEARCH;
// block any other exceptions hitting the veh while the messagebox is open
@ -248,6 +285,8 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
SymRefreshModuleList(GetCurrentProcess());
print_exception_info(ex, log);
auto window_log_str = log.str();
print_exception_info_extended(ex, log);
MINIDUMP_EXCEPTION_INFORMATION ex_info;
ex_info.ClientPointers = false;
@ -257,9 +296,9 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
auto miniDumpType = MiniDumpWithDataSegs;
if (g_veh_do_full_dump)
miniDumpType = MiniDumpWithFullMemory;
HANDLE file = CreateFileW(dmp_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, miniDumpType, &ex_info, nullptr, nullptr);
//MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, miniDumpType, &ex_info, nullptr, nullptr);
CloseHandle(file);
std::wstring message;
@ -289,7 +328,58 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
logging::E(std::format(L"Trapped in VEH handler: {}", message));
// show in another thread to prevent messagebox from pumping messages of current thread
std::thread([&]() { MessageBoxW(nullptr, message.c_str(), L"Dalamud Error", MB_ICONERROR | MB_TOPMOST | MB_OK); }).join();
std::thread([&]()
{
int nButtonPressed = 0;
TASKDIALOGCONFIG config = {0};
const TASKDIALOG_BUTTON buttons[] = {
{IDOK, L"Disable all plugins"},
{IDABORT, L"Open help page"},
};
config.cbSize = sizeof(config);
config.hInstance = g_hModule;
config.dwCommonButtons = TDCBF_CLOSE_BUTTON;
config.pszMainIcon = MAKEINTRESOURCE(IDI_ICON1);
//config.hMainIcon = dalamud_icon;
config.pszMainInstruction = L"An error occurred";
config.pszContent = message.c_str();
config.pButtons = buttons;
config.cButtons = ARRAYSIZE(buttons);
config.pszExpandedInformation = window_log_str.c_str();
config.pszWindowTitle = L"Dalamud Error";
config.nDefaultButton = IDCLOSE;
config.cxWidth = 300;
// Can't do this, xiv stops pumping messages here
//config.hwndParent = FindWindowA("FFXIVGAME", NULL);
config.pfCallback = TaskDialogCallbackProc;
TaskDialogIndirect(&config, &nButtonPressed, NULL, NULL);
switch (nButtonPressed)
{
case IDOK:
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szPath)))
{
auto appdata = std::filesystem::path(szPath);
auto safemode_file_path = ( appdata / "XIVLauncher" / ".dalamud_safemode" );
std::ofstream ofs(safemode_file_path);
ofs << "STAY SAFE!!!";
ofs.close();
}
break;
case IDABORT:
ShellExecute(0, 0, L"https://goatcorp.github.io/faq/", 0, 0 , SW_SHOW );
break;
case IDCANCEL:
break;
default:
break;
}
}).join();
return EXCEPTION_CONTINUE_SEARCH;
}

View file

@ -497,6 +497,7 @@ void xivfixes::clr_failfast_hijack(bool bApply)
{
static const char* LogTag = "[xivfixes:clr_failfast_hijack]";
static std::optional<hooks::import_hook<decltype(RaiseFailFastException)>> s_HookClrFatalError;
static std::optional<hooks::import_hook<decltype(SetUnhandledExceptionFilter)>> s_HookSetUnhandledExceptionFilter;
if (bApply)
{
@ -506,7 +507,8 @@ void xivfixes::clr_failfast_hijack(bool bApply)
}
s_HookClrFatalError.emplace("kernel32.dll!RaiseFailFastException (import, backup_userdata_save)", "kernel32.dll", "RaiseFailFastException", 0);
s_HookSetUnhandledExceptionFilter.emplace("kernel32.dll!SetUnhandledExceptionFilter (lpTopLevelExceptionFilter)", "kernel32.dll", "SetUnhandledExceptionFilter", 0);
s_HookClrFatalError->set_detour([](PEXCEPTION_RECORD pExceptionRecord,
_In_opt_ PCONTEXT pContextRecord,
_In_ DWORD dwFlags)
@ -516,6 +518,12 @@ void xivfixes::clr_failfast_hijack(bool bApply)
return s_HookClrFatalError->call_original(pExceptionRecord, pContextRecord, dwFlags);
});
s_HookSetUnhandledExceptionFilter->set_detour([](LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) -> LPTOP_LEVEL_EXCEPTION_FILTER
{
logging::I("{} SetUnhandledExceptionFilter", LogTag);
return nullptr;
});
logging::I("{} Enable", LogTag);
}
else
@ -523,6 +531,7 @@ void xivfixes::clr_failfast_hijack(bool bApply)
if (s_HookClrFatalError) {
logging::I("{} Disable ClrFatalError", LogTag);
s_HookClrFatalError.reset();
s_HookSetUnhandledExceptionFilter.reset();
}
}
}