1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3    Copyright (C) 2011 Red Hat, Inc.
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 /*
20  * Taken from xserver os/backtrace.c:
21  * Copyright (C) 2008 Red Hat, Inc.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include "backtrace.h"
29 
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #ifndef __MINGW32__
36 #include <sys/wait.h>
37 #endif
38 
39 #define GSTACK_PATH "/usr/bin/gstack"
40 
41 #if HAVE_EXECINFO_H
42 #include <execinfo.h>
43 
spice_backtrace_backtrace(void)44 static void spice_backtrace_backtrace(void)
45 {
46     void *array[100];
47     int size;
48 
49     size = backtrace(array, sizeof(array)/sizeof(array[0]));
50     backtrace_symbols_fd(array, size, STDERR_FILENO);
51 }
52 #else
spice_backtrace_backtrace(void)53 static void spice_backtrace_backtrace(void)
54 {
55 }
56 #endif
57 
58 /* XXX perhaps gstack can be available in windows but pipe/waitpid isn't,
59  * so until it is ported properly just compile it out, we lose the
60  * backtrace only. */
61 #ifndef __MINGW32__
spice_backtrace_gstack(void)62 static int spice_backtrace_gstack(void)
63 {
64     pid_t kidpid;
65     int pipefd[2];
66 
67     if (pipe(pipefd) != 0) {
68         return -1;
69     }
70 
71     kidpid = fork();
72 
73     if (kidpid == -1) {
74         /* ERROR */
75         return -1;
76     } else if (kidpid == 0) {
77         /* CHILD */
78         char parent[16];
79 
80         close(STDIN_FILENO);
81         close(STDOUT_FILENO);
82         dup2(pipefd[1],STDOUT_FILENO);
83         close(STDERR_FILENO);
84 
85         snprintf(parent, sizeof(parent), "%d", getppid());
86         execle(GSTACK_PATH, "gstack", parent, NULL, NULL);
87         exit(1);
88     } else {
89         /* PARENT */
90         char btline[256];
91         int kidstat;
92         int bytesread;
93         int done = 0;
94 
95         close(pipefd[1]);
96 
97         while (!done) {
98             bytesread = read(pipefd[0], btline, sizeof(btline) - 1);
99 
100             if (bytesread > 0) {
101                 btline[bytesread] = 0;
102                 fprintf(stderr, "%s", btline);
103             }
104             else if ((bytesread == 0) ||
105                      ((errno != EINTR) && (errno != EAGAIN))) {
106                 done = 1;
107             }
108         }
109         close(pipefd[0]);
110         waitpid(kidpid, &kidstat, 0);
111         if (kidstat != 0)
112             return -1;
113     }
114     return 0;
115 }
116 #else
spice_backtrace_gstack(void)117 static int spice_backtrace_gstack(void)
118 {
119     /* empty failing implementation */
120     return -1;
121 }
122 #endif
123 
spice_backtrace(void)124 void spice_backtrace(void)
125 {
126     int ret = -1;
127 
128     if (!access(GSTACK_PATH, X_OK)) {
129         ret = spice_backtrace_gstack();
130     }
131     if (ret != 0) {
132         spice_backtrace_backtrace();
133     }
134 }
135