From: hgn Date: Thu, 3 Jul 2025 14:53:09 +0000 (+0100) Subject: Write crash dumps instead of a scrappy crash screen X-Git-Url: https://skaterift.com/git/?a=commitdiff_plain;h=7c0839412ec69b6ec3ce85ff6961499018742c0d;p=vg.git Write crash dumps instead of a scrappy crash screen --- diff --git a/vg_audio.c b/vg_audio.c index 4fec43b..2734c7d 100644 --- a/vg_audio.c +++ b/vg_audio.c @@ -152,12 +152,7 @@ void audio_clip_load( audio_clip *clip, vg_stack_allocator *stack ) stb_vorbis *decoder = stb_vorbis_open_memory( filedata, fsize, &err, &alloc ); if( !decoder ) - { - vg_fatal_condition(); - vg_info( "Vorbis decode error\n" ); - vg_info( "stb_vorbis_open_memory failed on '%s' (%d)\n", clip->path, err ); - vg_fatal_exit(); - } + vg_fatal_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", clip->path, err ); /* only mono is supported in uncompressed */ u32 length_samples = stb_vorbis_stream_length_in_samples( decoder ), diff --git a/vg_build.h b/vg_build.h index e49f3b7..9069f87 100644 --- a/vg_build.h +++ b/vg_build.h @@ -232,11 +232,7 @@ vg_compiler_run( struct vg_project *project, { if( env->compiler != k_compiler_zigcc ) { - vg_fatal_condition(); - vg_info( - "Cannot specify libc version using the '%s' compiler.\n", - compiler_names[ env->compiler ] ); - vg_fatal_exit(); + vg_fatal_error( "Cannot specify libc version using the '%s' compiler.\n", compiler_names[ env->compiler ] ); } } @@ -244,9 +240,7 @@ vg_compiler_run( struct vg_project *project, { if( env->platform != k_platform_linux ) { - vg_fatal_condition(); - vg_info( "Cannot compile for '%s' using the '%s' compiler;" ); - vg_fatal_exit(); + vg_fatal_error( "Cannot compile for '%s' using the '%s' compiler;" ); } } @@ -511,7 +505,7 @@ vg_make_app( struct vg_project *proj, } else if( env->platform == k_platform_windows ) { - vg_strcat( &conf->link, "-lSDL2main -lSDL2 -lopengl32 \\\n" ); + vg_strcat( &conf->link, "-lSDL2main -lSDL2 -lopengl32 -ldbghelp \\\n" ); vg_strcat( &conf->link, "vg/dep/sdl/SDL2.dll " ); vg_add_blob( proj, "vg/dep/sdl/SDL2.dll ", "" ); vg_strcat( &conf->library, "-L./vg/dep/sdl " ); @@ -519,9 +513,7 @@ vg_make_app( struct vg_project *proj, } else { - vg_fatal_condition(); - vg_info( "No compile procedure set for platform '%s'\n", platform_names[env->platform] ); - vg_fatal_exit(); + vg_fatal_error( "No compile procedure set for platform '%s'\n", platform_names[env->platform] ); } return (struct compile_result){}; diff --git a/vg_engine.c b/vg_engine.c index c7f7634..fee2954 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -392,33 +392,6 @@ static int vg_framefilter( f64 dt ) return 0; } -static void _vg_crashscreen(void) -{ - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glEnable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - glClearColor( 0.15f,0.0f,0.0f,1.0f ); - glClear( GL_COLOR_BUFFER_BIT ); - glViewport( 0,0, vg.window_x, vg.window_y ); - - ui_prerender( &vg_ui.ctx ); - vg_ui_set_screen( vg.window_x, vg.window_y ); - ui_update_mouse( &vg_ui.ctx, (ui_px[2]){ vg.mouse_pos[0], vg.mouse_pos[1] }, vg.mouse_state ); - - vg_console.enabled = 1; - ui_ignore_input_frames( &vg_ui.ctx, 10 ); - vg_gui( &vg_ui.ctx ); - ui_ignore_input_frames( &vg_ui.ctx, 0 ); - ui_capture_mouse( &vg_ui.ctx, 1 ); - vg_console_draw( &vg_ui.ctx ); - - ui_postrender( &vg_ui.ctx, vg.time_frame_delta ); - vg_ui_post_update(); -} - static void _vg_gameloop(void) { vg.time_hp = SDL_GetPerformanceCounter(); @@ -463,21 +436,14 @@ static void _vg_gameloop(void) if( vg.window_should_close ) return; - if( status == k_engine_status_crashed ) + if( status == k_engine_status_running ) { - _vg_crashscreen(); + _vg_gameloop_update(); + _vg_gameloop_render(); } else { - if( status == k_engine_status_running ) - { - _vg_gameloop_update(); - _vg_gameloop_render(); - } - else - { - vg_loader_render(); - } + vg_loader_render(); } if( vg.loader_ring > 0.01f ) @@ -654,10 +620,6 @@ static void _vg_terminate(void) static int _vg_loader_thread( void *pfn ) { SDL_TLSSet( vg.thread_purpose, &_thread_purpose_loader, NULL ); - - if( setjmp( vg.env_loader_exit ) ) - return 0; - while( vg_async_process_next_task( &vg.loader_tasks ) ) {} return 0; } @@ -716,8 +678,43 @@ void vg_init( int argc, const char *argv[], const char *window_name ) vg.window_name = window_name; } +static int cmd_die( int argc, const char *argv[] ) +{ + if( argc ) + { + if( !strcmp( argv[0], "segv" ) ) + { + vg_info( "Trying to make a segfault\n" ); + u32 *nothing = (void *)3; + vg_info( "Uhm %u\n", *nothing ); + } + } + else + vg_fatal_error( "VG FATAL ASSERT ERROR" ); + return 0; +} + +#include +static void sync_signal_handler( int signum ) +{ + if( signum == SIGSEGV ) vg_fatal_exit( "SIGSEGV" ); +#ifndef _WIN32 + if( signum == SIGBUS ) vg_fatal_exit( "SIGBUS" ); +#endif + if( signum == SIGFPE ) vg_fatal_exit( "SIGFPE" ); + if( signum == SIGILL ) vg_fatal_exit( "SIGILL" ); + vg_fatal_exit( "UNKNOWN SIGNAL" ); +} + void vg_run(void) { + signal( SIGSEGV, sync_signal_handler ); +#ifndef _WIN32 + signal( SIGBUS, sync_signal_handler ); +#endif + signal( SIGFPE, sync_signal_handler ); + signal( SIGILL, sync_signal_handler ); + if( !_vg_opt_check() ) exit(0); @@ -730,6 +727,7 @@ void vg_run(void) vg_console_reg_var( "vg_quality", &vg.quality_profile, k_var_dtype_i32, VG_VAR_PERSISTENT ); vg_console_reg_var( "vg_screen_mode", &vg.screen_mode, k_var_dtype_i32, VG_VAR_PERSISTENT ); vg_console_reg_cmd( "vg_settings", cmd_vg_settings_toggle, NULL ); + vg_console_reg_cmd( "die", cmd_die, NULL ); rb_register_cvar(); vg_audio_register(); vg_framebuffer_register(); @@ -758,53 +756,6 @@ void vg_run(void) _vg_terminate(); } -#ifndef _WIN32 - #include -#endif - -void vg_fatal_exit(void) -{ - /* append backtrace */ -#if !defined(_WIN32) - void *array[20]; - char **strings; - int size, i; - - size = backtrace( array, 20 ); - strings = backtrace_symbols( array, size ); - - if( strings != NULL ) - { - vg_error( "\n---------------- gnu backtrace -------------\n" ); - - for( int i=0; i - /* API */ void vg_init( int argc, const char *argv[], const char *window_name ); void vg_run(void); @@ -63,7 +61,6 @@ enum engine_status k_engine_status_none, k_engine_status_load_internal, k_engine_status_running, - k_engine_status_crashed }; struct vg_engine @@ -76,7 +73,6 @@ struct vg_engine SDL_TLSID thread_purpose; vg_async_queue main_tasks, loader_tasks; - jmp_buf env_loader_exit; /* for deep fatal error handling */ SDL_atomic_t engine_status; vg_signal_id sig_engine, sig_client; diff --git a/vg_framebuffer.c b/vg_framebuffer.c index 7f838dc..616d6a0 100644 --- a/vg_framebuffer.c +++ b/vg_framebuffer.c @@ -73,10 +73,7 @@ void vg_framebuffer_bind_texture( vg_framebuffer *fb, int attachment, int slot ) if( (at->purpose != k_framebuffer_attachment_type_texture) && (at->purpose != k_framebuffer_attachment_type_texture_depth) ) { - vg_fatal_condition(); - vg_info( "illegal operation: bind non-texture framebuffer" - " attachment to texture slot" ); - vg_fatal_exit(); + vg_fatal_error( "illegal operation: bind non-texture framebuffer attachment to texture slot" ); } glActiveTexture( GL_TEXTURE0 + slot ); @@ -235,11 +232,7 @@ vg_framebuffer *vg_framebuffer_allocate( vg_stack_allocator *stack, u32 attachme if( _vg_framebuffer.count != VG_ARRAY_LEN(_vg_framebuffer.list) ) _vg_framebuffer.list[ _vg_framebuffer.count ++ ] = fb; else - { - vg_fatal_condition(); - vg_info( "Framebuffer list is full, and tried to allocate another.\n"); - vg_fatal_exit(); - } + vg_fatal_error( "Framebuffer list is full, and tried to allocate another.\n"); } fb->attachments = vg_stack_allocate( stack, sizeof(vg_framebuffer_attachment) * attachment_count, 8, NULL ); @@ -313,7 +306,6 @@ static void async_framebuffer_create( void *_fb ) } else { - vg_fatal_condition(); if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ) vg_info( " status: Incomplete attachment" ); else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT ) @@ -323,7 +315,7 @@ static void async_framebuffer_create( void *_fb ) else vg_info( " status: Generic Error" ); vg_info( "}\n" ); - vg_fatal_exit(); + vg_fatal_error( "Bad framebuffer\n" ); } } diff --git a/vg_io.c b/vg_io.c index e759572..cebcd7e 100644 --- a/vg_io.c +++ b/vg_io.c @@ -221,16 +221,12 @@ void *vg_file_read( vg_stack_allocator *stack, const char *path, u32 *size, bool if( ferror( f ) ) { fclose(f); - vg_fatal_condition(); - vg_info( "Read error\n" ); - vg_fatal_exit(); + vg_fatal_error( "Read error\n" ); } else { fclose(f); - vg_fatal_condition(); - vg_info( "Unknown error condition\n" ); - vg_fatal_exit(); + vg_fatal_error( "Unknown error condition\n" ); } } } diff --git a/vg_loader.c b/vg_loader.c index 676a613..d13a865 100644 --- a/vg_loader.c +++ b/vg_loader.c @@ -189,9 +189,5 @@ void _vg_loader_step( void( *fn_load )(void), void( *fn_free )(void), const char VG_ASSERT( vg_loader.step_count < VG_ARRAY_LEN(vg_loader.step_buffer) ); vg_loader.step_buffer[ vg_loader.step_count ++ ] = step; } - - enum engine_status status = SDL_AtomicGet( &vg.engine_status ); - if( status == k_engine_status_crashed ) - longjmp( vg.env_loader_exit, 1 ); } diff --git a/vg_log.c b/vg_log.c index 914bb94..9b674d4 100644 --- a/vg_log.c +++ b/vg_log.c @@ -151,7 +151,120 @@ void vg_logx( FILE *file, va_end( args ); } -void vg_fatal_condition(void) +/* FIXME: THIS NEEDS ITS OWN FILE, VG_PLATFORM.C */ + +void vg_fatal_error( const char *fmt, ... ) +{ + va_list args; + va_start( args, fmt ); + _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args ); + va_end( args ); + vg_fatal_exit( "VG Assertion (check STDOUT, or the text logfile if enabled)" ); +} + +#ifdef _WIN32 + #include + #include +#else + #include +#endif +#include +#include +#include + +void vg_fatal_exit( const char *comment ) { - vg_error( "--------- Fatal condition entered --------- \n" ); + char buf[ 1024 ]; + vg_str log_path; + vg_strnull( &log_path, buf, sizeof(buf) ); + vg_strcat( &log_path, "crash-" ); + vg_strcatu64( &log_path, time(NULL), 10 ); + vg_strcat( &log_path, "-trace.txt" ); + + if( !vg_strgood( &log_path ) ) + exit(-2); + + int fd = open( buf, O_CREAT | O_WRONLY, 0666 ); + if( fd == -1 ) + exit(-3); + + vg_str line; + vg_strnull( &line, buf, sizeof(buf) ); + +#ifdef _WIN32 + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + CONTEXT context; + STACKFRAME64 stack; + DWORD machine_type; + + RtlCaptureContext( &context ); + ZeroMemory( &stack, sizeof(STACKFRAME64) ); + machine_type = IMAGE_FILE_MACHINE_AMD64; + stack.AddrPC.Offset = context.Rip; + stack.AddrFrame.Offset = context.Rsp; + stack.AddrStack.Offset = context.Rsp; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrStack.Mode = AddrModeFlat; + + SymInitialize( process, NULL, TRUE ); + SymSetOptions( SYMOPT_LOAD_LINES | SYMOPT_UNDNAME ); + + vg_strcat( &line, "OS: Windows\n" + "Comment: " ); + vg_strcat( &line, comment ); + vg_strcat( &line, "\nStack trace\n" + "-----------------------------------\n" ); + vg_str_flushfd( &line, fd ); + + DWORD frame_number = 0; + while( StackWalk64( machine_type, process, thread, &stack, &context, NULL, SymFunctionTableAccess64, + SymGetModuleBase64, NULL)) + { + if( stack.AddrPC.Offset == 0 ) + break; + + DWORD64 symbol_addr = stack.AddrPC.Offset; + DWORD64 displacement = 0; + char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {0}; + SYMBOL_INFO *symbol = (SYMBOL_INFO *)symbol_buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + + char function_name[ MAX_SYM_NAME ] = "Unknown"; + if( SymFromAddr( process, symbol_addr, &displacement, symbol ) ) + { + strncpy( function_name, symbol->Name, MAX_SYM_NAME - 1 ); + function_name[ MAX_SYM_NAME - 1 ] = '\0'; + } + + vg_strcat( &line, " [" ); + vg_strcatu64( &line, frame_number, 10 ); + vg_strcat( &line, "] " ); + vg_strcatu64( &line, symbol_addr, 16 ); + vg_strcat( &line, " " ); + vg_strcat( &line, function_name ); + vg_strcat( &line, "\n" ); + vg_str_flushfd( &line, fd ); + + frame_number ++; + } + + SymCleanup(process); + +#else + vg_strcat( &line, "OS: GNU/Linux\n" + "Comment: " ); + vg_strcat( &line, comment ); + vg_strcat( &line, "\nStack trace\n" + "-----------------------------------\n" ); + vg_str_flushfd( &line, fd ); + void *functions[20]; + int count = backtrace( functions, 20 ); + backtrace_symbols_fd( functions, count, fd ); +#endif + + close( fd ); + exit(-1); } diff --git a/vg_platform.h b/vg_platform.h index e9bf50b..07ab3aa 100644 --- a/vg_platform.h +++ b/vg_platform.h @@ -29,8 +29,7 @@ typedef v4f m4x4f[4]; typedef v3f boxf[2]; /* anything compiled against VG shall implement vg_fatal_exit() somewhere. */ -void vg_fatal_condition(void); -void vg_fatal_exit(void); +void vg_fatal_exit( const char *comment ); void vg_fatal_error( const char *fmt, ... ); #define VG_ASSERT( ITEM, ... ) \ diff --git a/vg_shader.c b/vg_shader.c index c536cee..7888b9d 100644 --- a/vg_shader.c +++ b/vg_shader.c @@ -31,10 +31,8 @@ static GLuint vg_compile_opengl_subshader( GLint type, const char *src, bool cri if( shader == 0 ) { - vg_fatal_condition(); - vg_info( "glCreateShader returned 0.\n" ); vg_opengl_log_errors(); - vg_fatal_exit(); + vg_fatal_error( "glCreateShader returned 0.\n" ); return 0; } @@ -50,8 +48,6 @@ static GLuint vg_compile_opengl_subshader( GLint type, const char *src, bool cri } else { - if( critical ) vg_fatal_condition(); - GLchar info[1024]; GLsizei len; glGetShaderInfoLog( shader, sizeof(info), &len, info ); @@ -61,9 +57,8 @@ static GLuint vg_compile_opengl_subshader( GLint type, const char *src, bool cri if( type == GL_VERTEX_SHADER ) type_str = "GL_VERTEX_SHADER"; else if( type == GL_FRAGMENT_SHADER ) type_str = "GL_FRAGMENT_SHADER"; - vg_info( "%s subshader compile error:\n\n%s\n", type_str, info ); - - if( critical ) vg_fatal_exit(); + if( critical ) + vg_fatal_error( "%s subshader compile error:\n\n%s\n", type_str, info ); return 0; } } @@ -82,13 +77,10 @@ static int vg_link_opengl_program( GLuint program, bool critical ) if( success ) return 1; else { - if( critical ) vg_fatal_condition(); - char info[ 512 ]; glGetProgramInfoLog( program, sizeof(info), NULL, info ); - vg_info( "Shader program link error:\n\n%s\n", info ); - - if( critical ) vg_fatal_exit(); + if( critical ) + vg_fatal_error( "Shader program link error:\n\n%s\n", info ); return 0; } } diff --git a/vg_string.c b/vg_string.c index ba6d213..627d4fc 100644 --- a/vg_string.c +++ b/vg_string.c @@ -3,6 +3,7 @@ #include #include #include +#include i32 vg_str_storage( vg_str *str ) { @@ -97,13 +98,15 @@ static bool _vg_strcatch( vg_str *str, char c ) void vg_strcat( vg_str *str, const char *append ) { - if( !append || (str->i == -1) ) return; + if( !append || (str->i == -1) ) + return; i32 i = 0; append:; char c = append[ i ++ ]; - if( !_vg_strcatch( str, c ) ) return; + if( !_vg_strcatch( str, c ) ) + return; if( c == '\0' ) { @@ -123,8 +126,8 @@ void vg_strcatch( vg_str *str, char c ) /* * FIXME: Negative numbers */ -void vg_strcati32( vg_str *str, i32 value ){ vg_strcatu64( str, (u64)value ); } -void vg_strcatu64( vg_str *str, u64 value ) +void vg_strcati32( vg_str *str, i32 value ){ vg_strcatu64( str, (u64)value, 10 ); } +void vg_strcatu64( vg_str *str, u64 value, u64 base ) { if( value ) { @@ -132,8 +135,12 @@ void vg_strcatu64( vg_str *str, u64 value ) int i=0; while( value && (i<31) ) { - temp[ i ++ ] = '0' + (value % 10); - value /= 10; + u32 digit = (u32)(value % base); + if( digit <= 9 ) + temp[ i ++ ] = '0' + digit; + else + temp[ i ++ ] = 'A' + (digit-10); + value /= base; } char reverse[32]; @@ -172,6 +179,13 @@ int vg_strgood( vg_str *str ) else return 1; } +bool vg_str_flushfd( vg_str *str, int fd ) +{ + bool good = write( fd, str->buffer, str->i ) == str->i; + str->i = 0; + return good; +} + /* * Returns pointer to last instance of character */ @@ -208,12 +222,7 @@ u32 vg_strncpy( const char *src, char *dst, u32 len, enum strncpy_behaviour beha return i; } else if( behaviour == k_strncpy_overflow_fatal ) - { - vg_fatal_condition(); - vg_info( "vg_strncpy to buffer with maximum length '%u' exceeded" - " the end of the buffer.\n", len ); - vg_fatal_exit(); - } + vg_fatal_error( "vg_strncpy to buffer with maximum length '%u' exceeded the end of the buffer.\n", len ); } } diff --git a/vg_string.h b/vg_string.h index 145cc79..0e4710d 100644 --- a/vg_string.h +++ b/vg_string.h @@ -40,7 +40,7 @@ void vg_strcatf( vg_str *str, const char *fmt, ... ); * Append character to vg_str */ void vg_strcatch( vg_str *str, char c ); -void vg_strcatu64( vg_str *str, u64 value ); +void vg_strcatu64( vg_str *str, u64 value, u64 base ); void vg_strcati32( vg_str *str, i32 value ); void vg_strcati32r( vg_str *str, i32 value, i32 n, char alt ); /* @@ -68,3 +68,4 @@ int vg_strdjb2_eq( const char *s1, u32 h1, const char *s2, u32 h2 ); vg_strdjb2_eq( CS1, vg_strdjb2(CS1), S2, H2 ) bool vg_str_eq( const char *s1, const char *s2 ); +bool vg_str_flushfd( vg_str *str, int fd ); diff --git a/vg_tool.c b/vg_tool.c index c9ac3a8..c78f55d 100644 --- a/vg_tool.c +++ b/vg_tool.c @@ -8,41 +8,3 @@ #include "vg_mem.c" #include "vg_mem_queue.c" #include "vg_io.c" -#if !defined(_WIN32) - #include -#endif - -void vg_fatal_exit(void) -{ -#if !defined(_WIN32) - void *array[20]; - char **strings; - int size, i; - - size = backtrace( array, 20 ); - strings = backtrace_symbols( array, size ); - - if( strings != NULL ) - { - vg_error( "\n---------------- gnu backtrace -------------\n" ); - - for( int i=0; ihue ); } else - { - vg_fatal_condition(); - vg_info( "Invalid UI shader (%d)\n", shader ); - vg_fatal_exit(); - } + vg_fatal_error( "Invalid UI shader (%d)\n", shader ); glDrawElements( GL_TRIANGLES, batch->indice_count, GL_UNSIGNED_SHORT, (void *)((size_t)batch->indice_offset) );