From 6ebca563449a7fa93f7699f798803b26f8636215 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Wed, 19 Nov 2014 15:02:04 +0100 Subject: [PATCH] Backtrace using gdb instead --- include/yaz/backtrace.h | 5 ++- src/backtrace.c | 95 +++++++++++++++++++++++++++++------------------ ztest/ztest.c | 2 +- 3 files changed, 63 insertions(+), 39 deletions(-) diff --git a/include/yaz/backtrace.h b/include/yaz/backtrace.h index ca34bf4..8469c3f 100644 --- a/include/yaz/backtrace.h +++ b/include/yaz/backtrace.h @@ -37,10 +37,11 @@ YAZ_BEGIN_CDECL -/** \brief enables backtrace when bad signal is received (never returns) +/** \brief enables backtrace when SIGSEGV/SIGABRT/.. signal is received + \param progname name of executable that we run */ -YAZ_EXPORT void yaz_enable_panic_backtrace(void); +YAZ_EXPORT void yaz_enable_panic_backtrace(const char *progname); YAZ_END_CDECL diff --git a/src/backtrace.c b/src/backtrace.c index 840d2c5..b8f4183 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -26,6 +26,7 @@ #include #include #include +#include #if HAVE_SYS_TYPES_H #include @@ -37,7 +38,9 @@ #define BACKTRACE_SZ 100 -void yaz_invoke_backtrace(char *buf, int buf_sz) +static char static_progname[256]; + +static void yaz_invoke_backtrace(char *buf, int buf_sz) { FILE *file = yaz_log_file(); int fd = fileno(file); @@ -50,12 +53,12 @@ void yaz_invoke_backtrace(char *buf, int buf_sz) sz = backtrace(backtrace_info, sz); backtrace_str = backtrace_symbols(backtrace_info, sz); - yaz_snprintf(buf + strlen(buf), left, "Backtrace for PID=%ld\n", - (long) getpid()); + yaz_snprintf(buf + strlen(buf), left, "backtrace: PID=" NMEM_INT_PRINTF + "\n", (nmem_int_t) getpid()); if (backtrace_str) { int i; - for (i = 1; i < sz; i++) + for (i = 0; i < sz; i++) { left = buf_sz - strlen(buf); if (left < 80) @@ -69,8 +72,8 @@ void yaz_invoke_backtrace(char *buf, int buf_sz) if (backtrace_str) { pid_t pid; - const char *cp = "-----------\n"; - write(fd, cp, strlen(cp)); + int fds[2]; + pipe(fds); pid = fork(); if (pid == (pid_t) (-1)) @@ -80,47 +83,65 @@ void yaz_invoke_backtrace(char *buf, int buf_sz) } else if (pid == 0) { /* child */ - int i; - char *arg[BACKTRACE_SZ + 4]; + char *arg[10]; int arg_no = 0; - char *cp; + char pidstr[40]; + const char *cp = "backtrace: could not exec gdb"; + close(fds[1]); close(0); - dup(fd); - close(1); - dup(fd); - if (fd != 2) + dup(fds[0]); + if (fd != 1) { - close(2); + close(1); dup(fd); } - arg[arg_no++] = "addr2line"; - arg[arg_no++] = "-paf"; - arg[arg_no++] = "-e"; - arg[arg_no++] = backtrace_str[0]; - cp = strchr(backtrace_str[0], '('); - if (cp) - *cp = '\0'; - - for (i = 1; i < sz; i++) + if (fd != 2) { - cp = strchr(backtrace_str[i], '['); - if (cp) - arg[arg_no++] = cp + 1; + close(2); + dup(fd); } + arg[arg_no++] = "/usr/bin/gdb"; + arg[arg_no++] = "-n"; + arg[arg_no++] = static_progname; + sprintf(pidstr, NMEM_INT_PRINTF, (nmem_int_t) getppid()); + arg[arg_no++] = pidstr; arg[arg_no] = 0; - execv("/usr/bin/addr2line", arg); + execv(arg[0], arg); + write(2, cp, strlen(cp)); /* exec failure if we make it this far */ _exit(1); } else { /* parent */ - int status; - waitpid(pid, &status, 0); - if (status) + + char *dbg_commands = "info threads\nthread apply all bt\n"; + int off = 0; + int sec = 0; + + close(fds[0]); + while (off < strlen(dbg_commands)) { - char msg[100]; - sprintf(msg, "backtrace: exit status=%d\n", status); - write(fd, msg, strlen(msg)); + ssize_t r = write(fds[1], dbg_commands + off, + strlen(dbg_commands) - off); + if (r == (ssize_t) (-1)) + break; + off += r; + } + close(fds[1]); + while (1) + { + int status; + pid_t s = waitpid(pid, &status, WNOHANG); + if (s != 0) + break; + if (sec == 2) + kill(pid, SIGTERM); + if (sec == 3) + kill(pid, SIGKILL); + if (sec == 4) + break; + sleep(1); + sec++; } } } @@ -130,7 +151,7 @@ void yaz_invoke_backtrace(char *buf, int buf_sz) #endif } -void yaz_panic_sig_handler(int sig) +static void yaz_panic_sig_handler(int sig) { char buf[4096]; @@ -148,7 +169,7 @@ void yaz_panic_sig_handler(int sig) strcat(buf, "SIGFPE\n"); break; case SIGBUS: - strcat(buf, "SIGFPE\n"); + strcat(buf, "SIGBUS\n"); break; default: yaz_snprintf(buf + strlen(buf), sizeof buf, "signo=%d\n", sig); @@ -158,8 +179,10 @@ void yaz_panic_sig_handler(int sig) abort(); } -void yaz_enable_panic_backtrace(void) +void yaz_enable_panic_backtrace(const char *progname) { + strncpy(static_progname, progname, sizeof(static_progname) - 1); + static_progname[sizeof(static_progname) - 1] = '\0'; #if HAVE_EXECINFO_H signal(SIGABRT, yaz_panic_sig_handler); signal(SIGSEGV, yaz_panic_sig_handler); diff --git a/ztest/ztest.c b/ztest/ztest.c index 5f8dd3d..cc7736d 100644 --- a/ztest/ztest.c +++ b/ztest/ztest.c @@ -1159,7 +1159,7 @@ void bend_close(void *handle) int main(int argc, char **argv) { - yaz_enable_panic_backtrace(); + yaz_enable_panic_backtrace(argv[0]); return statserv_main(argc, argv, bend_init, bend_close); } -- 1.7.10.4