Backtrace using gdb instead
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 19 Nov 2014 14:02:04 +0000 (15:02 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 19 Nov 2014 14:02:04 +0000 (15:02 +0100)
include/yaz/backtrace.h
src/backtrace.c
ztest/ztest.c

index ca34bf4..8469c3f 100644 (file)
 
 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
 
index 840d2c5..b8f4183 100644 (file)
@@ -26,6 +26,7 @@
 #include <yaz/log.h>
 #include <yaz/snprintf.h>
 #include <yaz/backtrace.h>
+#include <yaz/nmem.h>
 
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -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);
index 5f8dd3d..cc7736d 100644 (file)
@@ -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);
 }