mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
C client: Log much more info for debugging crashes on windows
This commit is contained in:
parent
1aa7c57a62
commit
f265cf8044
@ -342,7 +342,7 @@ ReturnCode Bitmap_DecodePng(Bitmap* bmp, struct Stream* stream) {
|
||||
for (i = 0; i < PNG_PALETTE; i++) {
|
||||
palette[i] = PackedCol_ARGB(0, 0, 0, 255);
|
||||
}
|
||||
bool gotHeader = false, readingChunks = true;
|
||||
bool readingChunks = true;
|
||||
|
||||
struct InflateState inflate;
|
||||
struct Stream compStream;
|
||||
@ -363,7 +363,6 @@ ReturnCode Bitmap_DecodePng(Bitmap* bmp, struct Stream* stream) {
|
||||
switch (fourCC) {
|
||||
case PNG_FourCC('I','H','D','R'): {
|
||||
if (dataSize != PNG_IHDR_SIZE) return PNG_ERR_INVALID_HEADER_SIZE;
|
||||
gotHeader = true;
|
||||
res = Stream_Read(stream, buffer, PNG_IHDR_SIZE);
|
||||
if (res) return res;
|
||||
|
||||
@ -442,6 +441,7 @@ ReturnCode Bitmap_DecodePng(Bitmap* bmp, struct Stream* stream) {
|
||||
while (!zlibHeader.Done) {
|
||||
if ((res = ZLibHeader_Read(&datStream, &zlibHeader))) return res;
|
||||
}
|
||||
if (!bmp->Scan0) return PNG_ERR_NO_DATA;
|
||||
|
||||
UInt32 bufferLen = bufferRows * scanlineBytes, bufferMax = bufferLen - scanlineBytes;
|
||||
while (curY < bmp->Height) {
|
||||
|
@ -661,8 +661,8 @@ static ReturnCode Inflate_StreamRead(struct Stream* stream, UInt8* data, UInt32
|
||||
|
||||
UInt8* cur = state->NextIn;
|
||||
UInt32 read, remaining = (UInt32)(inputEnd - state->NextIn);
|
||||
ReturnCode code = state->Source->Read(state->Source, cur, remaining, &read);
|
||||
if (code != 0) return code;
|
||||
ReturnCode res = state->Source->Read(state->Source, cur, remaining, &read);
|
||||
if (res) return res;
|
||||
|
||||
/* Did we fail to read in more input data? Can't immediately return here, */
|
||||
/* because there might be a few bits of data left in the bit buffer */
|
||||
|
@ -3,10 +3,10 @@
|
||||
#include "Chat.h"
|
||||
#include "Window.h"
|
||||
#include "Funcs.h"
|
||||
#include "Stream.h"
|
||||
|
||||
static void ErrorHandler_FailCore(ReturnCode result, const char* raw_msg, void* ctx);
|
||||
static void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx);
|
||||
static void ErrorHandler_Registers(STRING_TRANSIENT String* str, void* ctx);
|
||||
static void ErrorHandler_FailCommon(ReturnCode result, const char* raw_msg, void* ctx);
|
||||
static void ErrorHandler_DumpCommon(STRING_TRANSIENT String* str, void* ctx);
|
||||
|
||||
#if CC_BUILD_WIN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -19,6 +19,160 @@ static void ErrorHandler_Registers(STRING_TRANSIENT String* str, void* ctx);
|
||||
struct StackPointers { UInt64 Instruction, Frame, Stack; };
|
||||
struct SymbolAndName { IMAGEHLP_SYMBOL64 Symbol; char Name[256]; };
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Info dumping------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static Int32 ErrorHandler_GetFrames(CONTEXT* ctx, struct StackPointers* pointers, Int32 max) {
|
||||
STACKFRAME64 frame = { 0 };
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD type;
|
||||
|
||||
#ifdef _M_IX86
|
||||
type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = ctx->Eip;
|
||||
frame.AddrFrame.Offset = ctx->Ebp;
|
||||
frame.AddrStack.Offset = ctx->Esp;
|
||||
#elif _M_X64
|
||||
type = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = ctx->Rip;
|
||||
frame.AddrFrame.Offset = ctx->Rsp;
|
||||
frame.AddrStack.Offset = ctx->Rsp;
|
||||
#elif _M_IA64
|
||||
type = IMAGE_FILE_MACHINE_IA64;
|
||||
frame.AddrPC.Offset = ctx->StIIP;
|
||||
frame.AddrFrame.Offset = ctx->IntSp;
|
||||
frame.AddrBStore.Offset = ctx->RsBSP;
|
||||
frame.AddrStack.Offset = ctx->IntSp;
|
||||
frame.AddrBStore.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Unknown machine type"
|
||||
#endif
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
Int32 count;
|
||||
CONTEXT copy = *ctx;
|
||||
|
||||
for (count = 0; count < max; count++) {
|
||||
if (!StackWalk64(type, process, thread, &frame, ©, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) break;
|
||||
if (!frame.AddrFrame.Offset) break;
|
||||
|
||||
pointers[count].Instruction = frame.AddrPC.Offset;
|
||||
pointers[count].Frame = frame.AddrFrame.Offset;
|
||||
pointers[count].Stack = frame.AddrStack.Offset;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK ErrorHandler_DumpModule(const char* name, DWORD64 base, ULONG size, void* ctx) {
|
||||
char buffer[STRING_SIZE * 4];
|
||||
String str = String_FromArray(buffer);
|
||||
DWORD64 end = base + (size - 1);
|
||||
|
||||
String_Format3(&str, "%c = %x-%x\r\n", name, &base, &end);
|
||||
ErrorHandler_Log(&str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ErrorHandler_Backtrace(STRING_TRANSIENT String* backtrace, void* ctx) {
|
||||
struct SymbolAndName sym = { 0 };
|
||||
sym.Symbol.MaxNameLength = 255;
|
||||
sym.Symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
struct StackPointers pointers[40];
|
||||
Int32 i, frames = ErrorHandler_GetFrames((CONTEXT*)ctx, pointers, 40);
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
Int32 number = i + 1;
|
||||
UInt64 addr = (UInt64)pointers[i].Instruction;
|
||||
|
||||
char strBuffer[STRING_SIZE * 10];
|
||||
String str = String_FromArray(strBuffer);
|
||||
|
||||
/* instruction pointer */
|
||||
if (SymGetSymFromAddr64(process, addr, NULL, &sym.Symbol)) {
|
||||
String_Format3(&str, "%i) 0x%x - %c\r\n", &number, &addr, sym.Symbol.Name);
|
||||
} else {
|
||||
String_Format2(&str, "%i) 0x%x\r\n", &number, &addr);
|
||||
}
|
||||
|
||||
/* frame and stack address */
|
||||
String_AppendString(backtrace, &str);
|
||||
String_Format2(&str, " fp: %x, sp: %x\r\n", &pointers[i].Frame, &pointers[i].Stack);
|
||||
|
||||
/* line number */
|
||||
IMAGEHLP_LINE64 line = { 0 };
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (SymGetLineFromAddr64(process, addr, &number, &line)) {
|
||||
String_Format2(&str, " line %i in %c\r\n", &line.LineNumber, line.FileName);
|
||||
}
|
||||
|
||||
/* module address is in */
|
||||
IMAGEHLP_MODULE64 module = { 0 };
|
||||
module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
||||
if (SymGetModuleInfo64(process, addr, &module)) {
|
||||
String_Format2(&str, " in module %c (%c)\r\n", module.ModuleName, module.ImageName);
|
||||
}
|
||||
ErrorHandler_Log(&str);
|
||||
}
|
||||
String_AppendConst(backtrace, "\n");
|
||||
}
|
||||
|
||||
static void ErrorHandler_DumpCommon(STRING_TRANSIENT String* str, void* ctx) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
String backtrace = String_FromConst("-- backtrace --\r\n");
|
||||
ErrorHandler_Log(&backtrace);
|
||||
ErrorHandler_Backtrace(str, ctx);
|
||||
|
||||
String modules = String_FromConst("-- modules --\r\n");
|
||||
ErrorHandler_Log(&modules);
|
||||
EnumerateLoadedModules64(process, ErrorHandler_DumpModule, NULL);
|
||||
}
|
||||
|
||||
static void ErrorHandler_DumpRegisters(CONTEXT* ctx) {
|
||||
char strBuffer[STRING_SIZE * 8];
|
||||
String str = String_FromArray(strBuffer);
|
||||
String_AppendConst(&str, "-- registers --\r\n");
|
||||
|
||||
#ifdef _M_IX86
|
||||
String_Format3(&str, "eax=%y ebx=%y ecx=%y\r\n", &ctx->Eax, &ctx->Ebx, &ctx->Ecx);
|
||||
String_Format3(&str, "edx=%y esi=%y edi=%y\r\n", &ctx->Edx, &ctx->Esi, &ctx->Edi);
|
||||
String_Format3(&str, "eip=%y ebp=%y esp=%y\r\n", &ctx->Eip, &ctx->Ebp, &ctx->Esp);
|
||||
#elif _M_X64
|
||||
String_Format3(&str, "rax=%x rbx=%x rcx=%x\r\n", &ctx->Rax, &ctx->Rbx, &ctx->Rcx);
|
||||
String_Format3(&str, "rdx=%x rsi=%x rdi=%x\r\n", &ctx->Rdx, &ctx->Rsi, &ctx->Rdi);
|
||||
String_Format3(&str, "rip=%x rbp=%x rsp=%x\r\n", &ctx->Rip, &ctx->Rbp, &ctx->Rsp);
|
||||
String_Format3(&str, "r8 =%x r9 =%x r10=%x\r\n", &ctx->R8, &ctx->R9, &ctx->R10);
|
||||
String_Format3(&str, "r11=%x r12=%x r13=%x\r\n", &ctx->R11, &ctx->R12, &ctx->R13);
|
||||
String_Format2(&str, "r14=%x r15=%x\r\n" , &ctx->R14, &ctx->R15);
|
||||
#elif _M_IA64
|
||||
String_Format3(&str, "r1 =%x r2 =%x r3 =%x\r\n", &ctx->IntGp, &ctx->IntT0, &ctx->IntT1);
|
||||
String_Format3(&str, "r4 =%x r5 =%x r6 =%x\r\n", &ctx->IntS0, &ctx->IntS1, &ctx->IntS2);
|
||||
String_Format3(&str, "r7 =%x r8 =%x r9 =%x\r\n", &ctx->IntS3, &ctx->IntV0, &ctx->IntT2);
|
||||
String_Format3(&str, "r10=%x r11=%x r12=%x\r\n", &ctx->IntT3, &ctx->IntT4, &ctx->IntSp);
|
||||
String_Format3(&str, "r13=%x r14=%x r15=%x\r\n", &ctx->IntTeb, &ctx->IntT5, &ctx->IntT6);
|
||||
String_Format3(&str, "r16=%x r17=%x r18=%x\r\n", &ctx->IntT7, &ctx->IntT8, &ctx->IntT9);
|
||||
String_Format3(&str, "r19=%x r20=%x r21=%x\r\n", &ctx->IntT10, &ctx->IntT11, &ctx->IntT12);
|
||||
String_Format3(&str, "r22=%x r23=%x r24=%x\r\n", &ctx->IntT13, &ctx->IntT14, &ctx->IntT15);
|
||||
String_Format3(&str, "r25=%x r26=%x r27=%x\r\n", &ctx->IntT16, &ctx->IntT17, &ctx->IntT18);
|
||||
String_Format3(&str, "r28=%x r29=%x r30=%x\r\n", &ctx->IntT19, &ctx->IntT20, &ctx->IntT21);
|
||||
String_Format3(&str, "r31=%x nat=%x pre=%x\r\n", &ctx->IntT22, &ctx->IntNats,&ctx->Preds);
|
||||
#else
|
||||
#error "Unknown machine type"
|
||||
#endif
|
||||
ErrorHandler_Log(&str);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Error handling-----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static LONG WINAPI ErrorHandler_UnhandledFilter(struct _EXCEPTION_POINTERS* pInfo) {
|
||||
/* TODO: Write processor state to file*/
|
||||
char msgBuffer[128 + 1] = { 0 };
|
||||
@ -28,13 +182,13 @@ static LONG WINAPI ErrorHandler_UnhandledFilter(struct _EXCEPTION_POINTERS* pInf
|
||||
UInt64 addr = (UInt64)pInfo->ExceptionRecord->ExceptionAddress;
|
||||
String_Format2(&msg, "Unhandled exception 0x%y at 0x%x", &code, &addr);
|
||||
|
||||
ErrorHandler_FailCore(0, msg.buffer, pInfo->ContextRecord);
|
||||
ErrorHandler_DumpRegisters(pInfo->ContextRecord);
|
||||
ErrorHandler_FailCommon(0, msg.buffer, pInfo->ContextRecord);
|
||||
return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */
|
||||
}
|
||||
|
||||
void ErrorHandler_Init(const char* logFile) {
|
||||
SetUnhandledExceptionFilter(ErrorHandler_UnhandledFilter);
|
||||
/* TODO: Open log file */
|
||||
}
|
||||
|
||||
void ErrorHandler_ShowDialog(const char* title, const char* msg) {
|
||||
@ -85,91 +239,21 @@ void ErrorHandler_FailWithCode(ReturnCode result, const char* raw_msg) {
|
||||
ctx.ContextFlags = CONTEXT_CONTROL;
|
||||
#endif
|
||||
|
||||
ErrorHandler_FailCore(result, raw_msg, &ctx);
|
||||
ErrorHandler_FailCommon(result, raw_msg, &ctx);
|
||||
}
|
||||
#if _MSC_VER
|
||||
#pragma optimize ("", on)
|
||||
#endif
|
||||
|
||||
static Int32 ErrorHandler_GetFrames(CONTEXT* ctx, struct StackPointers* pointers, Int32 max) {
|
||||
STACKFRAME64 frame = { 0 };
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD type;
|
||||
|
||||
#ifdef _M_IX86
|
||||
type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = ctx->Eip;
|
||||
frame.AddrFrame.Offset = ctx->Ebp;
|
||||
frame.AddrStack.Offset = ctx->Esp;
|
||||
#elif _M_X64
|
||||
type = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = ctx->Rip;
|
||||
frame.AddrFrame.Offset = ctx->Rsp;
|
||||
frame.AddrStack.Offset = ctx->Rsp;
|
||||
#elif _M_IA64
|
||||
type = IMAGE_FILE_MACHINE_IA64;
|
||||
frame.AddrPC.Offset = ctx->StIIP;
|
||||
frame.AddrFrame.Offset = ctx->IntSp;
|
||||
frame.AddrBStore.Offset = ctx->RsBSP;
|
||||
frame.AddrStack.Offset = ctx->IntSp;
|
||||
frame.AddrBStore.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Unknown machine type"
|
||||
#endif
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
Int32 count;
|
||||
CONTEXT copy = *ctx;
|
||||
|
||||
for (count = 0; count < max; count++) {
|
||||
if (!StackWalk64(type, process, thread, &frame, ©, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) break;
|
||||
if (!frame.AddrFrame.Offset) break;
|
||||
|
||||
pointers[count].Instruction = frame.AddrPC.Offset;
|
||||
pointers[count].Frame = frame.AddrFrame.Offset;
|
||||
pointers[count].Stack = frame.AddrStack.Offset;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
struct SymbolAndName sym = { 0 };
|
||||
sym.Symbol.MaxNameLength = 255;
|
||||
sym.Symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
struct StackPointers pointers[40];
|
||||
Int32 frames = ErrorHandler_GetFrames((CONTEXT*)ctx, pointers, 40);
|
||||
|
||||
String_AppendConst(str, "\r\nBacktrace: \r\n");
|
||||
Int32 i;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
Int32 number = i + 1;
|
||||
UInt64 addr = (UInt64)pointers[i].Instruction;
|
||||
|
||||
/* TODO: Log ESP and EBP here too */
|
||||
/* TODO: SymGetLineFromAddr64 as well? */
|
||||
/* TODO: Log module here too */
|
||||
if (SymGetSymFromAddr64(process, addr, NULL, &sym.Symbol)) {
|
||||
String_Format3(str, "%i) 0x%x - %c\r\n", &number, &addr, sym.Symbol.Name);
|
||||
} else {
|
||||
String_Format2(str, "%i) 0x%x\r\n", &number, &addr);
|
||||
}
|
||||
}
|
||||
String_AppendConst(str, "\r\n");
|
||||
}
|
||||
#elif CC_BUILD_NIX
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------X11 message box-----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
Display* dpy;
|
||||
unsigned long X11_Col(UInt8 r, UInt8 g, UInt8 b) {
|
||||
Colormap cmap = XDefaultColormap(dpy, DefaultScreen(dpy));
|
||||
@ -389,6 +473,10 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Error handling-----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void ErrorHandler_Init(const char* logFile) {
|
||||
/* TODO: Implement this */
|
||||
}
|
||||
@ -401,35 +489,53 @@ void ErrorHandler_ShowDialog(const char* title, const char* msg) {
|
||||
X11Window_Free(&w);
|
||||
}
|
||||
|
||||
void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx) {
|
||||
void ErrorHandler_DumpCommon(STRING_TRANSIENT String* str, void* ctx) {
|
||||
/* TODO: Implement this */
|
||||
}
|
||||
|
||||
void ErrorHandler_FailWithCode(ReturnCode result, const char* raw_msg) {
|
||||
/* TODO: Implement this */
|
||||
ErrorHandler_FailCore(result, raw_msg, NULL);
|
||||
ErrorHandler_FailCommon(result, raw_msg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ErrorHandler_FailCore(ReturnCode result, const char* raw_msg, void* ctx) {
|
||||
|
||||
/*########################################################################################################################*
|
||||
*----------------------------------------------------------Common---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void* logFile;
|
||||
struct Stream logStream;
|
||||
bool logOpen;
|
||||
|
||||
void ErrorHandler_Log(STRING_PURE String* msg) {
|
||||
if (!logOpen) {
|
||||
logOpen = true;
|
||||
String path = String_FromConst("client.log");
|
||||
|
||||
ReturnCode res = File_Append(&logFile, &path);
|
||||
if (!res) Stream_FromFile(&logStream, logFile);
|
||||
}
|
||||
|
||||
if (!logStream.Meta.File) return;
|
||||
Stream_Write(&logStream, msg->buffer, msg->length);
|
||||
}
|
||||
|
||||
static void ErrorHandler_FailCommon(ReturnCode result, const char* raw_msg, void* ctx) {
|
||||
char logMsgBuffer[3070 + 1] = { 0 };
|
||||
String logMsg = { logMsgBuffer, 0, 3070 };
|
||||
|
||||
String_Format1(&logMsg, "ClassiCube crashed.\nMessge: %c\n", raw_msg);
|
||||
if (result) { String_Format1(&logMsg, "%y\n", &result); } else { result = 1; }
|
||||
ErrorHandler_Log(&logMsg);
|
||||
|
||||
//ErrorHandler_Registers(ctx, &logMsg);
|
||||
ErrorHandler_Backtrace(&logMsg, ctx);
|
||||
/* TODO: write to log file */
|
||||
ErrorHandler_DumpCommon(&logMsg, ctx);
|
||||
if (logStream.Meta.File) File_Close(logFile);
|
||||
|
||||
String_AppendConst(&logMsg, "Full details of the crash have been logged to 'client.log'.\n");
|
||||
String_AppendConst(&logMsg,
|
||||
"Please report the crash to github.com/UnknownShadow200/ClassicalSharp/issues so we can fix it.");
|
||||
ErrorHandler_ShowDialog("We're sorry", logMsg.buffer);
|
||||
Platform_Exit(result);
|
||||
}
|
||||
|
||||
void ErrorHandler_Log(STRING_PURE String* msg) {
|
||||
/* TODO: write to log file */
|
||||
}
|
||||
|
||||
void ErrorHandler_Fail(const char* raw_msg) { ErrorHandler_FailWithCode(0, raw_msg); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user