From f265cf804453bc34909eeb024d96e97a2db195de Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 12 Sep 2018 17:03:20 +1000 Subject: [PATCH] C client: Log much more info for debugging crashes on windows --- src/Bitmap.c | 4 +- src/Deflate.c | 4 +- src/ErrorHandler.c | 286 +++++++++++++++++++++++++++++++-------------- 3 files changed, 200 insertions(+), 94 deletions(-) diff --git a/src/Bitmap.c b/src/Bitmap.c index 8c1b20bab..735f0ecd4 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -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) { diff --git a/src/Deflate.c b/src/Deflate.c index 727c07a54..2aee7cd6e 100644 --- a/src/Deflate.c +++ b/src/Deflate.c @@ -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 */ diff --git a/src/ErrorHandler.c b/src/ErrorHandler.c index 0dfc12002..78a68761b 100644 --- a/src/ErrorHandler.c +++ b/src/ErrorHandler.c @@ -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 #include #include #include + +/*########################################################################################################################* +*-----------------------------------------------------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); }