backtrace.c revision 706f2543
1/* 2 * Copyright 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#ifdef HAVE_DIX_CONFIG_H 25#include <dix-config.h> 26#endif 27 28#include "os.h" 29#include "misc.h" 30 31#ifdef HAVE_BACKTRACE 32#ifndef _GNU_SOURCE 33#define _GNU_SOURCE 34#endif 35#include <dlfcn.h> 36#include <execinfo.h> 37 38void xorg_backtrace(void) 39{ 40 void *array[64]; 41 const char *mod; 42 int size, i; 43 Dl_info info; 44 ErrorF("\nBacktrace:\n"); 45 size = backtrace(array, 64); 46 for (i = 0; i < size; i++) { 47 int rc = dladdr(array[i], &info); 48 if (rc == 0) { 49 ErrorF("%d: ?? [%p]\n", i, array[i]); 50 continue; 51 } 52 mod = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)"; 53 if (info.dli_saddr) 54 ErrorF("%d: %s (%s+0x%lx) [%p]\n", i, mod, 55 info.dli_sname, (long unsigned int)((char *) array[i] - (char *) info.dli_saddr), array[i]); 56 else 57 ErrorF("%d: %s (%p+0x%lx) [%p]\n", i, mod, 58 info.dli_fbase, (long unsigned int)((char *) array[i] - (char *) info.dli_fbase), array[i]); 59 } 60} 61 62#else /* not glibc or glibc < 2.1 */ 63 64# if defined(sun) && defined(__SVR4) 65# define HAVE_PSTACK 66# endif 67 68# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ 69 70# include <ucontext.h> 71# include <signal.h> 72# include <dlfcn.h> 73# include <sys/elf.h> 74 75#ifdef _LP64 76# define ElfSym Elf64_Sym 77#else 78# define ElfSym Elf32_Sym 79#endif 80 81/* Called for each frame on the stack to print it's contents */ 82static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) 83{ 84 Dl_info dlinfo; 85 ElfSym *dlsym; 86 char header[32]; 87 int depth = *((int *) arg); 88 89 if (signo) { 90 char signame[SIG2STR_MAX]; 91 92 if (sig2str(signo, signame) != 0) { 93 strcpy(signame, "unknown"); 94 } 95 96 ErrorF("** Signal %d (%s)\n", signo, signame); 97 } 98 99 snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc); 100 *((int *) arg) = depth + 1; 101 102 /* Ask system dynamic loader for info on the address */ 103 if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) { 104 unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr; 105 const char *symname; 106 107 if (offset < dlsym->st_size) { /* inside a function */ 108 symname = dlinfo.dli_sname; 109 } else { /* found which file it was in, but not which function */ 110 symname = "<section start>"; 111 offset = pc - (uintptr_t)dlinfo.dli_fbase; 112 } 113 ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname, 114 symname, offset); 115 116 } else { 117 /* Couldn't find symbol info from system dynamic loader, should 118 * probably poke elfloader here, but haven't written that code yet, 119 * so we just print the pc. 120 */ 121 ErrorF("%s\n", header); 122 } 123 124 return 0; 125} 126# endif /* HAVE_WALKCONTEXT */ 127 128# ifdef HAVE_PSTACK 129static int xorg_backtrace_pstack(void) { 130 pid_t kidpid; 131 int pipefd[2]; 132 133 if (pipe(pipefd) != 0) { 134 return -1; 135 } 136 137 kidpid = fork1(); 138 139 if (kidpid == -1) { 140 /* ERROR */ 141 return -1; 142 } else if (kidpid == 0) { 143 /* CHILD */ 144 char parent[16]; 145 146 seteuid(0); 147 close(STDIN_FILENO); 148 close(STDOUT_FILENO); 149 dup2(pipefd[1],STDOUT_FILENO); 150 closefrom(STDERR_FILENO); 151 152 snprintf(parent, sizeof(parent), "%d", getppid()); 153 execle("/usr/bin/pstack", "pstack", parent, NULL); 154 exit(1); 155 } else { 156 /* PARENT */ 157 char btline[256]; 158 int kidstat; 159 int bytesread; 160 int done = 0; 161 162 close(pipefd[1]); 163 164 while (!done) { 165 bytesread = read(pipefd[0], btline, sizeof(btline) - 1); 166 167 if (bytesread > 0) { 168 btline[bytesread] = 0; 169 ErrorF("%s", btline); 170 } 171 else if ((bytesread < 0) || 172 ((errno != EINTR) && (errno != EAGAIN))) 173 done = 1; 174 } 175 close(pipefd[0]); 176 waitpid(kidpid, &kidstat, 0); 177 if (kidstat != 0) 178 return -1; 179 } 180 return 0; 181} 182# endif /* HAVE_PSTACK */ 183 184 185# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) 186 187void xorg_backtrace(void) { 188 189 ErrorF("\nBacktrace:\n"); 190 191# ifdef HAVE_PSTACK 192/* First try fork/exec of pstack - otherwise fall back to walkcontext 193 pstack is preferred since it can print names of non-exported functions */ 194 195 if (xorg_backtrace_pstack() < 0) 196# endif 197 { 198# ifdef HAVE_WALKCONTEXT 199 ucontext_t u; 200 int depth = 1; 201 202 if (getcontext(&u) == 0) 203 walkcontext(&u, xorg_backtrace_frame, &depth); 204 else 205# endif 206 Error("Failed to get backtrace info"); 207 } 208 ErrorF("\n"); 209} 210 211# else 212 213/* Default fallback if we can't find any way to get a backtrace */ 214void xorg_backtrace(void) { return; } 215 216# endif 217#endif 218