windows dumps
This commit is contained in:
155
src/loader.cpp
155
src/loader.cpp
@@ -47,58 +47,55 @@ namespace anm2ed
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
namespace
|
std::filesystem::path g_minidump_dir{};
|
||||||
|
PVOID g_vectored_handler{};
|
||||||
|
LONG g_dump_in_progress{};
|
||||||
|
|
||||||
|
void windows_minidump_write(EXCEPTION_POINTERS* exceptionPointers)
|
||||||
{
|
{
|
||||||
std::filesystem::path g_minidump_dir{};
|
if (g_minidump_dir.empty()) return;
|
||||||
PVOID g_vectored_handler{};
|
if (InterlockedExchange(&g_dump_in_progress, 1) != 0) return;
|
||||||
LONG g_dump_in_progress{};
|
|
||||||
|
|
||||||
void windows_minidump_write(EXCEPTION_POINTERS* exceptionPointers)
|
SYSTEMTIME st{};
|
||||||
{
|
GetLocalTime(&st);
|
||||||
if (g_minidump_dir.empty()) return;
|
|
||||||
if (InterlockedExchange(&g_dump_in_progress, 1) != 0) return;
|
|
||||||
|
|
||||||
SYSTEMTIME st{};
|
auto pid = GetCurrentProcessId();
|
||||||
GetLocalTime(&st);
|
auto code = exceptionPointers && exceptionPointers->ExceptionRecord
|
||||||
|
? exceptionPointers->ExceptionRecord->ExceptionCode
|
||||||
|
: 0u;
|
||||||
|
|
||||||
auto pid = GetCurrentProcessId();
|
auto filename = std::format("anm2ed_{:04}{:02}{:02}_{:02}{:02}{:02}_pid{:08x}_code{:08x}.dmp", st.wYear,
|
||||||
auto code = exceptionPointers && exceptionPointers->ExceptionRecord ? exceptionPointers->ExceptionRecord->ExceptionCode : 0u;
|
st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, pid, code);
|
||||||
|
auto dumpPath = g_minidump_dir / path::from_utf8(filename);
|
||||||
|
|
||||||
auto filename =
|
auto dumpPathW = dumpPath.wstring();
|
||||||
std::format("anm2ed_{:04}{:02}{:02}_{:02}{:02}{:02}_pid{:08x}_code{:08x}.dmp", st.wYear, st.wMonth,
|
HANDLE file = CreateFileW(dumpPathW.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS,
|
||||||
st.wDay, st.wHour, st.wMinute, st.wSecond, pid, code);
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
auto dumpPath = g_minidump_dir / path::from_utf8(filename);
|
if (file == INVALID_HANDLE_VALUE) return;
|
||||||
|
|
||||||
auto dumpPathW = dumpPath.wstring();
|
MINIDUMP_EXCEPTION_INFORMATION mei{};
|
||||||
HANDLE file =
|
mei.ThreadId = GetCurrentThreadId();
|
||||||
CreateFileW(dumpPathW.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
mei.ExceptionPointers = exceptionPointers;
|
||||||
if (file == INVALID_HANDLE_VALUE) return;
|
mei.ClientPointers = FALSE;
|
||||||
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION mei{};
|
const MINIDUMP_TYPE dumpType = MiniDumpWithFullMemory;
|
||||||
mei.ThreadId = GetCurrentThreadId();
|
MiniDumpWriteDump(GetCurrentProcess(), pid, file, dumpType, exceptionPointers ? &mei : nullptr, nullptr, nullptr);
|
||||||
mei.ExceptionPointers = exceptionPointers;
|
|
||||||
mei.ClientPointers = FALSE;
|
|
||||||
|
|
||||||
// Full memory is large but most useful for user-submitted dumps.
|
FlushFileBuffers(file);
|
||||||
const MINIDUMP_TYPE dumpType = MiniDumpWithFullMemory;
|
CloseHandle(file);
|
||||||
MiniDumpWriteDump(GetCurrentProcess(), pid, file, dumpType, exceptionPointers ? &mei : nullptr, nullptr, nullptr);
|
}
|
||||||
|
|
||||||
FlushFileBuffers(file);
|
LONG WINAPI windows_unhandled_exception_filter(EXCEPTION_POINTERS* exceptionPointers)
|
||||||
CloseHandle(file);
|
{
|
||||||
}
|
windows_minidump_write(exceptionPointers);
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
LONG WINAPI windows_unhandled_exception_filter(EXCEPTION_POINTERS* exceptionPointers)
|
LONG CALLBACK windows_vectored_exception_handler(EXCEPTION_POINTERS* exceptionPointers)
|
||||||
{
|
{
|
||||||
windows_minidump_write(exceptionPointers);
|
windows_minidump_write(exceptionPointers);
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG CALLBACK windows_vectored_exception_handler(EXCEPTION_POINTERS* exceptionPointers)
|
|
||||||
{
|
|
||||||
windows_minidump_write(exceptionPointers);
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void windows_minidumps_configure()
|
void windows_minidumps_configure()
|
||||||
{
|
{
|
||||||
@@ -112,85 +109,11 @@ namespace anm2ed
|
|||||||
|
|
||||||
g_minidump_dir = dumpDir;
|
g_minidump_dir = dumpDir;
|
||||||
|
|
||||||
// Install both: vectored handler (more reliable) and unhandled filter (fallback).
|
|
||||||
if (!g_vectored_handler) g_vectored_handler = AddVectoredExceptionHandler(1, windows_vectored_exception_handler);
|
if (!g_vectored_handler) g_vectored_handler = AddVectoredExceptionHandler(1, windows_vectored_exception_handler);
|
||||||
SetUnhandledExceptionFilter(windows_unhandled_exception_filter);
|
SetUnhandledExceptionFilter(windows_unhandled_exception_filter);
|
||||||
|
|
||||||
logger.info(std::format("MiniDumpWriteDump enabled: {}", path::to_utf8(dumpDir)));
|
logger.info(std::format("MiniDumpWriteDump enabled: {}", path::to_utf8(dumpDir)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void windows_wer_localdumps_configure()
|
|
||||||
{
|
|
||||||
#ifndef DEBUG
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto prefDir = sdl::preferences_directory_get();
|
|
||||||
if (prefDir.empty()) return;
|
|
||||||
|
|
||||||
std::error_code ec{};
|
|
||||||
auto dumpDir = prefDir / "crash";
|
|
||||||
std::filesystem::create_directories(dumpDir, ec);
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
logger.warning(std::format("Failed to create dump directory {}: {}", path::to_utf8(dumpDir), ec.message()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t modulePath[MAX_PATH]{};
|
|
||||||
auto charsWritten = GetModuleFileNameW(nullptr, modulePath, MAX_PATH);
|
|
||||||
if (charsWritten == 0 || charsWritten >= MAX_PATH)
|
|
||||||
{
|
|
||||||
logger.warning(std::format("Failed to get module filename for WER LocalDumps (error {}).", GetLastError()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto exeName = std::filesystem::path(modulePath).filename().wstring();
|
|
||||||
if (exeName.empty())
|
|
||||||
{
|
|
||||||
logger.warning("Failed to determine executable name for WER LocalDumps.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto subkey = std::wstring(L"Software\\Microsoft\\Windows Error Reporting\\LocalDumps\\") + exeName;
|
|
||||||
|
|
||||||
HKEY key{};
|
|
||||||
auto status =
|
|
||||||
RegCreateKeyExW(HKEY_CURRENT_USER, subkey.c_str(), 0, nullptr, 0, KEY_SET_VALUE, nullptr, &key, nullptr);
|
|
||||||
if (status != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
logger.warning(std::format("Failed to create/open WER LocalDumps key (status {}).", (int)status));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto closeKey = [&]()
|
|
||||||
{
|
|
||||||
if (key) RegCloseKey(key);
|
|
||||||
key = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto dumpDirW = dumpDir.wstring();
|
|
||||||
const DWORD dumpType = 2; // full dump
|
|
||||||
const DWORD dumpCount = 10;
|
|
||||||
|
|
||||||
status = RegSetValueExW(key, L"DumpFolder", 0, REG_EXPAND_SZ, (const BYTE*)dumpDirW.c_str(),
|
|
||||||
(DWORD)((dumpDirW.size() + 1) * sizeof(wchar_t)));
|
|
||||||
if (status != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
logger.warning(std::format("Failed to set WER DumpFolder (status {}).", (int)status));
|
|
||||||
closeKey();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = RegSetValueExW(key, L"DumpType", 0, REG_DWORD, (const BYTE*)&dumpType, sizeof(dumpType));
|
|
||||||
if (status != ERROR_SUCCESS) logger.warning(std::format("Failed to set WER DumpType (status {}).", (int)status));
|
|
||||||
|
|
||||||
status = RegSetValueExW(key, L"DumpCount", 0, REG_DWORD, (const BYTE*)&dumpCount, sizeof(dumpCount));
|
|
||||||
if (status != ERROR_SUCCESS) logger.warning(std::format("Failed to set WER DumpCount (status {}).", (int)status));
|
|
||||||
|
|
||||||
closeKey();
|
|
||||||
logger.info(std::format("Crash dumps enabled: {}", path::to_utf8(dumpDir)));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool socket_paths_send(Socket& socket, const std::vector<std::string>& paths)
|
bool socket_paths_send(Socket& socket, const std::vector<std::string>& paths)
|
||||||
|
|||||||
Reference in New Issue
Block a user