2 * Copyright 2008 Red Hat, Inc.
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:
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
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.
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
35 #define UNW_LOCAL_ONLY
36 #include <libunwind.h>
47 unw_context_t context
;
55 pip
.unwind_info
= NULL
;
56 ret
= unw_getcontext(&context
);
58 ErrorFSigSafe("unw_getcontext failed: %s [%d]\n", unw_strerror(ret
),
63 ret
= unw_init_local(&cursor
, &context
);
65 ErrorFSigSafe("unw_init_local failed: %s [%d]\n", unw_strerror(ret
),
71 ErrorFSigSafe("Backtrace:\n");
72 ret
= unw_step(&cursor
);
74 ret
= unw_get_proc_info(&cursor
, &pip
);
76 ErrorFSigSafe("unw_get_proc_info failed: %s [%d]\n",
77 unw_strerror(ret
), ret
);
81 ret
= unw_get_proc_name(&cursor
, procname
, 256, &off
);
82 if (ret
&& ret
!= -UNW_ENOMEM
) {
83 if (ret
!= -UNW_EUNSPEC
)
84 ErrorFSigSafe("unw_get_proc_name failed: %s [%d]\n",
85 unw_strerror(ret
), ret
);
90 if (dladdr((void *)(pip
.start_ip
+ off
), &dlinfo
) && dlinfo
.dli_fname
&&
92 filename
= dlinfo
.dli_fname
;
96 ErrorFSigSafe("%u: %s (%s%s+0x%x) [%p]\n", i
++, filename
, procname
,
97 ret
== -UNW_ENOMEM
? "..." : "", (int)off
,
98 (void *)(pip
.start_ip
+ off
));
100 ret
= unw_step(&cursor
);
102 ErrorFSigSafe("unw_step failed: %s [%d]\n", unw_strerror(ret
), ret
);
106 #else /* HAVE_LIBUNWIND */
107 #ifdef HAVE_BACKTRACE
112 #include <execinfo.h>
117 const int BT_SIZE
= 64;
118 void *array
[BT_SIZE
];
124 ErrorFSigSafe("Backtrace:\n");
125 size
= backtrace(array
, BT_SIZE
);
126 for (i
= 0; i
< size
; i
++) {
127 int rc
= dladdr(array
[i
], &info
);
130 ErrorFSigSafe("%u: ?? [%p]\n", i
, array
[i
]);
133 mod
= (info
.dli_fname
&& *info
.dli_fname
) ? info
.dli_fname
: "(vdso)";
136 "%u: %s (%s+0x%x) [%p]\n",
140 (unsigned int)((char *) array
[i
] -
141 (char *) info
.dli_saddr
),
145 "%u: %s (%p+0x%x) [%p]\n",
149 (unsigned int)((char *) array
[i
] -
150 (char *) info
.dli_fbase
),
156 #else /* not glibc or glibc < 2.1 */
158 #if defined(sun) && defined(__SVR4)
162 #if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */
164 #include <ucontext.h>
170 #define ElfSym Elf64_Sym
172 #define ElfSym Elf32_Sym
175 /* Called for each frame on the stack to print it's contents */
177 xorg_backtrace_frame(uintptr_t pc
, int signo
, void *arg
)
182 int depth
= *((int *) arg
);
185 char signame
[SIG2STR_MAX
];
187 if (sig2str(signo
, signame
) != 0) {
188 strcpy(signame
, "unknown");
191 ErrorFSigSafe("** Signal %u (%s)\n", signo
, signame
);
194 snprintf(header
, sizeof(header
), "%d: 0x%lx", depth
, pc
);
195 *((int *) arg
) = depth
+ 1;
197 /* Ask system dynamic loader for info on the address */
198 if (dladdr1((void *) pc
, &dlinfo
, (void **) &dlsym
, RTLD_DL_SYMENT
)) {
199 unsigned long offset
= pc
- (uintptr_t) dlinfo
.dli_saddr
;
202 if (offset
< dlsym
->st_size
) { /* inside a function */
203 symname
= dlinfo
.dli_sname
;
205 else { /* found which file it was in, but not which function */
206 symname
= "<section start>";
207 offset
= pc
- (uintptr_t) dlinfo
.dli_fbase
;
209 ErrorFSigSafe("%s: %s:%s+0x%x\n", header
, dlinfo
.dli_fname
, symname
,
214 /* Couldn't find symbol info from system dynamic loader, should
215 * probably poke elfloader here, but haven't written that code yet,
216 * so we just print the pc.
218 ErrorFSigSafe("%s\n", header
);
223 #endif /* HAVE_WALKCONTEXT */
227 xorg_backtrace_pstack(void)
232 if (pipe(pipefd
) != 0) {
242 else if (kidpid
== 0) {
248 close(STDOUT_FILENO
);
249 dup2(pipefd
[1], STDOUT_FILENO
);
250 closefrom(STDERR_FILENO
);
252 snprintf(parent
, sizeof(parent
), "%d", getppid());
253 execle("/usr/bin/pstack", "pstack", parent
, NULL
);
266 bytesread
= read(pipefd
[0], btline
, sizeof(btline
) - 1);
269 btline
[bytesread
] = 0;
270 ErrorFSigSafe("%s", btline
);
272 else if ((bytesread
< 0) || ((errno
!= EINTR
) && (errno
!= EAGAIN
)))
276 waitpid(kidpid
, &kidstat
, 0);
282 #endif /* HAVE_PSTACK */
284 #if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT)
291 ErrorFSigSafe("Backtrace:\n");
294 /* First try fork/exec of pstack - otherwise fall back to walkcontext
295 pstack is preferred since it can print names of non-exported functions */
297 if (xorg_backtrace_pstack() < 0)
300 #ifdef HAVE_WALKCONTEXT
304 if (getcontext(&u
) == 0)
305 walkcontext(&u
, xorg_backtrace_frame
, &depth
);
308 ErrorFSigSafe("Failed to get backtrace info: %s\n", strerror(errno
));
315 /* Default fallback if we can't find any way to get a backtrace */