2026-03-27 00:08:46 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "Platform/Win32Utf8.h"
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
#include <dbghelp.h>
|
2026-03-27 00:08:46 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
|
|
|
|
namespace Platform {
|
|
|
|
|
|
|
|
|
|
inline std::string GetExecutableLogPath(const char* fileName) {
|
|
|
|
|
return GetExecutableDirectoryUtf8() + "\\" + fileName;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
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<SYMBOL_INFO*>(symbolStorage);
|
|
|
|
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
|
|
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
|
|
|
|
|
|
|
|
|
for (USHORT frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
|
|
|
|
const DWORD64 address = reinterpret_cast<DWORD64>(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<unsigned long long>(displacement));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SymGetLineFromAddr64(process, address, &lineDisplacement, &line)) {
|
|
|
|
|
fprintf(file, " (%s:%lu)", line.FileName, line.LineNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(file, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SymCleanup(process);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 00:08:46 +08:00
|
|
|
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);
|
2026-03-29 15:12:38 +08:00
|
|
|
WriteCrashStackTrace(file);
|
2026-03-27 00:08:46 +08:00
|
|
|
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
|