backtrace.c revision 706f2543
1706f2543Smrg/* 2706f2543Smrg * Copyright 2008 Red Hat, Inc. 3706f2543Smrg * 4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5706f2543Smrg * copy of this software and associated documentation files (the "Software"), 6706f2543Smrg * to deal in the Software without restriction, including without limitation 7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 9706f2543Smrg * Software is furnished to do so, subject to the following conditions: 10706f2543Smrg * 11706f2543Smrg * The above copyright notice and this permission notice (including the next 12706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the 13706f2543Smrg * Software. 14706f2543Smrg * 15706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21706f2543Smrg * DEALINGS IN THE SOFTWARE. 22706f2543Smrg */ 23706f2543Smrg 24706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 25706f2543Smrg#include <dix-config.h> 26706f2543Smrg#endif 27706f2543Smrg 28706f2543Smrg#include "os.h" 29706f2543Smrg#include "misc.h" 30706f2543Smrg 31706f2543Smrg#ifdef HAVE_BACKTRACE 32706f2543Smrg#ifndef _GNU_SOURCE 33706f2543Smrg#define _GNU_SOURCE 34706f2543Smrg#endif 35706f2543Smrg#include <dlfcn.h> 36706f2543Smrg#include <execinfo.h> 37706f2543Smrg 38706f2543Smrgvoid xorg_backtrace(void) 39706f2543Smrg{ 40706f2543Smrg void *array[64]; 41706f2543Smrg const char *mod; 42706f2543Smrg int size, i; 43706f2543Smrg Dl_info info; 44706f2543Smrg ErrorF("\nBacktrace:\n"); 45706f2543Smrg size = backtrace(array, 64); 46706f2543Smrg for (i = 0; i < size; i++) { 47706f2543Smrg int rc = dladdr(array[i], &info); 48706f2543Smrg if (rc == 0) { 49706f2543Smrg ErrorF("%d: ?? [%p]\n", i, array[i]); 50706f2543Smrg continue; 51706f2543Smrg } 52706f2543Smrg mod = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)"; 53706f2543Smrg if (info.dli_saddr) 54706f2543Smrg ErrorF("%d: %s (%s+0x%lx) [%p]\n", i, mod, 55706f2543Smrg info.dli_sname, (long unsigned int)((char *) array[i] - (char *) info.dli_saddr), array[i]); 56706f2543Smrg else 57706f2543Smrg ErrorF("%d: %s (%p+0x%lx) [%p]\n", i, mod, 58706f2543Smrg info.dli_fbase, (long unsigned int)((char *) array[i] - (char *) info.dli_fbase), array[i]); 59706f2543Smrg } 60706f2543Smrg} 61706f2543Smrg 62706f2543Smrg#else /* not glibc or glibc < 2.1 */ 63706f2543Smrg 64706f2543Smrg# if defined(sun) && defined(__SVR4) 65706f2543Smrg# define HAVE_PSTACK 66706f2543Smrg# endif 67706f2543Smrg 68706f2543Smrg# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ 69706f2543Smrg 70706f2543Smrg# include <ucontext.h> 71706f2543Smrg# include <signal.h> 72706f2543Smrg# include <dlfcn.h> 73706f2543Smrg# include <sys/elf.h> 74706f2543Smrg 75706f2543Smrg#ifdef _LP64 76706f2543Smrg# define ElfSym Elf64_Sym 77706f2543Smrg#else 78706f2543Smrg# define ElfSym Elf32_Sym 79706f2543Smrg#endif 80706f2543Smrg 81706f2543Smrg/* Called for each frame on the stack to print it's contents */ 82706f2543Smrgstatic int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) 83706f2543Smrg{ 84706f2543Smrg Dl_info dlinfo; 85706f2543Smrg ElfSym *dlsym; 86706f2543Smrg char header[32]; 87706f2543Smrg int depth = *((int *) arg); 88706f2543Smrg 89706f2543Smrg if (signo) { 90706f2543Smrg char signame[SIG2STR_MAX]; 91706f2543Smrg 92706f2543Smrg if (sig2str(signo, signame) != 0) { 93706f2543Smrg strcpy(signame, "unknown"); 94706f2543Smrg } 95706f2543Smrg 96706f2543Smrg ErrorF("** Signal %d (%s)\n", signo, signame); 97706f2543Smrg } 98706f2543Smrg 99706f2543Smrg snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc); 100706f2543Smrg *((int *) arg) = depth + 1; 101706f2543Smrg 102706f2543Smrg /* Ask system dynamic loader for info on the address */ 103706f2543Smrg if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) { 104706f2543Smrg unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr; 105706f2543Smrg const char *symname; 106706f2543Smrg 107706f2543Smrg if (offset < dlsym->st_size) { /* inside a function */ 108706f2543Smrg symname = dlinfo.dli_sname; 109706f2543Smrg } else { /* found which file it was in, but not which function */ 110706f2543Smrg symname = "<section start>"; 111706f2543Smrg offset = pc - (uintptr_t)dlinfo.dli_fbase; 112706f2543Smrg } 113706f2543Smrg ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname, 114706f2543Smrg symname, offset); 115706f2543Smrg 116706f2543Smrg } else { 117706f2543Smrg /* Couldn't find symbol info from system dynamic loader, should 118706f2543Smrg * probably poke elfloader here, but haven't written that code yet, 119706f2543Smrg * so we just print the pc. 120706f2543Smrg */ 121706f2543Smrg ErrorF("%s\n", header); 122706f2543Smrg } 123706f2543Smrg 124706f2543Smrg return 0; 125706f2543Smrg} 126706f2543Smrg# endif /* HAVE_WALKCONTEXT */ 127706f2543Smrg 128706f2543Smrg# ifdef HAVE_PSTACK 129706f2543Smrgstatic int xorg_backtrace_pstack(void) { 130706f2543Smrg pid_t kidpid; 131706f2543Smrg int pipefd[2]; 132706f2543Smrg 133706f2543Smrg if (pipe(pipefd) != 0) { 134706f2543Smrg return -1; 135706f2543Smrg } 136706f2543Smrg 137706f2543Smrg kidpid = fork1(); 138706f2543Smrg 139706f2543Smrg if (kidpid == -1) { 140706f2543Smrg /* ERROR */ 141706f2543Smrg return -1; 142706f2543Smrg } else if (kidpid == 0) { 143706f2543Smrg /* CHILD */ 144706f2543Smrg char parent[16]; 145706f2543Smrg 146706f2543Smrg seteuid(0); 147706f2543Smrg close(STDIN_FILENO); 148706f2543Smrg close(STDOUT_FILENO); 149706f2543Smrg dup2(pipefd[1],STDOUT_FILENO); 150706f2543Smrg closefrom(STDERR_FILENO); 151706f2543Smrg 152706f2543Smrg snprintf(parent, sizeof(parent), "%d", getppid()); 153706f2543Smrg execle("/usr/bin/pstack", "pstack", parent, NULL); 154706f2543Smrg exit(1); 155706f2543Smrg } else { 156706f2543Smrg /* PARENT */ 157706f2543Smrg char btline[256]; 158706f2543Smrg int kidstat; 159706f2543Smrg int bytesread; 160706f2543Smrg int done = 0; 161706f2543Smrg 162706f2543Smrg close(pipefd[1]); 163706f2543Smrg 164706f2543Smrg while (!done) { 165706f2543Smrg bytesread = read(pipefd[0], btline, sizeof(btline) - 1); 166706f2543Smrg 167706f2543Smrg if (bytesread > 0) { 168706f2543Smrg btline[bytesread] = 0; 169706f2543Smrg ErrorF("%s", btline); 170706f2543Smrg } 171706f2543Smrg else if ((bytesread < 0) || 172706f2543Smrg ((errno != EINTR) && (errno != EAGAIN))) 173706f2543Smrg done = 1; 174706f2543Smrg } 175706f2543Smrg close(pipefd[0]); 176706f2543Smrg waitpid(kidpid, &kidstat, 0); 177706f2543Smrg if (kidstat != 0) 178706f2543Smrg return -1; 179706f2543Smrg } 180706f2543Smrg return 0; 181706f2543Smrg} 182706f2543Smrg# endif /* HAVE_PSTACK */ 183706f2543Smrg 184706f2543Smrg 185706f2543Smrg# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) 186706f2543Smrg 187706f2543Smrgvoid xorg_backtrace(void) { 188706f2543Smrg 189706f2543Smrg ErrorF("\nBacktrace:\n"); 190706f2543Smrg 191706f2543Smrg# ifdef HAVE_PSTACK 192706f2543Smrg/* First try fork/exec of pstack - otherwise fall back to walkcontext 193706f2543Smrg pstack is preferred since it can print names of non-exported functions */ 194706f2543Smrg 195706f2543Smrg if (xorg_backtrace_pstack() < 0) 196706f2543Smrg# endif 197706f2543Smrg { 198706f2543Smrg# ifdef HAVE_WALKCONTEXT 199706f2543Smrg ucontext_t u; 200706f2543Smrg int depth = 1; 201706f2543Smrg 202706f2543Smrg if (getcontext(&u) == 0) 203706f2543Smrg walkcontext(&u, xorg_backtrace_frame, &depth); 204706f2543Smrg else 205706f2543Smrg# endif 206706f2543Smrg Error("Failed to get backtrace info"); 207706f2543Smrg } 208706f2543Smrg ErrorF("\n"); 209706f2543Smrg} 210706f2543Smrg 211706f2543Smrg# else 212706f2543Smrg 213706f2543Smrg/* Default fallback if we can't find any way to get a backtrace */ 214706f2543Smrgvoid xorg_backtrace(void) { return; } 215706f2543Smrg 216706f2543Smrg# endif 217706f2543Smrg#endif 218