#include <stdio.h>
#include <limits.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
static const char *progname;
static const char *dir_prefix = "/tmp/";
static const char *gdbserver = "gdbserver";
static int port = 2345;
static void call_gdb(int sig, int start_gdb_in_window)
{
FILE *f;
char tmp_gdbrc[PATH_MAX];
sprintf(tmp_gdbrc, "/tmp/gdbrc.%d",getpid());
if ((f = fopen(tmp_gdbrc,"w")) == NULL) {
perror(tmp_gdbrc);
abort();
}
fprintf(f,"set tcp auto-retry on\nset tcp connect-timeout 3600\n"
"file %s\ntarget remote :%d\n", progname, port);
fprintf(f,start_gdb_in_window ? "backtrace\n" :
"backtrace full\ninfo source\nquit\n");
fclose(f);
char cmd[PATH_MAX];
if (start_gdb_in_window) {
sprintf(cmd, "gnome-terminal --title 'GDB - %s backtrace' -x gdb -x %s",
progname, tmp_gdbrc);
fprintf(stderr, "signal_handler: got signal %d, starting debugger window (pid %d)\n",sig, getpid());
} else {
sprintf(cmd, "gdb --batch -x %s > %sbacktrace.%d &",
tmp_gdbrc, dir_prefix, getpid());
fprintf(stderr, "signal_handler: got signal %d, generating backtrace in %sbacktrace.%d\n",sig, dir_prefix, getpid());
}
int rc = system(cmd);
if (rc == -1) {
perror(cmd);
} else if (rc) {
fprintf(stderr,"system(%s) returned %d", cmd, rc);
}
sprintf(cmd,"%s --once --attach :%d %d &", gdbserver, port, getpid());
rc = system(cmd);
if (rc == -1) {
perror(cmd);
} else if (rc) {
fprintf(stderr,"system(%s) returned %d", cmd, rc);
}
sleep(3);
unlink(tmp_gdbrc);
fprintf(stderr, "signal_handler: sig %d - done\n", sig);
if (sig == SIGSEGV)
exit(0);
}
void gdb_backtrace(int sig)
{
call_gdb(sig, 0);
}
void gdb_in_window(int sig)
{
call_gdb(sig, 1);
}
void setup_signal_handlers()
{
struct sigaction backtrace_action, gdb_action;
char path[PATH_MAX];
char exe[PATH_MAX];
sprintf(path,"/proc/%d/exe", getpid());
if (readlink(path, exe, sizeof(exe)) < 0) {
fprintf(stderr, "signal_handler: cant readlink(%s): %s\n",path,strerror(errno));
return;
}
progname = strdup(exe);
sigemptyset( &gdb_action.sa_mask );
gdb_action.sa_handler = gdb_in_window;
gdb_action.sa_flags = 0;
sigemptyset( &backtrace_action.sa_mask );
backtrace_action.sa_handler = gdb_backtrace;
backtrace_action.sa_flags = 0;
sigaction( SIGSEGV, &gdb_action, (struct sigaction *) NULL );
sigaction( SIGUSR1, &gdb_action, (struct sigaction *) NULL );
sigaction( SIGUSR2, &backtrace_action, (struct sigaction *) NULL );
}
#ifdef TEST
int main(int argc, const char *argv[]) {
signal_handlers();
sleep(10);
void *foo = 0;
memset(foo,0,47);
return 0;
}
#endif