#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>
#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);
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)
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))
}
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++;
}
}
}
#endif
}
-void yaz_panic_sig_handler(int sig)
+static void yaz_panic_sig_handler(int sig)
{
char buf[4096];
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);
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);