xref: /onnv-gate/usr/src/lib/libc/port/gen/walkstack.c (revision 11411:c2fe1bf96826)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53988Sbarts  * Common Development and Distribution License (the "License").
63988Sbarts  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
21*11411SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * This file provides a general purpose mechanism
270Sstevel@tonic-gate  * for a user thread to walk its own call stack,
280Sstevel@tonic-gate  * calling a user-specified iterator function for each
290Sstevel@tonic-gate  * stack frame.  Special handling is provided to indicate
300Sstevel@tonic-gate  * kernel-constructed signal handler frames.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * Adapted from usr/src/lib/libproc/common/Pstack.c:
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * A signal handler frame is essentially a set of data pushed on to the user
350Sstevel@tonic-gate  * stack by the kernel prior to returning to the user program in one of the
360Sstevel@tonic-gate  * pre-defined signal handlers.  The signal handler itself receives the signal
370Sstevel@tonic-gate  * number, an optional pointer to a siginfo_t, and a pointer to the interrupted
380Sstevel@tonic-gate  * ucontext as arguments.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * When performing a stack backtrace, we would like to
410Sstevel@tonic-gate  * detect these frames so that we can correctly return the interrupted program
420Sstevel@tonic-gate  * counter and frame pointer as a separate frame.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * The stack layout for a signal handler frame is as follows:
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  * SPARC v7/v9:                           Intel ia32:
470Sstevel@tonic-gate  * +--------------+ -        high         +--------------+ -
480Sstevel@tonic-gate  * |  struct fq   | ^        addrs        |  siginfo_t   | optional
490Sstevel@tonic-gate  * +--------------+ |          ^          +--------------+ -
500Sstevel@tonic-gate  * |  gwindows_t  |            |          |  ucontext_t  | ^
510Sstevel@tonic-gate  * +--------------+ optional              +--------------+ |
520Sstevel@tonic-gate  * |  siginfo_t   |                       | ucontext_t * | |
530Sstevel@tonic-gate  * +--------------+ |          |          +--------------+
540Sstevel@tonic-gate  * |  xregs data  | v          v          |  siginfo_t * | mandatory
550Sstevel@tonic-gate  * +--------------+ -         low         +--------------+
560Sstevel@tonic-gate  * |  ucontext_t  | ^        addrs        |  int (signo) | |
570Sstevel@tonic-gate  * +--------------+ mandatory             +--------------+ |
580Sstevel@tonic-gate  * | struct frame | v                     | struct frame | v
590Sstevel@tonic-gate  * +--------------+ - <- %sp on resume    +--------------+ - <- %esp on resume
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * amd64 (64-bit)
620Sstevel@tonic-gate  * +--------------+ -
630Sstevel@tonic-gate  * |  siginfo_t   | optional
640Sstevel@tonic-gate  * +--------------+ -
650Sstevel@tonic-gate  * |  ucontext_t  | ^
660Sstevel@tonic-gate  * +--------------+ |
670Sstevel@tonic-gate  * |  siginfo_t * |
680Sstevel@tonic-gate  * +--------------+ mandatory
690Sstevel@tonic-gate  * |  int (signo) |
700Sstevel@tonic-gate  * +--------------+ |
710Sstevel@tonic-gate  * | struct frame | v
720Sstevel@tonic-gate  * +--------------+ - <- %rsp on resume
730Sstevel@tonic-gate  *
740Sstevel@tonic-gate  * The bottom-most struct frame is actually constructed by the kernel by
750Sstevel@tonic-gate  * copying the previous stack frame, allowing naive backtrace code to simply
760Sstevel@tonic-gate  * skip over the interrupted frame.  The copied frame is never really used,
776812Sraf  * since it is presumed the signal handler wrapper function
780Sstevel@tonic-gate  * will explicitly setcontext(2) to the interrupted context if the user
790Sstevel@tonic-gate  * program's handler returns.  If we detect a signal handler frame, we simply
800Sstevel@tonic-gate  * read the interrupted context structure from the stack, use its embedded
810Sstevel@tonic-gate  * gregs to construct the register set for the interrupted frame, and then
820Sstevel@tonic-gate  * continue our backtrace.  Detecting the frame itself is easy according to
830Sstevel@tonic-gate  * the diagram ("oldcontext" represents any element in the uc_link chain):
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  * On SPARC v7 or v9:
860Sstevel@tonic-gate  * %fp + sizeof (struct frame) == oldcontext
870Sstevel@tonic-gate  *
880Sstevel@tonic-gate  * On i386:
890Sstevel@tonic-gate  * %ebp + sizeof (struct frame) + (3 words) == oldcontext
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * On amd64:
920Sstevel@tonic-gate  * %rbp + sizeof (struct frame) + (2 words) == oldcontext
930Sstevel@tonic-gate  *
940Sstevel@tonic-gate  * Since we want to provide the signal number that generated a signal stack
950Sstevel@tonic-gate  * frame and on sparc this information isn't written to the stack by the kernel
960Sstevel@tonic-gate  * the way it's done on i386, we're forced to read the signo from the stack as
976812Sraf  * one of the arguments to the signal handler.  We use the thr_sighndlrinfo
986812Sraf  * interface to find the correct frame.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate 
1016812Sraf #include "lint.h"
1020Sstevel@tonic-gate #include <assert.h>
1030Sstevel@tonic-gate #include <dlfcn.h>
1040Sstevel@tonic-gate #include <fcntl.h>
1050Sstevel@tonic-gate #include <link.h>
1060Sstevel@tonic-gate #include <procfs.h>
1070Sstevel@tonic-gate #include <strings.h>
1080Sstevel@tonic-gate #include <signal.h>
1090Sstevel@tonic-gate #include <sys/frame.h>
1100Sstevel@tonic-gate #include <sys/regset.h>
1110Sstevel@tonic-gate #include <sys/types.h>
1120Sstevel@tonic-gate #include <sys/uio.h>
1130Sstevel@tonic-gate #include <thread.h>
1140Sstevel@tonic-gate #include <ucontext.h>
1150Sstevel@tonic-gate #include <unistd.h>
1160Sstevel@tonic-gate #include <stdarg.h>
1170Sstevel@tonic-gate #include <sys/stack.h>
1180Sstevel@tonic-gate #include <errno.h>
1190Sstevel@tonic-gate #include <stdio.h>
1200Sstevel@tonic-gate #include <alloca.h>
1210Sstevel@tonic-gate #include <limits.h>
1223988Sbarts #include <stdlib.h>
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate #ifdef _LP64
1250Sstevel@tonic-gate #define	_ELF64
1260Sstevel@tonic-gate #endif
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #include <sys/machelf.h>
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate #if defined(__sparc)
1320Sstevel@tonic-gate #define	FRAME_PTR_REGISTER REG_SP
1330Sstevel@tonic-gate #define	PC_REGISTER REG_PC
1340Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((fp) + SA(sizeof (struct frame)) \
1350Sstevel@tonic-gate 	== (oldctx))
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate #elif defined(__amd64)
1380Sstevel@tonic-gate #define	FRAME_PTR_REGISTER	REG_RBP
1390Sstevel@tonic-gate #define	PC_REGISTER		REG_RIP
1400Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
1410Sstevel@tonic-gate 	2 * sizeof (long) == (oldctx)) && \
1420Sstevel@tonic-gate 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate #elif defined(__i386)
1450Sstevel@tonic-gate #define	FRAME_PTR_REGISTER EBP
1460Sstevel@tonic-gate #define	PC_REGISTER EIP
1470Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
1480Sstevel@tonic-gate 	3 * sizeof (int) == (oldctx)) && \
1490Sstevel@tonic-gate 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
1500Sstevel@tonic-gate #else
1510Sstevel@tonic-gate #error no arch defined
1520Sstevel@tonic-gate #endif
1530Sstevel@tonic-gate 
1543988Sbarts #define	MAX_LINE 2048 /* arbitrary large value */
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * use /proc/self/as to safely dereference pointers so we don't
1580Sstevel@tonic-gate  * die in the case of a stack smash
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static int
read_safe(int fd,struct frame * fp,struct frame ** savefp,uintptr_t * savepc)1620Sstevel@tonic-gate read_safe(int fd, struct frame *fp, struct frame **savefp, uintptr_t *savepc)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	uintptr_t newfp;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	if ((uintptr_t)fp & (sizeof (void *) - 1))
1680Sstevel@tonic-gate 		return (-1); /* misaligned */
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp),
1710Sstevel@tonic-gate 	    (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) ||
1720Sstevel@tonic-gate 	    pread(fd, (void *)savepc, sizeof (fp->fr_savpc),
1730Sstevel@tonic-gate 	    (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc))
1740Sstevel@tonic-gate 		return (-1);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/*
1770Sstevel@tonic-gate 	 * handle stack bias on sparcv9
1780Sstevel@tonic-gate 	 */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (newfp != 0)
1810Sstevel@tonic-gate 		newfp += STACK_BIAS;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	*savefp = (struct frame *)newfp;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	return (0);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate int
walkcontext(const ucontext_t * uptr,int (* operate_func)(uintptr_t,int,void *),void * usrarg)1890Sstevel@tonic-gate walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *),
1900Sstevel@tonic-gate     void *usrarg)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	ucontext_t *oldctx = uptr->uc_link;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	int	fd;
1950Sstevel@tonic-gate 	int 	sig;
1960Sstevel@tonic-gate #if defined(__sparc)
1970Sstevel@tonic-gate 	int 	signo = 0;
1980Sstevel@tonic-gate #endif
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	struct frame *savefp;
2010Sstevel@tonic-gate 	uintptr_t savepc;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * snag frame point from ucontext... we'll see caller of
2050Sstevel@tonic-gate 	 * getucontext since we'll start by working up the call
2060Sstevel@tonic-gate 	 * stack by one
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	struct frame *fp = (struct frame *)
2100Sstevel@tonic-gate 	    ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2110Sstevel@tonic-gate 	    STACK_BIAS);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/*
2140Sstevel@tonic-gate 	 * Since we don't write signo to the stack on sparc, we need
2156812Sraf 	 * to extract signo from the stack frames.
2166812Sraf 	 * An awkward interface is provided for this purpose:
2176812Sraf 	 * thr_sighndlrinfo; this is documented in
2180Sstevel@tonic-gate 	 * /shared/sac/PSARC/1999/024.  When called, this function
2190Sstevel@tonic-gate 	 * returns the PC of a special function (and its size) that
2200Sstevel@tonic-gate 	 * will be present in the stack frame if a signal was
2210Sstevel@tonic-gate 	 * delivered and will have the following signature
2220Sstevel@tonic-gate 	 * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
2230Sstevel@tonic-gate 	 *	void (*hndlr)())
2240Sstevel@tonic-gate 	 * Since this function is written in assembler and doesn't
2250Sstevel@tonic-gate 	 * perturb its registers, we can then read sig out of arg0
2260Sstevel@tonic-gate 	 * when the saved pc is inside this function.
2270Sstevel@tonic-gate 	 */
2280Sstevel@tonic-gate #if defined(__sparc)
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	uintptr_t special_pc = NULL;
2310Sstevel@tonic-gate 	int special_size = 0;
2320Sstevel@tonic-gate 
2336812Sraf 	extern void thr_sighndlrinfo(void (**func)(), int *funcsize);
2340Sstevel@tonic-gate 
2356812Sraf 	thr_sighndlrinfo((void (**)())&special_pc, &special_size);
2360Sstevel@tonic-gate #endif /* sparc */
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if ((fd = open("/proc/self/as", O_RDONLY)) < 0)
2400Sstevel@tonic-gate 		return (-1);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	while (fp != NULL) {
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		sig = 0;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		/*
2470Sstevel@tonic-gate 		 * get value of saved fp and pc w/o crashing
2480Sstevel@tonic-gate 		 */
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		if (read_safe(fd, fp, &savefp, &savepc) != 0) {
2510Sstevel@tonic-gate 			(void) close(fd);
2520Sstevel@tonic-gate 			return (-1);
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		if (savefp == NULL)
2560Sstevel@tonic-gate 			break;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		/*
2590Sstevel@tonic-gate 		 * note that the following checks to see if we've got a
2600Sstevel@tonic-gate 		 * special signal stack frame present; this allows us to
2610Sstevel@tonic-gate 		 * detect signals and pass that info to the user stack walker
2620Sstevel@tonic-gate 		 */
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (oldctx != NULL &&
2650Sstevel@tonic-gate 		    CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) {
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
2680Sstevel@tonic-gate 			/*
2690Sstevel@tonic-gate 			 * i386 and amd64 store signo on stack;
2700Sstevel@tonic-gate 			 * simple to detect and use
2710Sstevel@tonic-gate 			 */
2720Sstevel@tonic-gate 			sig = *((int *)(savefp + 1));
2730Sstevel@tonic-gate #endif
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate #if defined(__sparc)
2760Sstevel@tonic-gate 			/*
2770Sstevel@tonic-gate 			 * In the case of threads, since there are multiple
2780Sstevel@tonic-gate 			 * complex routines between kernel and user handler,
2790Sstevel@tonic-gate 			 * we need to figure out where we can read signal from
2806812Sraf 			 * using thr_sighndlrinfo - which we've already done
2810Sstevel@tonic-gate 			 * for this signal, since it appeared on the stack
2820Sstevel@tonic-gate 			 * before the signal frame.... sigh.
2830Sstevel@tonic-gate 			 */
2846812Sraf 			sig = signo; /* already read - see below */
2850Sstevel@tonic-gate #endif
2860Sstevel@tonic-gate 			/*
2870Sstevel@tonic-gate 			 * this is the special signal frame, so cons up
2880Sstevel@tonic-gate 			 * the saved fp & pc to pass to user's function
2890Sstevel@tonic-gate 			 */
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 			savefp = (struct frame *)
2920Sstevel@tonic-gate 			    ((uintptr_t)oldctx->
2930Sstevel@tonic-gate 			    uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2940Sstevel@tonic-gate 			    STACK_BIAS);
2950Sstevel@tonic-gate 			savepc = oldctx->uc_mcontext.gregs[PC_REGISTER];
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 			oldctx = oldctx->uc_link; /* handle nested signals */
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate #if defined(__sparc)
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		/*
3020Sstevel@tonic-gate 		 * lookahead code to find right spot to read signo from...
3030Sstevel@tonic-gate 		 */
3040Sstevel@tonic-gate 
3056812Sraf 		if (savepc >= special_pc && savepc <
3060Sstevel@tonic-gate 		    (special_pc + special_size))
3070Sstevel@tonic-gate 			signo = fp->fr_arg[0];
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		/*
3110Sstevel@tonic-gate 		 * call user-supplied function and quit if non-zero return.
3120Sstevel@tonic-gate 		 */
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		if (operate_func((uintptr_t)savepc, sig, usrarg) != 0)
3150Sstevel@tonic-gate 			break;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 		fp = savefp; /* up one in the call stack */
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	(void) close(fd);
3210Sstevel@tonic-gate 	return (0);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3243988Sbarts /*
3253988Sbarts  * async safe version of fprintf
3263988Sbarts  */
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate static void
async_filenoprintf(int filenum,const char * format,...)3290Sstevel@tonic-gate async_filenoprintf(int filenum, const char *format, ...)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate 	va_list ap;
3323988Sbarts 	char buffer[MAX_LINE];
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	va_start(ap, format);
3353988Sbarts 	(void) vsnprintf(buffer, sizeof (buffer), format, ap);
3360Sstevel@tonic-gate 	va_end(ap);
3370Sstevel@tonic-gate 
3383988Sbarts 	(void) write(filenum, buffer, strlen(buffer));
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate 
3423988Sbarts /*
3433988Sbarts  *  print out stack frame info
3443988Sbarts  */
3453988Sbarts 
3460Sstevel@tonic-gate static int
display_stack_info(uintptr_t pc,int signo,void * arg)3470Sstevel@tonic-gate display_stack_info(uintptr_t pc, int signo, void *arg)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 
3503988Sbarts 	char buffer[MAX_LINE];
3510Sstevel@tonic-gate 	char sigbuf[SIG2STR_MAX];
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	int filenum = (intptr_t)arg;
3550Sstevel@tonic-gate 
3563988Sbarts 	(void) addrtosymstr((void *)pc, buffer, sizeof (buffer));
3570Sstevel@tonic-gate 
3583988Sbarts 	if (signo) {
3593988Sbarts 		sigbuf[0] = '?';
3603988Sbarts 		sigbuf[1] = 0;
3610Sstevel@tonic-gate 
3623988Sbarts 		(void) sig2str(signo, sigbuf);
3633988Sbarts 
3643988Sbarts 		async_filenoprintf(filenum, "%s [Signal %d (%s)]\n",
3656812Sraf 		    buffer, (ulong_t)signo, sigbuf);
3663988Sbarts 	} else
3673988Sbarts 		async_filenoprintf(filenum, "%s\n", buffer);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	return (0);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3723988Sbarts /*
3733988Sbarts  * walk current thread stack, writing symbolic stack trace to specified fd
3743988Sbarts  */
3753988Sbarts 
3760Sstevel@tonic-gate int
printstack(int dofd)3770Sstevel@tonic-gate printstack(int dofd)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate 	ucontext_t u;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (getcontext(&u) < 0)
3820Sstevel@tonic-gate 		return (-1);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd));
3850Sstevel@tonic-gate }
3863988Sbarts 
3873988Sbarts /*
3883988Sbarts  * Some routines for better opensource compatibility w/ glibc.
3893988Sbarts  */
3903988Sbarts 
3913988Sbarts typedef struct backtrace {
3923988Sbarts 	void	**bt_buffer;
3933988Sbarts 	int	bt_maxcount;
3943988Sbarts 	int	bt_actcount;
3953988Sbarts } backtrace_t;
3963988Sbarts 
3973988Sbarts /* ARGSUSED */
3983988Sbarts static int
callback(uintptr_t pc,int signo,void * arg)3993988Sbarts callback(uintptr_t pc, int signo, void *arg)
4003988Sbarts {
4013988Sbarts 	backtrace_t *bt = (backtrace_t *)arg;
4023988Sbarts 
4033988Sbarts 	if (bt->bt_actcount >= bt->bt_maxcount)
4043988Sbarts 		return (-1);
4053988Sbarts 
4063988Sbarts 	bt->bt_buffer[bt->bt_actcount++] = (void *)pc;
4073988Sbarts 
4083988Sbarts 	return (0);
4093988Sbarts }
4103988Sbarts 
4113988Sbarts /*
4123988Sbarts  * dump stack trace up to length count into buffer
4133988Sbarts  */
4143988Sbarts 
4153988Sbarts int
backtrace(void ** buffer,int count)4163988Sbarts backtrace(void **buffer, int count)
4173988Sbarts {
4183988Sbarts 	backtrace_t 	bt;
4193988Sbarts 	ucontext_t 	u;
4203988Sbarts 
4213988Sbarts 	bt.bt_buffer = buffer;
4223988Sbarts 	bt.bt_maxcount = count;
4233988Sbarts 	bt.bt_actcount = 0;
4243988Sbarts 
4253988Sbarts 	if (getcontext(&u) < 0)
4263988Sbarts 		return (0);
4273988Sbarts 
4283988Sbarts 	(void) walkcontext(&u, callback, &bt);
4293988Sbarts 
4303988Sbarts 	return (bt.bt_actcount);
4313988Sbarts }
4323988Sbarts 
4333988Sbarts /*
4343988Sbarts  * format backtrace string
4353988Sbarts  */
4363988Sbarts 
4373988Sbarts int
addrtosymstr(void * pc,char * buffer,int size)4383988Sbarts addrtosymstr(void *pc, char *buffer, int size)
4393988Sbarts {
4403988Sbarts 	Dl_info info;
4413988Sbarts 	Sym *sym;
4423988Sbarts 
4433988Sbarts 	if (dladdr1(pc, &info, (void **)&sym,
4443988Sbarts 	    RTLD_DL_SYMENT) == 0) {
4453988Sbarts 		return (snprintf(buffer, size, "[0x%p]", pc));
4463988Sbarts 	}
4473988Sbarts 
4483988Sbarts 	if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
4493988Sbarts 	    ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
4503988Sbarts 		/*
4513988Sbarts 		 * we have containing symbol info
4523988Sbarts 		 */
4533988Sbarts 		return (snprintf(buffer, size, "%s'%s+0x%x [0x%p]",
4543988Sbarts 		    info.dli_fname,
4553988Sbarts 		    info.dli_sname,
4563988Sbarts 		    (unsigned long)pc - (unsigned long)info.dli_saddr,
4573988Sbarts 		    pc));
4583988Sbarts 	} else {
4593988Sbarts 		/*
4603988Sbarts 		 * no local symbol info
4613988Sbarts 		 */
4623988Sbarts 		return (snprintf(buffer, size, "%s'0x%p [0x%p]",
4633988Sbarts 		    info.dli_fname,
4643988Sbarts 		    (unsigned long)pc - (unsigned long)info.dli_fbase,
4653988Sbarts 		    pc));
4663988Sbarts 	}
4673988Sbarts }
4683988Sbarts 
4693988Sbarts /*
4703988Sbarts  * This function returns the symbolic representation of stack trace; calls
4713988Sbarts  * malloc so it is NOT async safe!  A rather mis-designed and certainly misused
4723988Sbarts  * interface.
4733988Sbarts  */
4743988Sbarts 
4753988Sbarts char **
backtrace_symbols(void * const * array,int size)4763988Sbarts backtrace_symbols(void *const *array, int size)
4773988Sbarts {
4783988Sbarts 	int bufferlen, len;
4793988Sbarts 	char **ret_buffer;
4803988Sbarts 	char **ret;
4813988Sbarts 	char linebuffer[MAX_LINE];
4823988Sbarts 	int i;
4833988Sbarts 
4843988Sbarts 	bufferlen = size * sizeof (char *);
4853988Sbarts 
4863988Sbarts 	/*
4873988Sbarts 	 *  tmp buffer to hold strings while finding all symbol names
4883988Sbarts 	 */
4893988Sbarts 
4903988Sbarts 	ret_buffer = (char **)alloca(bufferlen);
4913988Sbarts 
4923988Sbarts 	for (i = 0; i < size; i++) {
4933988Sbarts 		(void) addrtosymstr(array[i], linebuffer, sizeof (linebuffer));
4943988Sbarts 		ret_buffer[i] = strcpy(alloca(len = strlen(linebuffer) + 1),
4953988Sbarts 		    linebuffer);
4963988Sbarts 		bufferlen += len;
4973988Sbarts 	}
4983988Sbarts 
4993988Sbarts 	/*
5003988Sbarts 	 * allocate total amount of storage required and copy strings
5013988Sbarts 	 */
5023988Sbarts 
5033988Sbarts 	if ((ret = (char **)malloc(bufferlen)) == NULL)
5043988Sbarts 		return (NULL);
5053988Sbarts 
5063988Sbarts 
5073988Sbarts 	for (len = i = 0; i < size; i++) {
5083988Sbarts 		ret[i] = (char *)ret + size * sizeof (char *) + len;
509*11411SSurya.Prakki@Sun.COM 		(void) strcpy(ret[i], ret_buffer[i]);
5103988Sbarts 		len += strlen(ret_buffer[i]) + 1;
5113988Sbarts 	}
5123988Sbarts 
5133988Sbarts 	return (ret);
5143988Sbarts }
5153988Sbarts 
5163988Sbarts /*
5173988Sbarts  * Write out symbolic stack trace in an async-safe way.
5183988Sbarts  */
5193988Sbarts 
5203988Sbarts void
backtrace_symbols_fd(void * const * array,int size,int fd)5213988Sbarts backtrace_symbols_fd(void *const *array, int size, int fd)
5223988Sbarts {
5233988Sbarts 	char linebuffer[MAX_LINE];
5243988Sbarts 	int i;
5253988Sbarts 	int len;
5263988Sbarts 
5273988Sbarts 	for (i = 0; i < size; i++) {
5283988Sbarts 		len = addrtosymstr(array[i], linebuffer,
5293988Sbarts 		    sizeof (linebuffer) - 1);
5303988Sbarts 		if (len >= sizeof (linebuffer))
5313988Sbarts 			len = sizeof (linebuffer) - 1;
5323988Sbarts 		linebuffer[len] = '\n';
5333988Sbarts 		(void) write(fd, linebuffer, len + 1);
5343988Sbarts 	}
5353988Sbarts }
536