Log error message on separate line. Also start work on describing internal classicube errors.

This commit is contained in:
UnknownShadow200 2019-03-08 22:34:56 +11:00
parent cc3ae79136
commit 87f1677e62
14 changed files with 421 additions and 303 deletions

View File

@ -367,7 +367,7 @@ ReturnCode Png_Decode(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;
if (dataSize != PNG_IHDR_SIZE) return PNG_ERR_INVALID_HDR_SIZE;
res = Stream_Read(stream, tmp, PNG_IHDR_SIZE);
if (res) return res;

View File

@ -4,6 +4,7 @@
Copyright 2017 ClassicalSharp | Licensed under BSD-3
*/
/* NOTE: When changing these, remember to keep Logger.C up to date! */
enum ERRORS_ALL {
ERROR_BASE = 0xCCDED000UL,
ERR_END_OF_STREAM,
@ -23,7 +24,7 @@ enum ERRORS_ALL {
VORBIS_ERR_MAPPING_CHANS, VORBIS_ERR_MAPPING_RESERVED,
VORBIS_ERR_FRAME_TYPE,
/* PNG image decoding errors */
PNG_ERR_INVALID_SIG, PNG_ERR_INVALID_HEADER_SIZE, PNG_ERR_TOO_WIDE, PNG_ERR_TOO_TALL,
PNG_ERR_INVALID_SIG, PNG_ERR_INVALID_HDR_SIZE, PNG_ERR_TOO_WIDE, PNG_ERR_TOO_TALL,
PNG_ERR_INVALID_COL_BPP, PNG_ERR_COMP_METHOD, PNG_ERR_FILTER, PNG_ERR_INTERLACED,
PNG_ERR_PAL_ENTRIES, PNG_ERR_PAL_SIZE, PNG_ERR_TRANS_COUNT, PNG_ERR_TRANS_INVALID,
PNG_ERR_INVALID_END_SIZE, PNG_ERR_NO_DATA,

View File

@ -314,7 +314,14 @@ static void Game_OnLowVRAMDetected(void* obj) {
Chat_AddRaw("&cOut of VRAM! Halving view distance..");
}
static void Game_WarnFunc(const String* msg) { Chat_Add1("&c%s", msg); }
static void Game_WarnFunc(const String* msg) {
String str = *msg, line;
while (str.length) {
String_UNSAFE_SplitBy(&str, '\n', &line);
Chat_Add1("&c%s", &line);
}
}
static void Game_ExtractInitialTexturePack(void) {
String texPack; char texPackBuffer[STRING_SIZE];
@ -405,7 +412,7 @@ static void Game_LoadPlugins(void) {
ReturnCode res;
res = Directory_Enum(&dir, NULL, Game_LoadPlugin);
if (res) Logger_OldWarn(res, "enumerating plugins directory");
if (res) Logger_Warn(res, "enumerating plugins directory");
}
void Game_Free(void* obj);

View File

@ -1567,10 +1567,10 @@ static void UpdatesScreen_Init(struct LScreen* s_) {
String_InitArray(path, pathBuffer);
res = Process_GetExePath(&path);
if (res) { Logger_OldWarn(res, "getting .exe path"); return; }
if (res) { Logger_Warn(res, "getting .exe path"); return; }
res = File_GetModifiedTime(&path, &buildTime);
if (res) { Logger_OldWarn(res, "getting build time"); return; }
if (res) { Logger_Warn(res, "getting build time"); return; }
UpdatesScreen_Format(&s->LblYour, "Your build: ", buildTime);
}

View File

@ -494,13 +494,13 @@ static void FetchUpdateTask_Handle(uint8_t* data, uint32_t len) {
ReturnCode res;
res = Stream_WriteAllTo(&path, data, len);
if (res) { Logger_OldWarn(res, "saving update"); return; }
if (res) { Logger_Warn(res, "saving update"); return; }
res = File_SetModifiedTime(&path, FetchUpdateTask.Timestamp);
if (res) Logger_OldWarn(res, "setting update time");
if (res) Logger_Warn(res, "setting update time");
res = Platform_MarkExecutable(&path);
if (res) Logger_OldWarn(res, "making update executable");
if (res) Logger_Warn(res, "making update executable");
}
void FetchUpdateTask_Run(bool release, bool d3d9) {
@ -565,7 +565,7 @@ static void FetchFlagsTask_Handle(uint8_t* data, uint32_t len) {
Stream_ReadonlyMemory(&s, data, len);
res = Png_Decode(&flags[FetchFlagsTask.Count].Bmp, &s);
if (res) Logger_OldWarn(res, "decoding flag");
if (res) Logger_Warn(res, "decoding flag");
FetchFlagsTask.Count++;
FetchFlagsTask_DownloadNext();

View File

@ -364,7 +364,7 @@ static ReturnCode Launcher_ProcessZipEntry(const String* path, struct Stream* da
res = Png_Decode(&fontBmp, data);
if (res) {
Logger_OldWarn(res, "decoding default.png"); return res;
Logger_Warn(res, "decoding default.png"); return res;
} else {
Drawer2D_SetFontBitmap(&fontBmp);
useBitmappedFont = !Options_GetBool(OPT_USE_CHAT_FONT, false);
@ -374,7 +374,7 @@ static ReturnCode Launcher_ProcessZipEntry(const String* path, struct Stream* da
res = Png_Decode(&bmp, data);
if (res) {
Logger_OldWarn(res, "decoding terrain.png"); return res;
Logger_Warn(res, "decoding terrain.png"); return res;
} else {
Launcher_LoadTextures(&bmp);
}
@ -388,18 +388,14 @@ static void Launcher_ExtractTexturePack(const String* path) {
ReturnCode res;
res = Stream_OpenFile(&stream, path);
if (res) {
Logger_OldWarn(res, "opening texture pack"); return;
}
if (res) { Logger_Warn(res, "opening texture pack"); return; }
Zip_Init(&state, &stream);
state.SelectEntry = Launcher_SelectZipEntry;
state.ProcessEntry = Launcher_ProcessZipEntry;
res = Zip_Extract(&state);
if (res) {
Logger_OldWarn(res, "extracting texture pack");
}
if (res) { Logger_Warn(res, "extracting texture pack"); }
stream.Close(&stream);
}
@ -534,7 +530,7 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String*
String_InitArray(path, pathBuffer);
res = Process_GetExePath(&path);
if (res) { Logger_OldWarn(res, "getting .exe path"); return false; }
if (res) { Logger_Warn(res, "getting .exe path"); return false; }
String_InitArray(args, argsBuffer);
String_AppendString(&args, user);
@ -546,7 +542,7 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String*
/* HRESULT when user clicks 'cancel' to 'are you sure you want to run ClassiCube.exe' */
if (res == 0x80004005) return;
#endif
if (res) { Logger_OldWarn(res, "starting game"); return false; }
if (res) { Logger_Warn(res, "starting game"); return false; }
Launcher_ShouldExit = Options_GetBool(OPT_AUTO_CLOSE_LAUNCHER, false);
return true;
@ -614,7 +610,7 @@ static void Launcher_ApplyUpdate(void) {
String_InitArray(exe, exeBuffer);
res = Process_GetExePath(&exe);
if (res) { Logger_OldWarn(res, "getting executable path"); return; }
if (res) { Logger_Warn(res, "getting executable path"); return; }
Utils_UNSAFE_GetFilename(&exe);
String_InitArray(str, strBuffer);
@ -622,12 +618,12 @@ static void Launcher_ApplyUpdate(void) {
/* Can't use WriteLine, want \n as actual newline not code page 437 */
res = Stream_WriteAllTo(&scriptPath, (const uint8_t*)str.buffer, str.length);
if (res) { Logger_OldWarn(res, "saving update script"); return; }
if (res) { Logger_Warn(res, "saving update script"); return; }
res = Platform_MarkExecutable(&scriptPath);
if (res) Logger_OldWarn(res, "making update script executable");
if (res) Logger_Warn(res, "making update script executable");
res = Process_Start(&scriptName, &scriptArgs);
if (res) { Logger_OldWarn(res, "starting update script"); return; }
if (res) { Logger_Warn(res, "starting update script"); return; }
}
#endif

View File

@ -4,23 +4,11 @@
#include "Window.h"
#include "Funcs.h"
#include "Stream.h"
static void Logger_AbortCommon(ReturnCode result, const char* raw_msg, void* ctx);
#include "Errors.h"
#ifdef CC_BUILD_WEB
/* Can't see native CPU state with javascript */
#undef CC_BUILD_POSIX
static void Logger_DumpBacktrace(String* str, void* ctx) { }
static void Logger_DumpRegisters(void* ctx) { }
static void Logger_DumpMisc(void* ctx) { }
void Logger_Hook(void) { }
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
Logger_AbortCommon(result, raw_msg, NULL);
}
#undef CC_BUILD_POSIX /* Can't see native CPU state with javascript */
#endif
#ifdef CC_BUILD_WIN
#define WIN32_LEAN_AND_MEAN
#define NOSERVICE
@ -28,49 +16,198 @@ void Logger_Abort2(ReturnCode result, const char* raw_msg) {
#define NOIME
#include <windows.h>
#include <imagehlp.h>
#endif
/* POSIX can be shared between Linux/BSD/OSX */
#ifdef CC_BUILD_POSIX
#ifndef CC_BUILD_OPENBSD
#include <ucontext.h>
#endif
#include <execinfo.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#endif
struct StackPointers { uintptr_t Instruction, Frame, Stack; };
struct SymbolAndName { IMAGEHLP_SYMBOL Symbol; char Name[256]; };
/*########################################################################################################################*
*----------------------------------------------------------Warning--------------------------------------------------------*
*#########################################################################################################################*/
void Logger_DialogWarn(const String* msg) {
String dst; char dstBuffer[512];
String_InitArray_NT(dst, dstBuffer);
String_AppendString(&dst, msg);
dst.buffer[dst.length] = '\0';
Window_ShowDialog(Logger_DialogTitle, dst.buffer);
}
const char* Logger_DialogTitle = "Error";
Logger_DoWarn Logger_WarnFunc = Logger_DialogWarn;
void Logger_OldWarn(ReturnCode res, const char* place) {
String msg; char msgBuffer[128];
String_InitArray(msg, msgBuffer);
String_Format2(&msg, "Error %h when %c", &res, place);
Logger_WarnFunc(&msg);
}
void Logger_OldWarn2(ReturnCode res, const char* place, const String* path) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Format3(&msg, "Error %h when %c '%s'", &res, place, path);
Logger_WarnFunc(&msg);
}
/* Returns a description for ClassiCube specific error codes */
static const char* Logger_GetCCErrorDesc(ReturnCode res) {
switch (res) {
case ERR_END_OF_STREAM: return "End of stream";
case OGG_ERR_INVALID_SIG: return "Invalid OGG signature";
case OGG_ERR_VERSION: return "Invalid OGG format version";
/*WAV_ERR_STREAM_HDR,
WAV_ERR_STREAM_TYPE,
WAV_ERR_DATA_TYPE,
WAV_ERR_NO_DATA,
/* Vorbis audio decoding errors */ /*
VORBIS_ERR_HEADER,
VORBIS_ERR_WRONG_HEADER,
VORBIS_ERR_FRAMING,
VORBIS_ERR_VERSION,
VORBIS_ERR_BLOCKSIZE,
VORBIS_ERR_CHANS,
VORBIS_ERR_TIME_TYPE,
VORBIS_ERR_FLOOR_TYPE,
VORBIS_ERR_RESIDUE_TYPE,
VORBIS_ERR_MAPPING_TYPE,
VORBIS_ERR_MODE_TYPE,
VORBIS_ERR_CODEBOOK_SYNC,
VORBIS_ERR_CODEBOOK_ENTRY,
VORBIS_ERR_CODEBOOK_LOOKUP,
VORBIS_ERR_MODE_WINDOW,
VORBIS_ERR_MODE_TRANSFORM,
VORBIS_ERR_MAPPING_CHANS,
VORBIS_ERR_MAPPING_RESERVED,
VORBIS_ERR_FRAME_TYPE,
/* PNG image decoding errors */ /*
PNG_ERR_INVALID_SIG,
PNG_ERR_INVALID_HDR_SIZE,
PNG_ERR_TOO_WIDE,
PNG_ERR_TOO_TALL,
PNG_ERR_INVALID_COL_BPP,
PNG_ERR_COMP_METHOD,
PNG_ERR_FILTER,
PNG_ERR_INTERLACED,
PNG_ERR_PAL_ENTRIES,
PNG_ERR_PAL_SIZE,
PNG_ERR_TRANS_COUNT,
PNG_ERR_TRANS_INVALID,
PNG_ERR_INVALID_END_SIZE,
PNG_ERR_NO_DATA,
/* ZIP archive decoding errors */ /*
ZIP_ERR_TOO_MANY_ENTRIES,
ZIP_ERR_SEEK_END_OF_CENTRAL_DIR,
ZIP_ERR_NO_END_OF_CENTRAL_DIR,
ZIP_ERR_SEEK_CENTRAL_DIR,
ZIP_ERR_INVALID_CENTRAL_DIR,
ZIP_ERR_SEEK_LOCAL_DIR,
ZIP_ERR_INVALID_LOCAL_DIR,
ZIP_ERR_FILENAME_LEN,
/* GZIP header decoding errors */ /*
GZIP_ERR_HEADER1,
GZIP_ERR_HEADER2,
GZIP_ERR_METHOD,
GZIP_ERR_FLAGS,
/* ZLIB header decoding errors */ /*
ZLIB_ERR_METHOD,
ZLIB_ERR_WINDOW_SIZE,
ZLIB_ERR_FLAGS,
/* FCM map decoding errors */ /*
FCM_ERR_IDENTIFIER,
FCM_ERR_REVISION,
/* LVL map decoding errors */ /*
LVL_ERR_VERSION,
/* DAT map decoding errors */ /*
DAT_ERR_IDENTIFIER,
DAT_ERR_VERSION,
DAT_ERR_JIDENTIFIER,
DAT_ERR_JVERSION,
DAT_ERR_ROOT_TYPE,
DAT_ERR_JSTRING_LEN,
DAT_ERR_JFIELD_CLASS_NAME,
DAT_ERR_JCLASS_TYPE,
DAT_ERR_JCLASS_FIELDS,
DAT_ERR_JCLASS_ANNOTATION,
DAT_ERR_JOBJECT_TYPE,
DAT_ERR_JARRAY_TYPE,
DAT_ERR_JARRAY_CONTENT,
/* CW map decoding errors */ /*
NBT_ERR_INT32S,
NBT_ERR_UNKNOWN,
CW_ERR_ROOT_TAG,
CW_ERR_STRING_LEN
*/
case PNG_ERR_INVALID_SIG: return "Invalid PNG signature";
case PNG_ERR_INVALID_HDR_SIZE: return "Invalid PNG header size";
case PNG_ERR_TOO_WIDE: return "PNG image too wide";
case PNG_ERR_TOO_TALL: return "PNG image too tall";
case PNG_ERR_INTERLACED: return "Interlaced PNGs unsupported";
}
return NULL;
}
/* Appends more detailed information about an error if possible */
static void Logger_AppendErrorDesc(String* msg, ReturnCode res, Logger_DescribeError describeErr) {
const char* cc_err;
String err; char errBuffer[128];
String_InitArray(err, errBuffer);
cc_err = Logger_GetCCErrorDesc(res);
if (cc_err) {
String_Format1(msg, "\n Error meaning: %c", cc_err);
} else if (describeErr(res, &err)) {
String_Format1(msg, "\n Error meaning: %s", &err);
}
}
void Logger_SysWarn(ReturnCode res, const char* place, Logger_DescribeError describeErr) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Format2(&msg, "Error %h when %c", &res, place);
Logger_AppendErrorDesc(&msg, res, describeErr);
Logger_WarnFunc(&msg);
}
void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logger_DescribeError describeErr) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Format3(&msg, "Error %h when %c '%s'", &res, place, path);
Logger_AppendErrorDesc(&msg, res, describeErr);
Logger_WarnFunc(&msg);
}
void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path) {
Logger_SysWarn2(res, place, path, DynamicLib_DescribeError);
}
void Logger_Warn(ReturnCode res, const char* place) {
Logger_SysWarn(res, place, Platform_DescribeError);
}
void Logger_Warn2(ReturnCode res, const char* place, const String* path) {
Logger_SysWarn2(res, place, path, Platform_DescribeError);
}
/*########################################################################################################################*
*-------------------------------------------------------Info dumping------------------------------------------------------*
*#########################################################################################################################*/
static void Logger_DumpRegisters(void* ctx) {
String str; char strBuffer[512];
CONTEXT* r = (CONTEXT*)ctx;
String_InitArray(str, strBuffer);
String_AppendConst(&str, "-- registers --\r\n");
#if defined _M_IX86
String_Format3(&str, "eax=%x ebx=%x ecx=%x\r\n", &r->Eax, &r->Ebx, &r->Ecx);
String_Format3(&str, "edx=%x esi=%x edi=%x\r\n", &r->Edx, &r->Esi, &r->Edi);
String_Format3(&str, "eip=%x ebp=%x esp=%x\r\n", &r->Eip, &r->Ebp, &r->Esp);
#elif defined _M_X64
String_Format3(&str, "rax=%x rbx=%x rcx=%x\r\n", &r->Rax, &r->Rbx, &r->Rcx);
String_Format3(&str, "rdx=%x rsi=%x rdi=%x\r\n", &r->Rdx, &r->Rsi, &r->Rdi);
String_Format3(&str, "rip=%x rbp=%x rsp=%x\r\n", &r->Rip, &r->Rbp, &r->Rsp);
String_Format3(&str, "r8 =%x r9 =%x r10=%x\r\n", &r->R8, &r->R9, &r->R10);
String_Format3(&str, "r11=%x r12=%x r13=%x\r\n", &r->R11, &r->R12, &r->R13);
String_Format2(&str, "r14=%x r15=%x\r\n" , &r->R14, &r->R15);
#elif defined _M_IA64
String_Format3(&str, "r1 =%x r2 =%x r3 =%x\r\n", &r->IntGp, &r->IntT0, &r->IntT1);
String_Format3(&str, "r4 =%x r5 =%x r6 =%x\r\n", &r->IntS0, &r->IntS1, &r->IntS2);
String_Format3(&str, "r7 =%x r8 =%x r9 =%x\r\n", &r->IntS3, &r->IntV0, &r->IntT2);
String_Format3(&str, "r10=%x r11=%x r12=%x\r\n", &r->IntT3, &r->IntT4, &r->IntSp);
String_Format3(&str, "r13=%x r14=%x r15=%x\r\n", &r->IntTeb, &r->IntT5, &r->IntT6);
String_Format3(&str, "r16=%x r17=%x r18=%x\r\n", &r->IntT7, &r->IntT8, &r->IntT9);
String_Format3(&str, "r19=%x r20=%x r21=%x\r\n", &r->IntT10, &r->IntT11, &r->IntT12);
String_Format3(&str, "r22=%x r23=%x r24=%x\r\n", &r->IntT13, &r->IntT14, &r->IntT15);
String_Format3(&str, "r25=%x r26=%x r27=%x\r\n", &r->IntT16, &r->IntT17, &r->IntT18);
String_Format3(&str, "r28=%x r29=%x r30=%x\r\n", &r->IntT19, &r->IntT20, &r->IntT21);
String_Format3(&str, "r31=%x nat=%x pre=%x\r\n", &r->IntT22, &r->IntNats,&r->Preds);
#else
#error "Unknown machine type"
#endif
Logger_Log(&str);
}
#if defined CC_BUILD_WIN
struct StackPointers { uintptr_t Instruction, Frame, Stack; };
struct SymbolAndName { IMAGEHLP_SYMBOL Symbol; char Name[256]; };
static int Logger_GetFrames(CONTEXT* ctx, struct StackPointers* pointers, int max) {
STACKFRAME frame = { 0 };
@ -170,6 +307,42 @@ static void Logger_DumpBacktrace(String* str, void* ctx) {
Logger_Backtrace(str, ctx);
}
static void Logger_DumpRegisters(void* ctx) {
String str; char strBuffer[512];
CONTEXT* r = (CONTEXT*)ctx;
String_InitArray(str, strBuffer);
String_AppendConst(&str, "-- registers --\r\n");
#if defined _M_IX86
String_Format3(&str, "eax=%x ebx=%x ecx=%x\r\n", &r->Eax, &r->Ebx, &r->Ecx);
String_Format3(&str, "edx=%x esi=%x edi=%x\r\n", &r->Edx, &r->Esi, &r->Edi);
String_Format3(&str, "eip=%x ebp=%x esp=%x\r\n", &r->Eip, &r->Ebp, &r->Esp);
#elif defined _M_X64
String_Format3(&str, "rax=%x rbx=%x rcx=%x\r\n", &r->Rax, &r->Rbx, &r->Rcx);
String_Format3(&str, "rdx=%x rsi=%x rdi=%x\r\n", &r->Rdx, &r->Rsi, &r->Rdi);
String_Format3(&str, "rip=%x rbp=%x rsp=%x\r\n", &r->Rip, &r->Rbp, &r->Rsp);
String_Format3(&str, "r8 =%x r9 =%x r10=%x\r\n", &r->R8, &r->R9, &r->R10);
String_Format3(&str, "r11=%x r12=%x r13=%x\r\n", &r->R11, &r->R12, &r->R13);
String_Format2(&str, "r14=%x r15=%x\r\n" , &r->R14, &r->R15);
#elif defined _M_IA64
String_Format3(&str, "r1 =%x r2 =%x r3 =%x\r\n", &r->IntGp, &r->IntT0, &r->IntT1);
String_Format3(&str, "r4 =%x r5 =%x r6 =%x\r\n", &r->IntS0, &r->IntS1, &r->IntS2);
String_Format3(&str, "r7 =%x r8 =%x r9 =%x\r\n", &r->IntS3, &r->IntV0, &r->IntT2);
String_Format3(&str, "r10=%x r11=%x r12=%x\r\n", &r->IntT3, &r->IntT4, &r->IntSp);
String_Format3(&str, "r13=%x r14=%x r15=%x\r\n", &r->IntTeb, &r->IntT5, &r->IntT6);
String_Format3(&str, "r16=%x r17=%x r18=%x\r\n", &r->IntT7, &r->IntT8, &r->IntT9);
String_Format3(&str, "r19=%x r20=%x r21=%x\r\n", &r->IntT10, &r->IntT11, &r->IntT12);
String_Format3(&str, "r22=%x r23=%x r24=%x\r\n", &r->IntT13, &r->IntT14, &r->IntT15);
String_Format3(&str, "r25=%x r26=%x r27=%x\r\n", &r->IntT16, &r->IntT17, &r->IntT18);
String_Format3(&str, "r28=%x r29=%x r30=%x\r\n", &r->IntT19, &r->IntT20, &r->IntT21);
String_Format3(&str, "r31=%x nat=%x pre=%x\r\n", &r->IntT22, &r->IntNats,&r->Preds);
#else
#error "Unknown machine type"
#endif
Logger_Log(&str);
}
static BOOL CALLBACK Logger_DumpModule(const char* name, ULONG_PTR base, ULONG size, void* ctx) {
String str; char strBuffer[256];
uintptr_t beg, end;
@ -190,94 +363,8 @@ static void Logger_DumpMisc(void* ctx) {
EnumerateLoadedModules(process, Logger_DumpModule, NULL);
}
/*########################################################################################################################*
*------------------------------------------------------Error handling-----------------------------------------------------*
*#########################################################################################################################*/
static LONG WINAPI Logger_UnhandledFilter(struct _EXCEPTION_POINTERS* pInfo) {
String msg; char msgBuffer[STRING_SIZE * 2 + 1];
uint32_t code;
uintptr_t addr;
code = (uint32_t)pInfo->ExceptionRecord->ExceptionCode;
addr = (uintptr_t)pInfo->ExceptionRecord->ExceptionAddress;
String_InitArray_NT(msg, msgBuffer);
String_Format2(&msg, "Unhandled exception 0x%h at 0x%x", &code, &addr);
msg.buffer[msg.length] = '\0';
Logger_AbortCommon(0, msg.buffer, pInfo->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */
}
void Logger_Hook(void) {
SetUnhandledExceptionFilter(Logger_UnhandledFilter);
}
/* Don't want compiler doing anything fancy with registers */
#if _MSC_VER
#pragma optimize ("", off)
#endif
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
CONTEXT ctx;
#ifndef _M_IX86
/* This method is guaranteed to exist on 64 bit windows */
/* It is missing in 32 bit Windows 2000 however */
RtlCaptureContext(&ctx);
#elif _MSC_VER
/* Stack frame layout on x86: */
/* [ebp] is previous frame's EBP */
/* [ebp+4] is previous frame's EIP (return address) */
/* address of [ebp+8] is previous frame's ESP */
__asm {
mov eax, [ebp]
mov [ctx.Ebp], eax
mov eax, [ebp+4]
mov [ctx.Eip], eax
lea eax, [ebp+8]
mov [ctx.Esp], eax
mov [ctx.ContextFlags], CONTEXT_CONTROL
}
#else
int32_t _ebp, _eip, _esp;
/* TODO: I think this is right, not sure.. */
__asm__(
"mov 0(%%ebp), %%eax \n\t"
"mov %%eax, %0 \n\t"
"mov 4(%%ebp), %%eax \n\t"
"mov %%eax, %1 \n\t"
"lea 8(%%ebp), %%eax \n\t"
"mov %%eax, %2"
: "=m" (_ebp), "=m" (_eip), "=m" (_esp)
:
: "eax", "memory");
ctx.Ebp = _ebp;
ctx.Eip = _eip;
ctx.Esp = _esp;
ctx.ContextFlags = CONTEXT_CONTROL;
#endif
Logger_AbortCommon(result, raw_msg, &ctx);
}
#if _MSC_VER
#pragma optimize ("", on)
#endif
#endif
/* POSIX can be shared between Linux/BSD/OSX */
#ifdef CC_BUILD_POSIX
#ifndef CC_BUILD_OPENBSD
#include <ucontext.h>
#endif
#include <execinfo.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
/*########################################################################################################################*
*-------------------------------------------------------Info dumping------------------------------------------------------*
*#########################################################################################################################*/
static void Logger_Backtrace(String* backtrace_, void* ctx) {
String str; char strBuffer[384];
void* addrs[40];
@ -314,58 +401,6 @@ static void Logger_DumpBacktrace(String* str, void* ctx) {
Logger_Backtrace(str, ctx);
}
/*########################################################################################################################*
*------------------------------------------------------Error handling-----------------------------------------------------*
*#########################################################################################################################*/
static void Logger_SignalHandler(int sig, siginfo_t* info, void* ctx) {
String msg; char msgBuffer[STRING_SIZE * 2 + 1];
int type, code;
uintptr_t addr;
/* Uninstall handler to avoid chance of infinite loop */
signal(SIGSEGV, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGABRT, SIG_DFL);
signal(SIGFPE, SIG_DFL);
type = info->si_signo;
code = info->si_code;
addr = (uintptr_t)info->si_addr;
String_InitArray_NT(msg, msgBuffer);
String_Format3(&msg, "Unhandled signal %i (code %i) at 0x%x", &type, &code, &addr);
msg.buffer[msg.length] = '\0';
Logger_AbortCommon(0, msg.buffer, ctx);
}
void Logger_Hook(void) {
struct sigaction sa, old;
sa.sa_sigaction = Logger_SignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sa, &old);
sigaction(SIGBUS, &sa, &old);
sigaction(SIGILL, &sa, &old);
sigaction(SIGABRT, &sa, &old);
sigaction(SIGFPE, &sa, &old);
}
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
ucontext_t ctx;
getcontext(&ctx);
Logger_AbortCommon(result, raw_msg, &ctx);
}
#endif
/*########################################################################################################################*
*-------------------------------------------------------Info dumping------------------------------------------------------*
*#########################################################################################################################*/
#ifdef CC_BUILD_POSIX
static void Logger_DumpRegisters(void* ctx) {
String str; char strBuffer[512];
#ifdef CC_BUILD_OPENBSD
@ -451,8 +486,8 @@ static void Logger_DumpRegisters(void* ctx) {
Logger_Log(&str);
}
#endif
/* OS specific stuff */
#if defined CC_BUILD_LINUX || defined CC_BUILD_SOLARIS
static void Logger_DumpMisc(void* ctx) {
const static String memMap = String_FromConst("-- memory map --\n");
@ -472,76 +507,143 @@ static void Logger_DumpMisc(void* ctx) {
close(fd);
}
#elif defined CC_BUILD_OSX || defined CC_BUILD_FREEBSD || defined CC_BUILD_OPENBSD
#else
static void Logger_DumpMisc(void* ctx) { }
#endif
#endif
#ifdef CC_BUILD_WEB
static void Logger_DumpBacktrace(String* str, void* ctx) { }
static void Logger_DumpRegisters(void* ctx) { }
static void Logger_DumpMisc(void* ctx) { }
#endif
/*########################################################################################################################*
*------------------------------------------------------Error handling-----------------------------------------------------*
*#########################################################################################################################*/
static void Logger_AbortCommon(ReturnCode result, const char* raw_msg, void* ctx);
#ifdef CC_BUILD_WIN
static LONG WINAPI Logger_UnhandledFilter(struct _EXCEPTION_POINTERS* pInfo) {
String msg; char msgBuffer[STRING_SIZE * 2 + 1];
uint32_t code;
uintptr_t addr;
code = (uint32_t)pInfo->ExceptionRecord->ExceptionCode;
addr = (uintptr_t)pInfo->ExceptionRecord->ExceptionAddress;
String_InitArray_NT(msg, msgBuffer);
String_Format2(&msg, "Unhandled exception 0x%h at 0x%x", &code, &addr);
msg.buffer[msg.length] = '\0';
Logger_AbortCommon(0, msg.buffer, pInfo->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */
}
void Logger_Hook(void) { SetUnhandledExceptionFilter(Logger_UnhandledFilter); }
/* Don't want compiler doing anything fancy with registers */
#if _MSC_VER
#pragma optimize ("", off)
#endif
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
CONTEXT ctx;
#ifndef _M_IX86
/* This method is guaranteed to exist on 64 bit windows */
/* It is missing in 32 bit Windows 2000 however */
RtlCaptureContext(&ctx);
#elif _MSC_VER
/* Stack frame layout on x86: */
/* [ebp] is previous frame's EBP */
/* [ebp+4] is previous frame's EIP (return address) */
/* address of [ebp+8] is previous frame's ESP */
__asm {
mov eax, [ebp]
mov [ctx.Ebp], eax
mov eax, [ebp+4]
mov [ctx.Eip], eax
lea eax, [ebp+8]
mov [ctx.Esp], eax
mov [ctx.ContextFlags], CONTEXT_CONTROL
}
#else
int32_t _ebp, _eip, _esp;
/* TODO: I think this is right, not sure.. */
__asm__(
"mov 0(%%ebp), %%eax \n\t"
"mov %%eax, %0 \n\t"
"mov 4(%%ebp), %%eax \n\t"
"mov %%eax, %1 \n\t"
"lea 8(%%ebp), %%eax \n\t"
"mov %%eax, %2"
: "=m" (_ebp), "=m" (_eip), "=m" (_esp)
:
: "eax", "memory");
ctx.Ebp = _ebp;
ctx.Eip = _eip;
ctx.Esp = _esp;
ctx.ContextFlags = CONTEXT_CONTROL;
#endif
Logger_AbortCommon(result, raw_msg, &ctx);
}
#if _MSC_VER
#pragma optimize ("", on)
#endif
#endif
#ifdef CC_BUILD_POSIX
static void Logger_SignalHandler(int sig, siginfo_t* info, void* ctx) {
String msg; char msgBuffer[STRING_SIZE * 2 + 1];
int type, code;
uintptr_t addr;
/* Uninstall handler to avoid chance of infinite loop */
signal(SIGSEGV, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGABRT, SIG_DFL);
signal(SIGFPE, SIG_DFL);
type = info->si_signo;
code = info->si_code;
addr = (uintptr_t)info->si_addr;
String_InitArray_NT(msg, msgBuffer);
String_Format3(&msg, "Unhandled signal %i (code %i) at 0x%x", &type, &code, &addr);
msg.buffer[msg.length] = '\0';
Logger_AbortCommon(0, msg.buffer, ctx);
}
void Logger_Hook(void) {
struct sigaction sa, old;
sa.sa_sigaction = Logger_SignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sa, &old);
sigaction(SIGBUS, &sa, &old);
sigaction(SIGILL, &sa, &old);
sigaction(SIGABRT, &sa, &old);
sigaction(SIGFPE, &sa, &old);
}
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
ucontext_t ctx;
getcontext(&ctx);
Logger_AbortCommon(result, raw_msg, &ctx);
}
#endif
#ifdef CC_BUILD_WEB
void Logger_Hook(void) { }
void Logger_Abort2(ReturnCode result, const char* raw_msg) {
Logger_AbortCommon(result, raw_msg, NULL);
}
#endif
/*########################################################################################################################*
*----------------------------------------------------------Common---------------------------------------------------------*
*#########################################################################################################################*/
void Logger_OldWarn(ReturnCode res, const char* place) {
String msg; char msgBuffer[128];
String_InitArray(msg, msgBuffer);
String_Format2(&msg, "Error %h when %c", &res, place);
Logger_WarnFunc(&msg);
}
void Logger_OldWarn2(ReturnCode res, const char* place, const String* path) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Format3(&msg, "Error %h when %c '%s'", &res, place, path);
Logger_WarnFunc(&msg);
}
void Logger_SysWarn(ReturnCode res, const char* place, Logger_DescribeError describeErr) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Append(&msg, '"');
if (describeErr(res, &msg)) {
String_Format2(&msg, "\" (i) error when %c", &res, place);
} else {
String_DeleteAt(&msg, 0);
String_Format2(&msg, "Error %h when %c", &res, place);
}
Logger_WarnFunc(&msg);
}
void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logger_DescribeError describeErr) {
String msg; char msgBuffer[256];
String_InitArray(msg, msgBuffer);
String_Append(&msg, '"');
if (describeErr(res, &msg)) {
String_Format3(&msg, "\" (%i) error when %c '%s'", &res, place, path);
} else {
String_DeleteAt(&msg, 0);
String_Format3(&msg, "Error %h when %c '%s'", &res, place, path);
}
Logger_WarnFunc(&msg);
}
void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path) {
Logger_SysWarn2(res, place, path, DynamicLib_DescribeError);
}
void Logger_Warn2(ReturnCode res, const char* place, const String* path) {
Logger_SysWarn2(res, place, path, Platform_DescribeError);
}
void Logger_DialogWarn(const String* msg) {
String dst; char dstBuffer[256];
String_InitArray_NT(dst, dstBuffer);
String_AppendString(&dst, msg);
dst.buffer[dst.length] = '\0';
Window_ShowDialog(Logger_DialogTitle, dst.buffer);
}
const char* Logger_DialogTitle = "Error";
Logger_DoWarn Logger_WarnFunc = Logger_DialogWarn;
static FileHandle logFile;
static struct Stream logStream;
static bool logOpen;

View File

@ -27,6 +27,8 @@ void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logg
/* Shortcut for Logger_SysWarn2 with DynamicLib_DescribeError */
void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path);
/* Shortcut for Logger_SysWarn with Platform_DescribeError */
void Logger_Warn(ReturnCode res, const char* place);
/* Shortcut for Logger_SysWarn2 with Platform_DescribeError */
void Logger_Warn2(ReturnCode res, const char* place, const String* path);

View File

@ -2028,7 +2028,7 @@ void Platform_Init(void) {
heap = GetProcessHeap();
res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (res) Logger_OldWarn(res, "starting WSA");
if (res) Logger_Warn(res, "starting WSA");
hasDebugger = IsDebuggerPresent();
/* For when user runs from command prompt */

View File

@ -72,14 +72,14 @@ static void Program_SetCurrentDirectory(void) {
String_InitArray(path, pathBuffer);
res = Process_GetExePath(&path);
if (res) { Logger_OldWarn(res, "getting exe path"); return; }
if (res) { Logger_Warn(res, "getting exe path"); return; }
/* get rid of filename at end of directory */
for (i = path.length - 1; i >= 0; i--, path.length--) {
if (path.buffer[i] == '/' || path.buffer[i] == '\\') break;
}
res = Platform_SetCurrentDirectory(&path);
if (res) { Logger_OldWarn(res, "setting current directory"); return; }
if (res) { Logger_Warn(res, "setting current directory"); return; }
#endif
}

View File

@ -83,13 +83,13 @@ static void Resources_CheckTextures(void) {
if (!File_Exists(&path)) return;
res = Stream_OpenFile(&stream, &path);
if (res) { Logger_OldWarn(res, "checking default.zip"); return; }
if (res) { Logger_Warn(res, "checking default.zip"); return; }
Zip_Init(&state, &stream);
state.SelectEntry = Resources_SelectZipEntry;
res = Zip_Extract(&state);
stream.Close(&stream);
if (res) Logger_OldWarn(res, "inspecting default.zip");
if (res) Logger_Warn(res, "inspecting default.zip");
/* if somehow have say "gui.png", "GUI.png" */
Textures_AllExist = texturesFound >= Array_Elems(Resources_Textures);
@ -558,13 +558,13 @@ static void TexPatcher_MakeDefaultZip(void) {
res = Stream_CreateFile(&s, &path);
if (res) {
Logger_OldWarn(res, "creating default.zip");
Logger_Warn(res, "creating default.zip");
} else {
res = TexPatcher_WriteEntries(&s);
if (res) Logger_OldWarn(res, "making default.zip");
if (res) Logger_Warn(res, "making default.zip");
res = s.Close(&s);
if (res) Logger_OldWarn(res, "closing default.zip");
if (res) Logger_Warn(res, "closing default.zip");
}
for (i = 0; i < Array_Elems(Resources_Files); i++) {
@ -585,9 +585,9 @@ static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx)
ReturnCode res;
res = s->Length(s, &length);
if (res) { Logger_OldWarn(res, "getting .wav length"); return; }
if (res) { Logger_Warn(res, "getting .wav length"); return; }
res = s->Seek(s, 0);
if (res) { Logger_OldWarn(res, "seeking to .wav start"); return; }
if (res) { Logger_Warn(res, "seeking to .wav start"); return; }
Stream_SetU32_BE(&header[0], WAV_FourCC('R','I','F','F'));
Stream_SetU32_LE(&header[4], length - 8);
@ -605,7 +605,7 @@ static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx)
Stream_SetU32_LE(&header[40], length - sizeof(header));
res = Stream_Write(s, header, sizeof(header));
if (res) Logger_OldWarn(res, "fixing .wav header");
if (res) Logger_Warn(res, "fixing .wav header");
}
static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx) {
@ -615,21 +615,21 @@ static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx)
/* ctx is all 0, so reuse it here for header */
res = Stream_Write(s, ctx, 44);
if (res) { Logger_OldWarn(res, "writing .wav header"); return; }
if (res) { Logger_Warn(res, "writing .wav header"); return; }
res = Vorbis_DecodeHeaders(ctx);
if (res) { Logger_OldWarn(res, "decoding .ogg header"); return; }
if (res) { Logger_Warn(res, "decoding .ogg header"); return; }
samples = Mem_Alloc(ctx->BlockSizes[1] * ctx->Channels, 2, ".ogg samples");
for (;;) {
res = Vorbis_DecodeFrame(ctx);
if (res == ERR_END_OF_STREAM) break;
if (res) { Logger_OldWarn(res, "decoding .ogg"); break; }
if (res) { Logger_Warn(res, "decoding .ogg"); break; }
count = Vorbis_OutputFrame(ctx, samples);
/* TODO: Do we need to account for big endian */
res = Stream_Write(s, samples, count * 2);
if (res) { Logger_OldWarn(res, "writing samples"); break; }
if (res) { Logger_Warn(res, "writing samples"); break; }
}
Mem_Free(samples);
}
@ -646,7 +646,7 @@ static void SoundPatcher_Save(struct ResourceSound* sound, struct HttpRequest* r
String_Format1(&path, "audio/%c.wav", sound->Name);
res = Stream_CreateFile(&dst, &path);
if (res) { Logger_OldWarn(res, "creating .wav file"); return; }
if (res) { Logger_Warn(res, "creating .wav file"); return; }
Ogg_MakeStream(&ogg, buffer, &src);
ctx.Source = &ogg;
@ -655,7 +655,7 @@ static void SoundPatcher_Save(struct ResourceSound* sound, struct HttpRequest* r
SoundPatcher_FixupHeader(&dst, &ctx);
res = dst.Close(&dst);
if (res) Logger_OldWarn(res, "closing .wav file");
if (res) Logger_Warn(res, "closing .wav file");
}
static void MusicPatcher_Save(struct ResourceMusic* music, struct HttpRequest* req) {
@ -666,7 +666,7 @@ static void MusicPatcher_Save(struct ResourceMusic* music, struct HttpRequest* r
String_Format1(&path, "audio/%c", music->Name);
res = Stream_WriteAllTo(&path, req->Data, req->Size);
if (res) Logger_OldWarn(res, "saving music file");
if (res) Logger_Warn(res, "saving music file");
}

View File

@ -74,6 +74,17 @@ int String_UNSAFE_Split(STRING_REF const String* str, char c, String* subs, int
return count;
}
CC_API void String_UNSAFE_SplitBy(STRING_REF String* str, char c, String* part) {
int idx = String_IndexOf(str, c);
if (idx == -1) {
*part = *str;
*str = String_Empty;
} else {
*part = String_UNSAFE_Substring(str, 0, idx); idx++;
*str = String_UNSAFE_SubstringAt(str, idx);
}
}
bool String_UNSAFE_Separate(STRING_REF const String* str, char c, String* key, String* value) {
int idx = String_IndexOf(str, c);
if (idx == -1) {

View File

@ -64,6 +64,9 @@ CC_API String String_UNSAFE_Substring(STRING_REF const String* str, int offset,
/* UNSAFE: Splits a string of the form [str1][c][str2][c][str3].. into substrings. */
/* e.g., "abc:id:xyz" becomes "abc","id","xyz" */
CC_API int String_UNSAFE_Split(STRING_REF const String* str, char c, String* subs, int maxSubs);
/* UNSAFE: Splits a string of the form [part][c][rest], returning whether [c] was found or not. */
/* NOTE: This is intended to be repeatedly called until str->length is 0. (unbounded String_UNSAFE_Split) */
CC_API void String_UNSAFE_SplitBy(STRING_REF String* str, char c, String* part);
/* UNSAFE: Splits a string of the form [key][c][value] into two substrings. */
/* e.g., "allowed =true" becomes "allowed" and "true", and excludes the space. */
/* If c is not found, sets key to str and value to String_Empty, returns false. */

View File

@ -1462,16 +1462,12 @@ static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) {
}
static void X11Textbox_Draw(X11Textbox* t, X11Window* w) {
String str = String_FromReadonly(t->Text);
String str = String_FromReadonly(t->Text), line;
int y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */
int end, len;
for (end = 0; end >= 0; y += t->LineHeight) {
end = String_IndexOf(&str, '\n');
len = end == -1 ? str.length : end;
XDrawString(dpy, w->win, w->gc, t->X, y, str.buffer, len);
if (end >= 0) str = String_UNSAFE_SubstringAt(&str, end + 1);
while (str.length) {
String_UNSAFE_SplitBy(&str, '\n', &line);
XDrawString(dpy, w->win, w->gc, t->X, y, line.buffer, line.length);
}
}