Skip to content

Commit 3cc3e57

Browse files
committed
#75 wip: xboxビルドテスト v54
1 parent 9d59d17 commit 3cc3e57

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

templates/xbox/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ target_link_libraries(Next2DXboxHost PRIVATE
153153
dxgi
154154
dxguid
155155
windowscodecs # WIC: 画像デコード
156+
dbghelp # クラッシュハンドラのスタックトレース (StackWalk64/SymFromAddr)
156157
)
157158

158159
if(NEXT2D_IS_CONSOLE)

templates/xbox/src/main.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <Windows.h>
66
#include <windowsx.h>
77
#include <timeapi.h>
8+
#include <DbgHelp.h>
89
#include <XGameRuntime.h>
910

1011
#pragma comment(lib, "winmm.lib")
@@ -27,6 +28,7 @@
2728
#include <iostream>
2829
#include <sstream>
2930
#include <string>
31+
#include <cstring>
3032

3133
namespace fs = std::filesystem;
3234
using namespace next2d;
@@ -238,8 +240,96 @@ HWND CreateHostWindow(HINSTANCE instance, int width, int height)
238240

239241
} // namespace
240242

243+
// 未処理例外(segfault/AV 等)発生時にコールスタックを next2d-error.log へ書き出す。
244+
// GUI 実行では stderr が見えないため、C++ クラッシュ地点を掴む唯一の手段。
245+
// DbgHelp の StackWalk64 で例外コンテキストからフレームを辿り、可能なら
246+
// シンボル名 (関数+行) とモジュールを添える (PDB があれば関数/行まで解決)。
247+
static LONG WINAPI CrashHandler(EXCEPTION_POINTERS* ep)
248+
{
249+
std::ofstream ofs("next2d-error.log", std::ios::app);
250+
if (!ofs || !ep || !ep->ExceptionRecord || !ep->ContextRecord) {
251+
return EXCEPTION_EXECUTE_HANDLER;
252+
}
253+
254+
ofs << "\n[CRASH] code=0x" << std::hex
255+
<< ep->ExceptionRecord->ExceptionCode
256+
<< " addr=" << ep->ExceptionRecord->ExceptionAddress
257+
<< std::dec << std::endl;
258+
259+
HANDLE process = GetCurrentProcess();
260+
HANDLE thread = GetCurrentThread();
261+
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
262+
SymInitialize(process, nullptr, TRUE);
263+
264+
CONTEXT ctx = *ep->ContextRecord;
265+
STACKFRAME64 frame = {};
266+
DWORD machine = 0;
267+
#if defined(_M_X64)
268+
machine = IMAGE_FILE_MACHINE_AMD64;
269+
frame.AddrPC.Offset = ctx.Rip;
270+
frame.AddrFrame.Offset = ctx.Rbp;
271+
frame.AddrStack.Offset = ctx.Rsp;
272+
#elif defined(_M_ARM64)
273+
machine = IMAGE_FILE_MACHINE_ARM64;
274+
frame.AddrPC.Offset = ctx.Pc;
275+
frame.AddrFrame.Offset = ctx.Fp;
276+
frame.AddrStack.Offset = ctx.Sp;
277+
#endif
278+
frame.AddrPC.Mode = AddrModeFlat;
279+
frame.AddrFrame.Mode = AddrModeFlat;
280+
frame.AddrStack.Mode = AddrModeFlat;
281+
282+
char symbuf[sizeof(SYMBOL_INFO) + 256] = {};
283+
SYMBOL_INFO* sym = reinterpret_cast<SYMBOL_INFO*>(symbuf);
284+
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
285+
sym->MaxNameLen = 255;
286+
287+
for (int i = 0; i < 48; ++i) {
288+
if (!StackWalk64(machine, process, thread, &frame, &ctx,
289+
nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) {
290+
break;
291+
}
292+
const DWORD64 pc = frame.AddrPC.Offset;
293+
if (!pc) {
294+
break;
295+
}
296+
297+
ofs << " #" << i << " 0x" << std::hex << pc << std::dec;
298+
299+
DWORD64 disp = 0;
300+
if (SymFromAddr(process, pc, &disp, sym)) {
301+
ofs << " " << sym->Name << "+0x" << std::hex << disp << std::dec;
302+
}
303+
304+
const DWORD64 modbase = SymGetModuleBase64(process, pc);
305+
if (modbase) {
306+
char modname[MAX_PATH] = {};
307+
if (GetModuleFileNameA(reinterpret_cast<HMODULE>(modbase), modname, MAX_PATH)) {
308+
const char* base = std::strrchr(modname, '\\');
309+
ofs << " [" << (base ? base + 1 : modname) << "]";
310+
}
311+
}
312+
313+
IMAGEHLP_LINE64 line = {};
314+
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
315+
DWORD line_disp = 0;
316+
if (SymGetLineFromAddr64(process, pc, &line_disp, &line) && line.FileName) {
317+
const char* fbase = std::strrchr(line.FileName, '\\');
318+
ofs << " (" << (fbase ? fbase + 1 : line.FileName) << ":" << line.LineNumber << ")";
319+
}
320+
ofs << std::endl;
321+
}
322+
323+
ofs.flush();
324+
SymCleanup(process);
325+
return EXCEPTION_EXECUTE_HANDLER; // プロセスを終了させる (無限再入回避)
326+
}
327+
241328
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR cmd_line, int)
242329
{
330+
// 最初にクラッシュハンドラを設置し、以降の segfault 等でスタックを記録する。
331+
SetUnhandledExceptionFilter(CrashHandler);
332+
243333
// Sleep() の分解能を 1ms に上げる (フレームペーシング用。既定 15.6ms では
244334
// 60Hz を刻めない)
245335
timeBeginPeriod(1);

0 commit comments

Comments
 (0)