import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / walkstack.c
blobde8cc3f6e6679f499b429a0e2ef3db37851d1566
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
26 * This file provides a general purpose mechanism
27 * for a user thread to walk its own call stack,
28 * calling a user-specified iterator function for each
29 * stack frame. Special handling is provided to indicate
30 * kernel-constructed signal handler frames.
32 * Adapted from usr/src/lib/libproc/common/Pstack.c:
34 * A signal handler frame is essentially a set of data pushed on to the user
35 * stack by the kernel prior to returning to the user program in one of the
36 * pre-defined signal handlers. The signal handler itself receives the signal
37 * number, an optional pointer to a siginfo_t, and a pointer to the interrupted
38 * ucontext as arguments.
40 * When performing a stack backtrace, we would like to
41 * detect these frames so that we can correctly return the interrupted program
42 * counter and frame pointer as a separate frame.
44 * The stack layout for a signal handler frame is as follows:
46 * SPARC v7/v9: Intel ia32:
47 * +--------------+ - high +--------------+ -
48 * | struct fq | ^ addrs | siginfo_t | optional
49 * +--------------+ | ^ +--------------+ -
50 * | gwindows_t | | | ucontext_t | ^
51 * +--------------+ optional +--------------+ |
52 * | siginfo_t | | ucontext_t * | |
53 * +--------------+ | | +--------------+
54 * | xregs data | v v | siginfo_t * | mandatory
55 * +--------------+ - low +--------------+
56 * | ucontext_t | ^ addrs | int (signo) | |
57 * +--------------+ mandatory +--------------+ |
58 * | struct frame | v | struct frame | v
59 * +--------------+ - <- %sp on resume +--------------+ - <- %esp on resume
61 * amd64 (64-bit)
62 * +--------------+ -
63 * | siginfo_t | optional
64 * +--------------+ -
65 * | ucontext_t | ^
66 * +--------------+ |
67 * | siginfo_t * |
68 * +--------------+ mandatory
69 * | int (signo) |
70 * +--------------+ |
71 * | struct frame | v
72 * +--------------+ - <- %rsp on resume
74 * The bottom-most struct frame is actually constructed by the kernel by
75 * copying the previous stack frame, allowing naive backtrace code to simply
76 * skip over the interrupted frame. The copied frame is never really used,
77 * since it is presumed the signal handler wrapper function
78 * will explicitly setcontext(2) to the interrupted context if the user
79 * program's handler returns. If we detect a signal handler frame, we simply
80 * read the interrupted context structure from the stack, use its embedded
81 * gregs to construct the register set for the interrupted frame, and then
82 * continue our backtrace. Detecting the frame itself is easy according to
83 * the diagram ("oldcontext" represents any element in the uc_link chain):
85 * On SPARC v7 or v9:
86 * %fp + sizeof (struct frame) == oldcontext
88 * On i386:
89 * %ebp + sizeof (struct frame) + (3 words) == oldcontext
91 * On amd64:
92 * %rbp + sizeof (struct frame) + (2 words) == oldcontext
94 * Since we want to provide the signal number that generated a signal stack
95 * frame and on sparc this information isn't written to the stack by the kernel
96 * the way it's done on i386, we're forced to read the signo from the stack as
97 * one of the arguments to the signal handler. We use the thr_sighndlrinfo
98 * interface to find the correct frame.
101 #include "lint.h"
102 #include <assert.h>
103 #include <dlfcn.h>
104 #include <fcntl.h>
105 #include <link.h>
106 #include <procfs.h>
107 #include <strings.h>
108 #include <signal.h>
109 #include <sys/frame.h>
110 #include <sys/regset.h>
111 #include <sys/types.h>
112 #include <sys/uio.h>
113 #include <thread.h>
114 #include <ucontext.h>
115 #include <unistd.h>
116 #include <stdarg.h>
117 #include <sys/stack.h>
118 #include <errno.h>
119 #include <stdio.h>
120 #include <alloca.h>
121 #include <limits.h>
122 #include <stdlib.h>
124 #ifdef _LP64
125 #define _ELF64
126 #endif
128 #include <sys/machelf.h>
131 #if defined(__sparc)
132 #define FRAME_PTR_REGISTER REG_SP
133 #define PC_REGISTER REG_PC
134 #define CHECK_FOR_SIGFRAME(fp, oldctx) ((fp) + SA(sizeof (struct frame)) \
135 == (oldctx))
137 #elif defined(__amd64)
138 #define FRAME_PTR_REGISTER REG_RBP
139 #define PC_REGISTER REG_RIP
140 #define CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
141 2 * sizeof (long) == (oldctx)) && \
142 (((struct frame *)fp)->fr_savpc == (greg_t)-1))
144 #elif defined(__i386)
145 #define FRAME_PTR_REGISTER EBP
146 #define PC_REGISTER EIP
147 #define CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
148 3 * sizeof (int) == (oldctx)) && \
149 (((struct frame *)fp)->fr_savpc == (greg_t)-1))
150 #else
151 #error no arch defined
152 #endif
154 #define MAX_LINE 2048 /* arbitrary large value */
157 * use /proc/self/as to safely dereference pointers so we don't
158 * die in the case of a stack smash
161 static int
162 read_safe(int fd, struct frame *fp, struct frame **savefp, uintptr_t *savepc)
165 uintptr_t newfp;
167 if ((uintptr_t)fp & (sizeof (void *) - 1))
168 return (-1); /* misaligned */
170 if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp),
171 (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) ||
172 pread(fd, (void *)savepc, sizeof (fp->fr_savpc),
173 (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc))
174 return (-1);
177 * handle stack bias on sparcv9
180 if (newfp != 0)
181 newfp += STACK_BIAS;
183 *savefp = (struct frame *)newfp;
185 return (0);
189 walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *),
190 void *usrarg)
192 ucontext_t *oldctx = uptr->uc_link;
194 int fd;
195 int sig;
197 struct frame *savefp;
198 uintptr_t savepc;
201 * snag frame point from ucontext... we'll see caller of
202 * getucontext since we'll start by working up the call
203 * stack by one
206 struct frame *fp = (struct frame *)
207 ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] +
208 STACK_BIAS);
211 * Since we don't write signo to the stack on sparc, we need
212 * to extract signo from the stack frames.
213 * An awkward interface is provided for this purpose:
214 * thr_sighndlrinfo; this is documented in
215 * /shared/sac/PSARC/1999/024. When called, this function
216 * returns the PC of a special function (and its size) that
217 * will be present in the stack frame if a signal was
218 * delivered and will have the following signature
219 * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
220 * void (*hndlr)())
221 * Since this function is written in assembler and doesn't
222 * perturb its registers, we can then read sig out of arg0
223 * when the saved pc is inside this function.
227 if ((fd = open("/proc/self/as", O_RDONLY)) < 0)
228 return (-1);
230 while (fp != NULL) {
232 sig = 0;
235 * get value of saved fp and pc w/o crashing
238 if (read_safe(fd, fp, &savefp, &savepc) != 0) {
239 (void) close(fd);
240 return (-1);
243 if (savefp == NULL)
244 break;
247 * note that the following checks to see if we've got a
248 * special signal stack frame present; this allows us to
249 * detect signals and pass that info to the user stack walker
252 if (oldctx != NULL &&
253 CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) {
255 #if defined(__i386) || defined(__amd64)
257 * i386 and amd64 store signo on stack;
258 * simple to detect and use
260 sig = *((int *)(savefp + 1));
261 #endif
264 * this is the special signal frame, so cons up
265 * the saved fp & pc to pass to user's function
268 savefp = (struct frame *)
269 ((uintptr_t)oldctx->
270 uc_mcontext.gregs[FRAME_PTR_REGISTER] +
271 STACK_BIAS);
272 savepc = oldctx->uc_mcontext.gregs[PC_REGISTER];
274 oldctx = oldctx->uc_link; /* handle nested signals */
278 * call user-supplied function and quit if non-zero return.
281 if (operate_func((uintptr_t)savepc, sig, usrarg) != 0)
282 break;
284 fp = savefp; /* up one in the call stack */
287 (void) close(fd);
288 return (0);
292 * async safe version of fprintf
295 static void
296 async_filenoprintf(int filenum, const char *format, ...)
298 va_list ap;
299 char buffer[MAX_LINE];
301 va_start(ap, format);
302 (void) vsnprintf(buffer, sizeof (buffer), format, ap);
303 va_end(ap);
305 (void) write(filenum, buffer, strlen(buffer));
310 * print out stack frame info
313 static int
314 display_stack_info(uintptr_t pc, int signo, void *arg)
317 char buffer[MAX_LINE];
318 char sigbuf[SIG2STR_MAX];
321 int filenum = (intptr_t)arg;
323 (void) addrtosymstr((void *)pc, buffer, sizeof (buffer));
325 if (signo) {
326 sigbuf[0] = '?';
327 sigbuf[1] = 0;
329 (void) sig2str(signo, sigbuf);
331 async_filenoprintf(filenum, "%s [Signal %d (%s)]\n",
332 buffer, (ulong_t)signo, sigbuf);
333 } else
334 async_filenoprintf(filenum, "%s\n", buffer);
336 return (0);
340 * walk current thread stack, writing symbolic stack trace to specified fd
344 printstack(int dofd)
346 ucontext_t u;
348 if (getcontext(&u) < 0)
349 return (-1);
351 return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd));
355 * Some routines for better opensource compatibility w/ glibc.
358 typedef struct backtrace {
359 void **bt_buffer;
360 int bt_maxcount;
361 int bt_actcount;
362 } backtrace_t;
364 /* ARGSUSED */
365 static int
366 callback(uintptr_t pc, int signo, void *arg)
368 backtrace_t *bt = (backtrace_t *)arg;
370 if (bt->bt_actcount >= bt->bt_maxcount)
371 return (-1);
373 bt->bt_buffer[bt->bt_actcount++] = (void *)pc;
375 return (0);
379 * dump stack trace up to length count into buffer
383 backtrace(void **buffer, int count)
385 backtrace_t bt;
386 ucontext_t u;
388 bt.bt_buffer = buffer;
389 bt.bt_maxcount = count;
390 bt.bt_actcount = 0;
392 if (getcontext(&u) < 0)
393 return (0);
395 (void) walkcontext(&u, callback, &bt);
397 return (bt.bt_actcount);
401 * format backtrace string
405 addrtosymstr(void *pc, char *buffer, int size)
407 Dl_info info;
408 Sym *sym;
410 if (dladdr1(pc, &info, (void **)&sym,
411 RTLD_DL_SYMENT) == 0) {
412 return (snprintf(buffer, size, "[0x%p]", pc));
415 if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
416 ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
418 * we have containing symbol info
420 return (snprintf(buffer, size, "%s'%s+0x%x [0x%p]",
421 info.dli_fname,
422 info.dli_sname,
423 (unsigned long)pc - (unsigned long)info.dli_saddr,
424 pc));
425 } else {
427 * no local symbol info
429 return (snprintf(buffer, size, "%s'0x%p [0x%p]",
430 info.dli_fname,
431 (unsigned long)pc - (unsigned long)info.dli_fbase,
432 pc));
437 * This function returns the symbolic representation of stack trace; calls
438 * malloc so it is NOT async safe! A rather mis-designed and certainly misused
439 * interface.
442 char **
443 backtrace_symbols(void *const *array, int size)
445 int bufferlen, len;
446 char **ret_buffer;
447 char **ret;
448 char linebuffer[MAX_LINE];
449 int i;
451 bufferlen = size * sizeof (char *);
454 * tmp buffer to hold strings while finding all symbol names
457 ret_buffer = (char **)alloca(bufferlen);
459 for (i = 0; i < size; i++) {
460 (void) addrtosymstr(array[i], linebuffer, sizeof (linebuffer));
461 ret_buffer[i] = strcpy(alloca(len = strlen(linebuffer) + 1),
462 linebuffer);
463 bufferlen += len;
467 * allocate total amount of storage required and copy strings
470 if ((ret = (char **)malloc(bufferlen)) == NULL)
471 return (NULL);
474 for (len = i = 0; i < size; i++) {
475 ret[i] = (char *)ret + size * sizeof (char *) + len;
476 (void) strcpy(ret[i], ret_buffer[i]);
477 len += strlen(ret_buffer[i]) + 1;
480 return (ret);
484 * Write out symbolic stack trace in an async-safe way.
487 void
488 backtrace_symbols_fd(void *const *array, int size, int fd)
490 char linebuffer[MAX_LINE];
491 int i;
492 int len;
494 for (i = 0; i < size; i++) {
495 len = addrtosymstr(array[i], linebuffer,
496 sizeof (linebuffer) - 1);
497 if (len >= sizeof (linebuffer))
498 len = sizeof (linebuffer) - 1;
499 linebuffer[len] = '\n';
500 (void) write(fd, linebuffer, len + 1);