medfall

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit b74e61a913527babd16001995bc56da3a79393a2
parent 52ea14acaae25db2bbacfe22084f665a3b003677
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Wed Oct 12 18:54:56 +0300

Drop into GDB when the game crashes on Linux

Diffstat:
autogdb.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.cc | 9+++++++++
2 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/autogdb.h b/autogdb.h @@ -0,0 +1,72 @@ +#ifndef _AUTOGDB_H_ +#define _AUTOGDB_H_ + +#include <sys/ptrace.h> +#include <sys/wait.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <err.h> + +static void prompt_to_run_gdb( int signal ) { + const char * signal_names[ NSIG ]; + signal_names[ SIGABRT ] = "SIGABRT"; + signal_names[ SIGILL ] = "SIGILL"; + signal_names[ SIGSEGV ] = "SIGSEGV"; + + char crashed_pid[ 16 ]; + snprintf( crashed_pid, sizeof( crashed_pid ), "%d", getpid() ); + printf( "PID %s received %s. Debug? (y/n)\n", crashed_pid, signal_names[ signal ] ); + + char c; + read( STDIN_FILENO, &c, 1 ); + if( c != 'y' ) exit( 1 ); + + // fork off and run gdb + pid_t child_pid = fork(); + if( child_pid == -1 ) err( 1, "fork" ); + + if( child_pid == 0 ) { + execlp( "gdbx", "gdbx", "--", "-p", crashed_pid, ( char * ) 0 ); + execlp( "gdb", "gdb", "-p", crashed_pid, ( char * ) 0 ); + err( 1, "execlp" ); + } + + // pause the parent while we wait for gdb to attach + pause(); +} + +static void install_debug_signal_handlers() { + signal( SIGABRT, prompt_to_run_gdb ); + signal( SIGILL, prompt_to_run_gdb ); + signal( SIGSEGV, prompt_to_run_gdb ); +} + +static bool being_debugged() { + pid_t parent_pid = getpid(); + pid_t child_pid = fork(); + if( child_pid == -1 ) err( 1, "fork" ); + + if( child_pid == 0 ) { + // if we can't ptrace the parent then gdb is already there + if( ptrace( PTRACE_ATTACH, parent_pid, NULL, NULL ) != 0 ) exit( 1 ); + + // ptrace automatically stops the process so wait for SIGSTOP and send PTRACE_CONT + waitpid( parent_pid, NULL, 0 ); + ptrace( PTRACE_CONT, NULL, NULL ); + + // detach + ptrace( PTRACE_DETACH, parent_pid, NULL, NULL ); + exit( 0 ); + } + + int status; + waitpid( child_pid, &status, 0 ); + if( !WIFEXITED( status ) ) err( 1, "WIFEXITED" ); + + return WEXITSTATUS( status ) == 1; +} + +#endif // _AUTOGDB_H_ diff --git a/main.cc b/main.cc @@ -14,6 +14,7 @@ #include "intrinsics.h" #include "gl.h" #include "keys.h" +#include "platform.h" #include "platform_library.h" struct Game { @@ -72,7 +73,15 @@ static bool should_reload_game( const char * const path, const time_t lib_write_ return file_last_write_time( path ) > lib_write_time; } +#if PLATFORM_LINUX +#include "autogdb.h" +#endif + int main( int argc, char ** argv ) { +#if PLATFORM_LINUX + install_debug_signal_handlers(); +#endif + const char * game_library_path = argc == 2 ? argv[ 1 ] : "./hm.so"; size_t persistent_size = megabytes( 64 );