From 7a8a31c041b52d87c1522e684cb301b07ea6ad9b Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 10 Oct 2008 15:53:48 -0400 Subject: [PATCH] Move xorg_backtrace() up to the OS level so we can call it from DIX. --- hw/xfree86/common/xf86Events.c | 173 ---------------------------------- include/os.h | 2 + os/Makefile.am | 1 + os/backtrace.c | 202 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 173 deletions(-) create mode 100644 os/backtrace.c diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 6ca0ae7..a2c206e 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -358,179 +358,6 @@ xf86SigIllHandler = sigillhandler; } -#ifdef HAVE_BACKTRACE -#include - -static __inline__ void xorg_backtrace(void) -{ - void *array[32]; /* deeper nesting than this means something's wrong */ - size_t size, i; - char **strings; - ErrorF("\nBacktrace:\n"); - size = backtrace(array, 32); - strings = backtrace_symbols(array, size); - for (i = 0; i < size; i++) - ErrorF("%d: %s\n", i, strings[i]); - free(strings); -} - -#else /* not glibc or glibc < 2.1 */ - -# if defined(sun) && defined(__SVR4) -# define HAVE_PSTACK -# endif - -# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ - -# include -# include -# include -# include - -#ifdef _LP64 -# define ElfSym Elf64_Sym -#else -# define ElfSym Elf32_Sym -#endif - -/* Called for each frame on the stack to print it's contents */ -static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) -{ - Dl_info dlinfo; - ElfSym *dlsym; - char header[32]; - int depth = *((int *) arg); - - if (signo) { - char signame[SIG2STR_MAX]; - - if (sig2str(signo, signame) != 0) { - strcpy(signame, "unknown"); - } - - ErrorF("** Signal %d (%s)\n", signo, signame); - } - - snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc); - *((int *) arg) = depth + 1; - - /* Ask system dynamic loader for info on the address */ - if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) { - unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr; - const char *symname; - - if (offset < dlsym->st_size) { /* inside a function */ - symname = dlinfo.dli_sname; - } else { /* found which file it was in, but not which function */ - symname = "
"; - offset = pc - (uintptr_t)dlinfo.dli_fbase; - } - ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname, - symname, offset); - - } else { - /* Couldn't find symbol info from system dynamic loader, should - * probably poke elfloader here, but haven't written that code yet, - * so we just print the pc. - */ - ErrorF("%s\n", header); - } - - return 0; -} -# endif /* HAVE_WALKCONTEXT */ - -# ifdef HAVE_PSTACK -static int xorg_backtrace_pstack(void) { - pid_t kidpid; - int pipefd[2]; - - if (pipe(pipefd) != 0) { - return -1; - } - - kidpid = fork1(); - - if (kidpid == -1) { - /* ERROR */ - return -1; - } else if (kidpid == 0) { - /* CHILD */ - char parent[16]; - - seteuid(0); - close(STDIN_FILENO); - close(STDOUT_FILENO); - dup2(pipefd[1],STDOUT_FILENO); - closefrom(STDERR_FILENO); - - snprintf(parent, sizeof(parent), "%d", getppid()); - execle("/usr/bin/pstack", "pstack", parent, NULL); - exit(1); - } else { - /* PARENT */ - char btline[256]; - int kidstat; - int bytesread; - int done = 0; - - close(pipefd[1]); - - while (!done) { - bytesread = read(pipefd[0], btline, sizeof(btline) - 1); - - if (bytesread > 0) { - btline[bytesread] = 0; - ErrorF("%s", btline); - } - else if ((bytesread < 0) || - ((errno != EINTR) && (errno != EAGAIN))) - done = 1; - } - close(pipefd[0]); - waitpid(kidpid, &kidstat, 0); - if (kidstat != 0) - return -1; - } - return 0; -} -# endif /* HAVE_PSTACK */ - - -# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) - -static __inline__ void xorg_backtrace(void) { - - ErrorF("\nBacktrace:\n"); - -# ifdef HAVE_PSTACK -/* First try fork/exec of pstack - otherwise fall back to walkcontext - pstack is preferred since it can print names of non-exported functions */ - - if (xorg_backtrace_pstack() < 0) -# endif - { -# ifdef HAVE_WALKCONTEXT - ucontext_t u; - int depth = 1; - - if (getcontext(&u) == 0) - walkcontext(&u, xorg_backtrace_frame, &depth); - else -# endif - Error("Failed to get backtrace info"); - } - ErrorF("\n"); -} - -# else - -/* Default fallback if we can't find any way to get a backtrace */ -static __inline__ void xorg_backtrace(void) { return; } - -# endif -#endif - /* * xf86SigHandler -- * Catch unexpected signals and exit or continue cleanly. diff --git a/include/os.h b/include/os.h --- a/include/os.h +++ b/include/os.h @@ -517,4 +517,6 @@ extern void Error(char *str); extern void LogPrintMarkers(void); +extern void xorg_backtrace(void); + #endif /* OS_H */ diff --git a/os/Makefile.am b/os/Makefile.am --- a/os/Makefile.am +++ b/os/Makefile.am @@ -11,6 +11,7 @@ WaitFor.c \ access.c \ auth.c \ + backtrace.c \ connection.c \ io.c \ mitauth.c \ diff --git a/os/backtrace.c b/os/backtrace.c new file mode 100644 --- /dev/null +++ b/os/backtrace.c @@ -0,0 +1,201 @@ +/* + * Copyright 2008 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software") + * to deal in the software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * them Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "os.h" +#include "misc.h" + +#ifdef HAVE_BACKTRACE +#include + +void xorg_backtrace(void) +{ + void *array[32]; /* deeper nesting than this means something's wrong */ + size_t size, i; + char **strings; + ErrorF("\nBacktrace:\n"); + size = backtrace(array, 32); + strings = backtrace_symbols(array, size); + for (i = 0; i < size; i++) + ErrorF("%d: %s\n", i, strings[i]); + free(strings); +} + +#else /* not glibc or glibc < 2.1 */ + +# if defined(sun) && defined(__SVR4) +# define HAVE_PSTACK +# endif + +# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ + +# include +# include +# include +# include + +#ifdef _LP64 +# define ElfSym Elf64_Sym +#else +# define ElfSym Elf32_Sym +#endif + +/* Called for each frame on the stack to print it's contents */ +static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) +{ + Dl_info dlinfo; + ElfSym *dlsym; + char header[32]; + int depth = *((int *) arg); + + if (signo) { + char signame[SIG2STR_MAX]; + + if (sig2str(signo, signame) != 0) { + strcpy(signame, "unknown"); + } + + ErrorF("** Signal %d (%s)\n", signo, signame); + } + + snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc); + *((int *) arg) = depth + 1; + + /* Ask system dynamic loader for info on the address */ + if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) { + unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr; + const char *symname; + + if (offset < dlsym->st_size) { /* inside a function */ + symname = dlinfo.dli_sname; + } else { /* found which file it was in, but not which function */ + symname = "
"; + offset = pc - (uintptr_t)dlinfo.dli_fbase; + } + ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname, + symname, offset); + + } else { + /* Couldn't find symbol info from system dynamic loader, should + * probably poke elfloader here, but haven't written that code yet, + * so we just print the pc. + */ + ErrorF("%s\n", header); + } + + return 0; +} +# endif /* HAVE_WALKCONTEXT */ + +# ifdef HAVE_PSTACK +static int xorg_backtrace_pstack(void) { + pid_t kidpid; + int pipefd[2]; + + if (pipe(pipefd) != 0) { + return -1; + } + + kidpid = fork1(); + + if (kidpid == -1) { + /* ERROR */ + return -1; + } else if (kidpid == 0) { + /* CHILD */ + char parent[16]; + + seteuid(0); + close(STDIN_FILENO); + close(STDOUT_FILENO); + dup2(pipefd[1],STDOUT_FILENO); + closefrom(STDERR_FILENO); + + snprintf(parent, sizeof(parent), "%d", getppid()); + execle("/usr/bin/pstack", "pstack", parent, NULL); + exit(1); + } else { + /* PARENT */ + char btline[256]; + int kidstat; + int bytesread; + int done = 0; + + close(pipefd[1]); + + while (!done) { + bytesread = read(pipefd[0], btline, sizeof(btline) - 1); + + if (bytesread > 0) { + btline[bytesread] = 0; + ErrorF("%s", btline); + } + else if ((bytesread < 0) || + ((errno != EINTR) && (errno != EAGAIN))) + done = 1; + } + close(pipefd[0]); + waitpid(kidpid, &kidstat, 0); + if (kidstat != 0) + return -1; + } + return 0; +} +# endif /* HAVE_PSTACK */ + + +# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) + +void xorg_backtrace(void) { + + ErrorF("\nBacktrace:\n"); + +# ifdef HAVE_PSTACK +/* First try fork/exec of pstack - otherwise fall back to walkcontext + pstack is preferred since it can print names of non-exported functions */ + + if (xorg_backtrace_pstack() < 0) +# endif + { +# ifdef HAVE_WALKCONTEXT + ucontext_t u; + int depth = 1; + + if (getcontext(&u) == 0) + walkcontext(&u, xorg_backtrace_frame, &depth); + else +# endif + Error("Failed to get backtrace info"); + } + ErrorF("\n"); +} + +# else + +/* Default fallback if we can't find any way to get a backtrace */ +void xorg_backtrace(void) { return; } + +# endif +#endif -- 1.6.0.1