Line data Source code
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 : #include <config.h> 25 : 26 : #if !defined(WIN32) || defined(__MINGW32__) 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 : 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 53 0 : static void spice_backtrace_backtrace(void) 54 : { 55 0 : } 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__ 62 0 : static int spice_backtrace_gstack(void) 63 : { 64 : pid_t kidpid; 65 : int pipefd[2]; 66 : 67 0 : if (pipe(pipefd) != 0) { 68 0 : return -1; 69 : } 70 : 71 0 : kidpid = fork(); 72 : 73 0 : if (kidpid == -1) { 74 : /* ERROR */ 75 0 : return -1; 76 0 : } else if (kidpid == 0) { 77 : /* CHILD */ 78 : char parent[16]; 79 : 80 0 : close(STDIN_FILENO); 81 0 : close(STDOUT_FILENO); 82 0 : dup2(pipefd[1],STDOUT_FILENO); 83 0 : close(STDERR_FILENO); 84 : 85 0 : snprintf(parent, sizeof(parent), "%d", getppid()); 86 0 : execle(GSTACK_PATH, "gstack", parent, NULL, NULL); 87 0 : exit(1); 88 : } else { 89 : /* PARENT */ 90 : char btline[256]; 91 : int kidstat; 92 : int bytesread; 93 0 : int done = 0; 94 : 95 0 : close(pipefd[1]); 96 : 97 0 : while (!done) { 98 0 : bytesread = read(pipefd[0], btline, sizeof(btline) - 1); 99 : 100 0 : if (bytesread > 0) { 101 0 : btline[bytesread] = 0; 102 0 : fprintf(stderr, "%s", btline); 103 : } 104 0 : else if ((bytesread == 0) || 105 0 : ((errno != EINTR) && (errno != EAGAIN))) { 106 0 : done = 1; 107 : } 108 : } 109 0 : close(pipefd[0]); 110 0 : waitpid(kidpid, &kidstat, 0); 111 0 : if (kidstat != 0) 112 0 : return -1; 113 : } 114 0 : return 0; 115 : } 116 : #else 117 : static int spice_backtrace_gstack(void) 118 : { 119 : /* empty failing implementation */ 120 : return -1; 121 : } 122 : #endif 123 : 124 0 : void spice_backtrace(void) 125 : { 126 0 : int ret = -1; 127 : 128 0 : if (!access(GSTACK_PATH, X_OK)) { 129 0 : ret = spice_backtrace_gstack(); 130 : } 131 0 : if (ret != 0) { 132 0 : spice_backtrace_backtrace(); 133 : } 134 0 : } 135 : #endif