#pragma once #include "Platform/Win32Utf8.h" #include #include #include #include namespace XCEngine { namespace Editor { namespace Platform { inline std::string GetExecutableLogPath(const char* fileName) { return GetExecutableDirectoryUtf8() + "\\" + fileName; } inline void WriteCrashStackTrace(FILE* file) { if (file == nullptr) { return; } HANDLE process = GetCurrentProcess(); SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); if (!SymInitialize(process, nullptr, TRUE)) { fprintf(file, "[CRASH] SymInitialize failed: %lu\n", GetLastError()); return; } void* frames[64] = {}; const USHORT frameCount = CaptureStackBackTrace(0, 64, frames, nullptr); char symbolStorage[sizeof(SYMBOL_INFO) + MAX_SYM_NAME] = {}; SYMBOL_INFO* symbol = reinterpret_cast(symbolStorage); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = MAX_SYM_NAME; for (USHORT frameIndex = 0; frameIndex < frameCount; ++frameIndex) { const DWORD64 address = reinterpret_cast(frames[frameIndex]); DWORD64 displacement = 0; IMAGEHLP_LINE64 line = {}; line.SizeOfStruct = sizeof(line); DWORD lineDisplacement = 0; fprintf(file, "[CRASH] #%u 0x%p", frameIndex, frames[frameIndex]); if (SymFromAddr(process, address, &displacement, symbol)) { fprintf(file, " %s+0x%llX", symbol->Name, static_cast(displacement)); } if (SymGetLineFromAddr64(process, address, &lineDisplacement, &line)) { fprintf(file, " (%s:%lu)", line.FileName, line.LineNumber); } fprintf(file, "\n"); } SymCleanup(process); } inline LONG WINAPI CrashExceptionFilter(EXCEPTION_POINTERS* exceptionPointers) { const std::string logPath = GetExecutableLogPath("crash.log"); FILE* file = nullptr; fopen_s(&file, logPath.c_str(), "a"); if (file) { fprintf( file, "[CRASH] ExceptionCode=0x%08X, Address=0x%p\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); WriteCrashStackTrace(file); fclose(file); } fprintf( stderr, "[CRASH] ExceptionCode=0x%08X, Address=0x%p\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); return EXCEPTION_EXECUTE_HANDLER; } inline void InstallCrashExceptionFilter() { SetUnhandledExceptionFilter(CrashExceptionFilter); } inline void RedirectStderrToExecutableLog() { const std::string stderrPath = GetExecutableLogPath("stderr.log"); freopen(stderrPath.c_str(), "w", stderr); } } // namespace Platform } // namespace Editor } // namespace XCEngine