Permalink
Browse files

C client: Log much more info for debugging crashes on windows

  • Loading branch information...
UnknownShadow200 committed Sep 12, 2018
1 parent 1aa7c57 commit f265cf804453bc34909eeb024d96e97a2db195de
Showing with 200 additions and 94 deletions.
  1. +2 −2 src/Bitmap.c
  2. +2 −2 src/Deflate.c
  3. +196 −90 src/ErrorHandler.c
View
@@ -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) {
View
@@ -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 */
View
@@ -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, &copy, 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, &copy, 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); }

0 comments on commit f265cf8

Please sign in to comment.