Write crash dumps instead of a scrappy crash screen
authorhgn <hgodden00@gmail.com>
Thu, 3 Jul 2025 14:53:09 +0000 (15:53 +0100)
committerhgn <hgodden00@gmail.com>
Thu, 3 Jul 2025 14:53:09 +0000 (15:53 +0100)
14 files changed:
vg_audio.c
vg_build.h
vg_engine.c
vg_engine.h
vg_framebuffer.c
vg_io.c
vg_loader.c
vg_log.c
vg_platform.h
vg_shader.c
vg_string.c
vg_string.h
vg_tool.c
vg_ui/imgui_impl_opengl.c

index 4fec43bb8d125caf2b230ab0042dbc11c9daede9..2734c7de5a59609d174d0cc7abb3e43bc5431f62 100644 (file)
@@ -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 ),
index e49f3b71c1f2349445757597428a2f4bec54889d..9069f872a4d679a7ed2ca27dad5d994f00e7b9f0 100644 (file)
@@ -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){};
index c7f76346399be151f3bd9d01af570b0889745f12..fee2954cfd932cfa0fba7e4b35cf2a1e6377e5f5 100644 (file)
@@ -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 <signal.h>
+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 <execinfo.h>
-#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<size; i++ )
-         vg_low( "%s\n", strings[i] );
-   }
-
-   free( strings );
-#endif
-
-   SDL_AtomicSet( &vg.engine_status, k_engine_status_crashed );
-
-   if( vg_thread_purpose() == _thread_purpose_loader )
-      longjmp( vg.env_loader_exit, 1 );
-   else
-   {
-      /* TODO: This should also be able to go to the crash screen? */
-      _vg_terminate();
-   }
-}
-
-void vg_fatal_error( const char *fmt, ... )
-{
-   vg_fatal_condition();
-   va_list args;
-   va_start( args, fmt );
-   _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
-   va_end( args );
-   vg_fatal_exit();
-}
-
 /* 
  * settings menu
  * ---------------------------------------------------------------------------
@@ -1113,7 +1064,7 @@ static void vg_settings_audio_apply(void)
       if( vg_settings.audio_devices.new_value == -1 ){ }
       else if( vg_settings.audio_devices.new_value == -2 )
       {
-         vg_fatal_exit();
+         vg_fatal_error( "" );
       }
       else 
       {
index b44f4415e580052ba21254e0fe343675d43435be..bbdc93a7ed155a0246e2167f4962a80479e01ca0 100644 (file)
@@ -31,8 +31,6 @@
 #include "vg_async2.h"
 #include "vg_tower.h"
 
-#include <setjmp.h>
-
 /* 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;
index 7f838dc3b68dab39c88fb6982f43151ecec7b547..616d6a096fcbc64d6ad05644cfa9318970230478 100644 (file)
@@ -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 e75957271502e8bda487b293930234fd4f785773..cebcd7eeb3ef3836d4fe51dd6fd1467b684229ae 100644 (file)
--- 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" );
                }
             }
          }
index 676a613f8535a4c819b48a781d76be93cea3b88b..d13a86574c88aa8456454740c3e140007d8f69cc 100644 (file)
@@ -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 );
 }
 
index 914bb94637e2261ceb41388640ea2764a5f92f1a..9b674d44bf3377d0d8e4a0b88a11be3bbc716506 100644 (file)
--- 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 <windows.h>
+ #include <dbghelp.h>
+#else
+ #include <execinfo.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+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);
 }
index e9bf50b4e9e606845f0c87085eee59c7aab59863..07ab3aad1133b16ba1c24195d306bf5a73f9093b 100644 (file)
@@ -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, ... ) \
index c536cee33555dd367c2ec547737b7e0c0ae789e4..7888b9ddd864bb4b2925c8f09d8dece81a0b8a38 100644 (file)
@@ -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;
        }
 }
index ba6d21310bac0dc7b1a0208b7794d9d9d6a3bd66..627d4fc9884688cf94673866249d42d57842d632 100644 (file)
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <unistd.h>
 
 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 );
       }
    }
 
index 145cc797c5f0eec1c071891ee38686469b774a0f..0e4710d7d6aa86d65f6fb6395c5534ecbc7189c9 100644 (file)
@@ -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 );
index c9ac3a8607a53dbbe905c421c3961ebf4d6da1ca..c78f55d8c28794a3963b98c5e973f3c335acedeb 100644 (file)
--- 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 <execinfo.h>
-#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; i<size; i++ )
-         vg_low( "%s\n", strings[i] );
-   }
-
-   free( strings );
-#endif
-   exit(1);
-}
-
-void vg_fatal_error( const char *fmt, ... )
-{
-   vg_fatal_condition();
-
-   va_list args;
-   va_start( args, fmt );
-   _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args );
-   va_end( args );
-
-   vg_fatal_exit();
-}
index 8f7b1bb2ac58e230e3234467dead60d0ba1bb5d9..19fd7694853a3de69ab8338db8fd9c6bc3f7217a 100644 (file)
@@ -350,11 +350,7 @@ void ui_impl_render_batch( ui_context *ctx, ui_batch *batch,
       glUniform1f( glGetUniformLocation(_shader_ui_hsv.id,"uHue"), inf->hue );
    }
    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) );