Apply a patch for fixing TDIS-5990 (CVE-2013-1940 allow physically proximate attacker...
[framework/uifw/xorg/server/xorg-server.git] / os / backtrace.c
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_BACKTRACE
34 #ifndef _GNU_SOURCE
35 #define _GNU_SOURCE
36 #endif
37 #include <dlfcn.h>
38 #include <execinfo.h>
39
40 void
41 xorg_backtrace(void)
42 {
43     void *array[64];
44     const char *mod;
45     int size, i;
46     Dl_info info;
47
48     ErrorFSigSafe("\n");
49     ErrorFSigSafe("Backtrace:\n");
50     size = backtrace(array, 64);
51     for (i = 0; i < size; i++) {
52         int rc = dladdr(array[i], &info);
53
54         if (rc == 0) {
55             ErrorFSigSafe("%u: ?? [%p]\n", i, array[i]);
56             continue;
57         }
58         mod = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)";
59         if (info.dli_saddr)
60             ErrorFSigSafe(
61                 "%u: %s (%s+0x%x) [%p]\n",
62                 i,
63                 mod,
64                 info.dli_sname,
65                 (unsigned int)((char *) array[i] -
66                                (char *) info.dli_saddr),
67                 array[i]);
68         else
69             ErrorFSigSafe(
70                 "%u: %s (%p+0x%x) [%p]\n",
71                 i,
72                 mod,
73                 info.dli_fbase,
74                 (unsigned int)((char *) array[i] -
75                                (char *) info.dli_fbase),
76                 array[i]);
77     }
78     ErrorFSigSafe("\n");
79 }
80
81 #else                           /* not glibc or glibc < 2.1 */
82
83 #if defined(sun) && defined(__SVR4)
84 #define HAVE_PSTACK
85 #endif
86
87 #if defined(HAVE_WALKCONTEXT)   /* Solaris 9 & later */
88
89 #include <ucontext.h>
90 #include <signal.h>
91 #include <dlfcn.h>
92 #include <sys/elf.h>
93
94 #ifdef _LP64
95 #define ElfSym Elf64_Sym
96 #else
97 #define ElfSym Elf32_Sym
98 #endif
99
100 /* Called for each frame on the stack to print it's contents */
101 static int
102 xorg_backtrace_frame(uintptr_t pc, int signo, void *arg)
103 {
104     Dl_info dlinfo;
105     ElfSym *dlsym;
106     char header[32];
107     int depth = *((int *) arg);
108
109     if (signo) {
110         char signame[SIG2STR_MAX];
111
112         if (sig2str(signo, signame) != 0) {
113             strcpy(signame, "unknown");
114         }
115
116         ErrorFSigSafe("** Signal %u (%s)\n", signo, signame);
117     }
118
119     snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc);
120     *((int *) arg) = depth + 1;
121
122     /* Ask system dynamic loader for info on the address */
123     if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) {
124         unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr;
125         const char *symname;
126
127         if (offset < dlsym->st_size) {  /* inside a function */
128             symname = dlinfo.dli_sname;
129         }
130         else {                  /* found which file it was in, but not which function */
131             symname = "<section start>";
132             offset = pc - (uintptr_t) dlinfo.dli_fbase;
133         }
134         ErrorFSigSafe("%s: %s:%s+0x%x\n", header, dlinfo.dli_fname, symname,
135                      offset);
136
137     }
138     else {
139         /* Couldn't find symbol info from system dynamic loader, should
140          * probably poke elfloader here, but haven't written that code yet,
141          * so we just print the pc.
142          */
143         ErrorFSigSafe("%s\n", header);
144     }
145
146     return 0;
147 }
148 #endif                          /* HAVE_WALKCONTEXT */
149
150 #ifdef HAVE_PSTACK
151 static int
152 xorg_backtrace_pstack(void)
153 {
154     pid_t kidpid;
155     int pipefd[2];
156
157     if (pipe(pipefd) != 0) {
158         return -1;
159     }
160
161     kidpid = fork1();
162
163     if (kidpid == -1) {
164         /* ERROR */
165         return -1;
166     }
167     else if (kidpid == 0) {
168         /* CHILD */
169         char parent[16];
170
171         seteuid(0);
172         close(STDIN_FILENO);
173         close(STDOUT_FILENO);
174         dup2(pipefd[1], STDOUT_FILENO);
175         closefrom(STDERR_FILENO);
176
177         snprintf(parent, sizeof(parent), "%d", getppid());
178         execle("/usr/bin/pstack", "pstack", parent, NULL);
179         exit(1);
180     }
181     else {
182         /* PARENT */
183         char btline[256];
184         int kidstat;
185         int bytesread;
186         int done = 0;
187
188         close(pipefd[1]);
189
190         while (!done) {
191             bytesread = read(pipefd[0], btline, sizeof(btline) - 1);
192
193             if (bytesread > 0) {
194                 btline[bytesread] = 0;
195                 ErrorFSigSafe("%s", btline);
196             }
197             else if ((bytesread < 0) || ((errno != EINTR) && (errno != EAGAIN)))
198                 done = 1;
199         }
200         close(pipefd[0]);
201         waitpid(kidpid, &kidstat, 0);
202         if (kidstat != 0)
203             return -1;
204     }
205     return 0;
206 }
207 #endif                          /* HAVE_PSTACK */
208
209 #if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT)
210
211 void
212 xorg_backtrace(void)
213 {
214
215     ErrorFSigSafe("\n");
216     ErrorFSigSafe("Backtrace:\n");
217
218 #ifdef HAVE_PSTACK
219 /* First try fork/exec of pstack - otherwise fall back to walkcontext
220    pstack is preferred since it can print names of non-exported functions */
221
222     if (xorg_backtrace_pstack() < 0)
223 #endif
224     {
225 #ifdef HAVE_WALKCONTEXT
226         ucontext_t u;
227         int depth = 1;
228
229         if (getcontext(&u) == 0)
230             walkcontext(&u, xorg_backtrace_frame, &depth);
231         else
232 #endif
233             ErrorFSigSafe("Failed to get backtrace info: %s\n", strerror(errno));
234     }
235     ErrorFSigSafe("\n");
236 }
237
238 #else
239
240 /* Default fallback if we can't find any way to get a backtrace */
241 void
242 xorg_backtrace(void)
243 {
244     return;
245 }
246
247 #endif
248 #endif