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