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 ),
{
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 ] );
}
}
{
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;" );
}
}
}
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 " );
}
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){};
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();
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 )
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;
}
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);
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();
_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
* ---------------------------------------------------------------------------
if( vg_settings.audio_devices.new_value == -1 ){ }
else if( vg_settings.audio_devices.new_value == -2 )
{
- vg_fatal_exit();
+ vg_fatal_error( "" );
}
else
{
#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);
k_engine_status_none,
k_engine_status_load_internal,
k_engine_status_running,
- k_engine_status_crashed
};
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;
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 );
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 );
}
else
{
- vg_fatal_condition();
if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
vg_info( " status: Incomplete attachment" );
else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
else
vg_info( " status: Generic Error" );
vg_info( "}\n" );
- vg_fatal_exit();
+ vg_fatal_error( "Bad framebuffer\n" );
}
}
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" );
}
}
}
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 );
}
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);
}
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, ... ) \
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;
}
}
else
{
- if( critical ) vg_fatal_condition();
-
GLchar info[1024];
GLsizei len;
glGetShaderInfoLog( shader, sizeof(info), &len, info );
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;
}
}
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;
}
}
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
+#include <unistd.h>
i32 vg_str_storage( vg_str *str )
{
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' )
{
/*
* 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 )
{
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];
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
*/
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 );
}
}
* 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 );
/*
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 );
#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();
-}
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) );