Fix compilation on windows for new backtrace stuff
[yaz-moved-to-github.git] / src / backtrace.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file
8  * \brief get information for abnormal terminated, crashes, etc
9  */
10
11
12 #if HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <signal.h>
17 #include <string.h>
18 #include <errno.h>
19 #if HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #include <stdlib.h>
23 #if HAVE_SYS_WAIT_H
24 #include <sys/wait.h>
25 #endif
26 #include <yaz/log.h>
27 #include <yaz/snprintf.h>
28 #include <yaz/backtrace.h>
29 #include <yaz/nmem.h>
30
31 #if HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34
35 #if HAVE_EXECINFO_H
36 #include <execinfo.h>
37 #endif
38
39 #define BACKTRACE_SZ 100
40
41 static char static_progname[256];
42 #if HAVE_EXECINFO_H
43
44 static void yaz_invoke_backtrace(char *buf, int buf_sz)
45 {
46     FILE *file = yaz_log_file();
47     int fd = fileno(file);
48     pid_t pid;
49     int fds[2];
50     void *backtrace_info[BACKTRACE_SZ];
51     int sz = BACKTRACE_SZ;
52
53     write(fd, buf, strlen(buf));
54     sz = backtrace(backtrace_info, sz);
55     backtrace_symbols_fd(backtrace_info, sz, fd);
56
57     pipe(fds);
58     pid = fork();
59     if (pid == (pid_t) (-1))
60     {   /* error */
61         const char *cp = "backtrace: fork failure";
62         write(fd, cp, strlen(cp));
63     }
64     else if (pid == 0)
65     {   /* child */
66         char *arg[20];
67         int arg_no = 0;
68         char pidstr[40];
69         const char *cp = "backtrace: could not exec gdb";
70
71         close(fds[1]);
72         close(0);
73         dup(fds[0]);
74         if (fd != 1)
75         {
76             close(1);
77             dup(fd);
78         }
79         if (fd != 2)
80         {
81             close(2);
82             dup(fd);
83         }
84         arg[arg_no++] = "/usr/bin/gdb";
85         arg[arg_no++] = "-n";
86         arg[arg_no++] = "-batch";
87         arg[arg_no++] = "-ex";
88         arg[arg_no++] = "info threads";
89         arg[arg_no++] = "-ex";
90         arg[arg_no++] = "thread apply all bt";
91         arg[arg_no++] = static_progname;
92         sprintf(pidstr, NMEM_INT_PRINTF, (nmem_int_t) getppid());
93         arg[arg_no++] = pidstr;
94         arg[arg_no] = 0;
95         execv(arg[0], arg);
96         write(2, cp, strlen(cp)); /* exec failure if we make it this far */
97         _exit(1);
98     }
99     else
100     {  /* parent */
101         int sec = 0;
102
103         close(fds[0]);
104         write(fds[1], "quit\n", 5);
105         while (1)
106         {
107             int status;
108             pid_t s = waitpid(pid, &status, WNOHANG);
109             if (s != 0)
110                 break;
111             if (sec == 9)
112                 kill(pid, SIGTERM);
113             if (sec == 10)
114                 kill(pid, SIGKILL);
115             if (sec == 11)
116                 break;
117             if (sec > 3)
118                 write(fds[1], "quit\n", 5);
119             sleep(1);
120             sec++;
121         }
122         close(fds[1]);
123     }
124 }
125
126 static void yaz_panic_sig_handler(int sig)
127 {
128     char buf[512];
129
130     signal(SIGABRT, SIG_DFL);
131     strcpy(buf, "\nYAZ panic received ");
132     switch (sig)
133     {
134     case SIGSEGV:
135         strcat(buf, "SIGSEGV");
136         break;
137     case SIGABRT:
138         strcat(buf, "SIGABRT");
139         break;
140     case SIGFPE:
141         strcat(buf, "SIGFPE");
142         break;
143     case SIGBUS:
144         strcat(buf, "SIGBUS");
145         break;
146     default:
147         yaz_snprintf(buf + strlen(buf), sizeof buf, "signo=%d", sig);
148         break;
149     }
150     yaz_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
151                  " PID=" NMEM_INT_PRINTF "\n", (nmem_int_t) getpid());
152     yaz_invoke_backtrace(buf, sizeof buf);
153     abort();
154 }
155 #endif
156
157 void yaz_enable_panic_backtrace(const char *progname)
158 {
159     strncpy(static_progname, progname, sizeof(static_progname) - 1);
160     static_progname[sizeof(static_progname) - 1] = '\0';
161 #if HAVE_EXECINFO_H
162     signal(SIGABRT, yaz_panic_sig_handler);
163     signal(SIGSEGV, yaz_panic_sig_handler);
164     signal(SIGFPE, yaz_panic_sig_handler);
165     signal(SIGBUS, yaz_panic_sig_handler);
166 #endif
167 }
168
169 /*
170  * Local variables:
171  * c-basic-offset: 4
172  * c-file-style: "Stroustrup"
173  * indent-tabs-mode: nil
174  * End:
175  * vim: shiftwidth=4 tabstop=8 expandtab
176  */
177