"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.5/os/backtrace.c" (30 May 2019, 8475 Bytes) of package /linux/misc/xorg-server-1.20.5.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "backtrace.c" see the Fossies "Dox" file reference documentation.

    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 #include <errno.h>
   31 #include <string.h>
   32 
   33 #ifdef HAVE_LIBUNWIND
   34 
   35 #define UNW_LOCAL_ONLY
   36 #include <libunwind.h>
   37 
   38 #ifndef _GNU_SOURCE
   39 #define _GNU_SOURCE
   40 #endif
   41 #include <dlfcn.h>
   42 
   43 void
   44 xorg_backtrace(void)
   45 {
   46     unw_cursor_t cursor;
   47     unw_context_t context;
   48     unw_word_t off;
   49     unw_proc_info_t pip;
   50     int ret, i = 0;
   51     char procname[256];
   52     const char *filename;
   53     Dl_info dlinfo;
   54 
   55     pip.unwind_info = NULL;
   56     ret = unw_getcontext(&context);
   57     if (ret) {
   58         ErrorFSigSafe("unw_getcontext failed: %s [%d]\n", unw_strerror(ret),
   59                 ret);
   60         return;
   61     }
   62 
   63     ret = unw_init_local(&cursor, &context);
   64     if (ret) {
   65         ErrorFSigSafe("unw_init_local failed: %s [%d]\n", unw_strerror(ret),
   66                 ret);
   67         return;
   68     }
   69 
   70     ErrorFSigSafe("\n");
   71     ErrorFSigSafe("Backtrace:\n");
   72     ret = unw_step(&cursor);
   73     while (ret > 0) {
   74         ret = unw_get_proc_info(&cursor, &pip);
   75         if (ret) {
   76             ErrorFSigSafe("unw_get_proc_info failed: %s [%d]\n",
   77                     unw_strerror(ret), ret);
   78             break;
   79         }
   80 
   81         off = 0;
   82         ret = unw_get_proc_name(&cursor, procname, 256, &off);
   83         if (ret && ret != -UNW_ENOMEM) {
   84             if (ret != -UNW_EUNSPEC)
   85                 ErrorFSigSafe("unw_get_proc_name failed: %s [%d]\n",
   86                         unw_strerror(ret), ret);
   87             procname[0] = '?';
   88             procname[1] = 0;
   89         }
   90 
   91         if (dladdr((void *)(uintptr_t)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
   92                 *dlinfo.dli_fname)
   93             filename = dlinfo.dli_fname;
   94         else
   95             filename = "?";
   96 
   97         ErrorFSigSafe("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname,
   98             ret == -UNW_ENOMEM ? "..." : "", (int)off,
   99             (void *)(uintptr_t)(pip.start_ip + off));
  100 
  101         ret = unw_step(&cursor);
  102         if (ret < 0)
  103             ErrorFSigSafe("unw_step failed: %s [%d]\n", unw_strerror(ret), ret);
  104     }
  105     ErrorFSigSafe("\n");
  106 }
  107 #else /* HAVE_LIBUNWIND */
  108 #ifdef HAVE_BACKTRACE
  109 #ifndef _GNU_SOURCE
  110 #define _GNU_SOURCE
  111 #endif
  112 #include <dlfcn.h>
  113 #include <execinfo.h>
  114 
  115 void
  116 xorg_backtrace(void)
  117 {
  118     const int BT_SIZE = 64;
  119     void *array[BT_SIZE];
  120     const char *mod;
  121     int size, i;
  122     Dl_info info;
  123 
  124     ErrorFSigSafe("\n");
  125     ErrorFSigSafe("Backtrace:\n");
  126     size = backtrace(array, BT_SIZE);
  127     for (i = 0; i < size; i++) {
  128         int rc = dladdr(array[i], &info);
  129 
  130         if (rc == 0) {
  131             ErrorFSigSafe("%u: ?? [%p]\n", i, array[i]);
  132             continue;
  133         }
  134         mod = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)";
  135         if (info.dli_saddr)
  136             ErrorFSigSafe(
  137                 "%u: %s (%s+0x%x) [%p]\n",
  138                 i,
  139                 mod,
  140                 info.dli_sname,
  141                 (unsigned int)((char *) array[i] -
  142                                (char *) info.dli_saddr),
  143                 array[i]);
  144         else
  145             ErrorFSigSafe(
  146                 "%u: %s (%p+0x%x) [%p]\n",
  147                 i,
  148                 mod,
  149                 info.dli_fbase,
  150                 (unsigned int)((char *) array[i] -
  151                                (char *) info.dli_fbase),
  152                 array[i]);
  153     }
  154     ErrorFSigSafe("\n");
  155 }
  156 
  157 #else                           /* not glibc or glibc < 2.1 */
  158 
  159 #if defined(__sun) && defined(__SVR4)
  160 #define HAVE_PSTACK
  161 #endif
  162 
  163 #if defined(HAVE_WALKCONTEXT)   /* Solaris 9 & later */
  164 
  165 #include <ucontext.h>
  166 #include <signal.h>
  167 #include <dlfcn.h>
  168 #include <sys/elf.h>
  169 
  170 #ifdef _LP64
  171 #define ElfSym Elf64_Sym
  172 #else
  173 #define ElfSym Elf32_Sym
  174 #endif
  175 
  176 /* Called for each frame on the stack to print it's contents */
  177 static int
  178 xorg_backtrace_frame(uintptr_t pc, int signo, void *arg)
  179 {
  180     Dl_info dlinfo;
  181     ElfSym *dlsym;
  182     char header[32];
  183     int depth = *((int *) arg);
  184 
  185     if (signo) {
  186         char signame[SIG2STR_MAX];
  187 
  188         if (sig2str(signo, signame) != 0) {
  189             strcpy(signame, "unknown");
  190         }
  191 
  192         ErrorFSigSafe("** Signal %u (%s)\n", signo, signame);
  193     }
  194 
  195     snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc);
  196     *((int *) arg) = depth + 1;
  197 
  198     /* Ask system dynamic loader for info on the address */
  199     if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) {
  200         unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr;
  201         const char *symname;
  202 
  203         if (offset < dlsym->st_size) {  /* inside a function */
  204             symname = dlinfo.dli_sname;
  205         }
  206         else {                  /* found which file it was in, but not which function */
  207             symname = "<section start>";
  208             offset = pc - (uintptr_t) dlinfo.dli_fbase;
  209         }
  210         ErrorFSigSafe("%s: %s:%s+0x%x\n", header, dlinfo.dli_fname, symname,
  211                      offset);
  212 
  213     }
  214     else {
  215         /* Couldn't find symbol info from system dynamic loader, should
  216          * probably poke elfloader here, but haven't written that code yet,
  217          * so we just print the pc.
  218          */
  219         ErrorFSigSafe("%s\n", header);
  220     }
  221 
  222     return 0;
  223 }
  224 #endif                          /* HAVE_WALKCONTEXT */
  225 
  226 #ifdef HAVE_PSTACK
  227 static int
  228 xorg_backtrace_pstack(void)
  229 {
  230     pid_t kidpid;
  231     int pipefd[2];
  232 
  233     if (pipe(pipefd) != 0) {
  234         return -1;
  235     }
  236 
  237     kidpid = fork1();
  238 
  239     if (kidpid == -1) {
  240         /* ERROR */
  241         return -1;
  242     }
  243     else if (kidpid == 0) {
  244         /* CHILD */
  245         char parent[16];
  246 
  247         seteuid(0);
  248         close(STDIN_FILENO);
  249         close(STDOUT_FILENO);
  250         dup2(pipefd[1], STDOUT_FILENO);
  251         closefrom(STDERR_FILENO);
  252 
  253         snprintf(parent, sizeof(parent), "%d", getppid());
  254         execle("/usr/bin/pstack", "pstack", parent, NULL);
  255         exit(1);
  256     }
  257     else {
  258         /* PARENT */
  259         char btline[256];
  260         int kidstat;
  261         int bytesread;
  262         int done = 0;
  263 
  264         close(pipefd[1]);
  265 
  266         while (!done) {
  267             bytesread = read(pipefd[0], btline, sizeof(btline) - 1);
  268 
  269             if (bytesread > 0) {
  270                 btline[bytesread] = 0;
  271                 ErrorFSigSafe("%s", btline);
  272             }
  273             else if ((bytesread < 0) || ((errno != EINTR) && (errno != EAGAIN)))
  274                 done = 1;
  275         }
  276         close(pipefd[0]);
  277         waitpid(kidpid, &kidstat, 0);
  278         if (kidstat != 0)
  279             return -1;
  280     }
  281     return 0;
  282 }
  283 #endif                          /* HAVE_PSTACK */
  284 
  285 #if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT)
  286 
  287 void
  288 xorg_backtrace(void)
  289 {
  290 
  291     ErrorFSigSafe("\n");
  292     ErrorFSigSafe("Backtrace:\n");
  293 
  294 #ifdef HAVE_PSTACK
  295 /* First try fork/exec of pstack - otherwise fall back to walkcontext
  296    pstack is preferred since it can print names of non-exported functions */
  297 
  298     if (xorg_backtrace_pstack() < 0)
  299 #endif
  300     {
  301 #ifdef HAVE_WALKCONTEXT
  302         ucontext_t u;
  303         int depth = 1;
  304 
  305         if (getcontext(&u) == 0)
  306             walkcontext(&u, xorg_backtrace_frame, &depth);
  307         else
  308 #endif
  309             ErrorFSigSafe("Failed to get backtrace info: %s\n", strerror(errno));
  310     }
  311     ErrorFSigSafe("\n");
  312 }
  313 
  314 #else
  315 
  316 /* Default fallback if we can't find any way to get a backtrace */
  317 void
  318 xorg_backtrace(void)
  319 {
  320     return;
  321 }
  322 
  323 #endif
  324 #endif
  325 #endif