xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

backtrace.c (8573B)


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