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]
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
63 * | siginfo_t | optional
68 * +--------------+ mandatory
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):
86 * %fp + sizeof (struct frame) == oldcontext
89 * %ebp + sizeof (struct frame) + (3 words) == oldcontext
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.
109 #include <sys/frame.h>
110 #include <sys/regset.h>
111 #include <sys/types.h>
114 #include <ucontext.h>
117 #include <sys/stack.h>
128 #include <sys/machelf.h>
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)) \
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))
151 #error no arch defined
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
162 read_safe(int fd
, struct frame
*fp
, struct frame
**savefp
, uintptr_t *savepc
)
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
))
177 * handle stack bias on sparcv9
183 *savefp
= (struct frame
*)newfp
;
189 walkcontext(const ucontext_t
*uptr
, int (*operate_func
)(uintptr_t, int, void *),
192 ucontext_t
*oldctx
= uptr
->uc_link
;
197 struct frame
*savefp
;
201 * snag frame point from ucontext... we'll see caller of
202 * getucontext since we'll start by working up the call
206 struct frame
*fp
= (struct frame
*)
207 ((uintptr_t)uptr
->uc_mcontext
.gregs
[FRAME_PTR_REGISTER
] +
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,
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)
235 * get value of saved fp and pc w/o crashing
238 if (read_safe(fd
, fp
, &savefp
, &savepc
) != 0) {
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));
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
*)
270 uc_mcontext
.gregs
[FRAME_PTR_REGISTER
] +
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)
284 fp
= savefp
; /* up one in the call stack */
292 * async safe version of fprintf
296 async_filenoprintf(int filenum
, const char *format
, ...)
299 char buffer
[MAX_LINE
];
301 va_start(ap
, format
);
302 (void) vsnprintf(buffer
, sizeof (buffer
), format
, ap
);
305 (void) write(filenum
, buffer
, strlen(buffer
));
310 * print out stack frame info
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
));
329 (void) sig2str(signo
, sigbuf
);
331 async_filenoprintf(filenum
, "%s [Signal %d (%s)]\n",
332 buffer
, (ulong_t
)signo
, sigbuf
);
334 async_filenoprintf(filenum
, "%s\n", buffer
);
340 * walk current thread stack, writing symbolic stack trace to specified fd
348 if (getcontext(&u
) < 0)
351 return (walkcontext(&u
, display_stack_info
, (void*)(intptr_t)dofd
));
355 * Some routines for better opensource compatibility w/ glibc.
358 typedef struct backtrace
{
366 callback(uintptr_t pc
, int signo
, void *arg
)
368 backtrace_t
*bt
= (backtrace_t
*)arg
;
370 if (bt
->bt_actcount
>= bt
->bt_maxcount
)
373 bt
->bt_buffer
[bt
->bt_actcount
++] = (void *)pc
;
379 * dump stack trace up to length count into buffer
383 backtrace(void **buffer
, int count
)
388 bt
.bt_buffer
= buffer
;
389 bt
.bt_maxcount
= count
;
392 if (getcontext(&u
) < 0)
395 (void) walkcontext(&u
, callback
, &bt
);
397 return (bt
.bt_actcount
);
401 * format backtrace string
405 addrtosymstr(void *pc
, char *buffer
, int size
)
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]",
423 (unsigned long)pc
- (unsigned long)info
.dli_saddr
,
427 * no local symbol info
429 return (snprintf(buffer
, size
, "%s'0x%p [0x%p]",
431 (unsigned long)pc
- (unsigned long)info
.dli_fbase
,
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
443 backtrace_symbols(void *const *array
, int size
)
448 char linebuffer
[MAX_LINE
];
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),
467 * allocate total amount of storage required and copy strings
470 if ((ret
= (char **)malloc(bufferlen
)) == 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;
484 * Write out symbolic stack trace in an async-safe way.
488 backtrace_symbols_fd(void *const *array
, int size
, int fd
)
490 char linebuffer
[MAX_LINE
];
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);