xref: /illumos-gate/usr/src/lib/libc/port/gen/walkstack.c (revision 4a38094c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f151e4bfSbarts  * Common Development and Distribution License (the "License").
6f151e4bfSbarts  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  *
215ad42b1bSSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
227c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * This file provides a general purpose mechanism
277c478bd9Sstevel@tonic-gate  * for a user thread to walk its own call stack,
287c478bd9Sstevel@tonic-gate  * calling a user-specified iterator function for each
297c478bd9Sstevel@tonic-gate  * stack frame.  Special handling is provided to indicate
307c478bd9Sstevel@tonic-gate  * kernel-constructed signal handler frames.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * Adapted from usr/src/lib/libproc/common/Pstack.c:
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * A signal handler frame is essentially a set of data pushed on to the user
357c478bd9Sstevel@tonic-gate  * stack by the kernel prior to returning to the user program in one of the
367c478bd9Sstevel@tonic-gate  * pre-defined signal handlers.  The signal handler itself receives the signal
377c478bd9Sstevel@tonic-gate  * number, an optional pointer to a siginfo_t, and a pointer to the interrupted
387c478bd9Sstevel@tonic-gate  * ucontext as arguments.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * When performing a stack backtrace, we would like to
417c478bd9Sstevel@tonic-gate  * detect these frames so that we can correctly return the interrupted program
427c478bd9Sstevel@tonic-gate  * counter and frame pointer as a separate frame.
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * The stack layout for a signal handler frame is as follows:
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * SPARC v7/v9:                           Intel ia32:
477c478bd9Sstevel@tonic-gate  * +--------------+ -        high         +--------------+ -
487c478bd9Sstevel@tonic-gate  * |  struct fq   | ^        addrs        |  siginfo_t   | optional
497c478bd9Sstevel@tonic-gate  * +--------------+ |          ^          +--------------+ -
507c478bd9Sstevel@tonic-gate  * |  gwindows_t  |            |          |  ucontext_t  | ^
517c478bd9Sstevel@tonic-gate  * +--------------+ optional              +--------------+ |
527c478bd9Sstevel@tonic-gate  * |  siginfo_t   |                       | ucontext_t * | |
537c478bd9Sstevel@tonic-gate  * +--------------+ |          |          +--------------+
547c478bd9Sstevel@tonic-gate  * |  xregs data  | v          v          |  siginfo_t * | mandatory
557c478bd9Sstevel@tonic-gate  * +--------------+ -         low         +--------------+
567c478bd9Sstevel@tonic-gate  * |  ucontext_t  | ^        addrs        |  int (signo) | |
577c478bd9Sstevel@tonic-gate  * +--------------+ mandatory             +--------------+ |
587c478bd9Sstevel@tonic-gate  * | struct frame | v                     | struct frame | v
597c478bd9Sstevel@tonic-gate  * +--------------+ - <- %sp on resume    +--------------+ - <- %esp on resume
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * amd64 (64-bit)
627c478bd9Sstevel@tonic-gate  * +--------------+ -
637c478bd9Sstevel@tonic-gate  * |  siginfo_t   | optional
647c478bd9Sstevel@tonic-gate  * +--------------+ -
657c478bd9Sstevel@tonic-gate  * |  ucontext_t  | ^
667c478bd9Sstevel@tonic-gate  * +--------------+ |
677c478bd9Sstevel@tonic-gate  * |  siginfo_t * |
687c478bd9Sstevel@tonic-gate  * +--------------+ mandatory
697c478bd9Sstevel@tonic-gate  * |  int (signo) |
707c478bd9Sstevel@tonic-gate  * +--------------+ |
717c478bd9Sstevel@tonic-gate  * | struct frame | v
727c478bd9Sstevel@tonic-gate  * +--------------+ - <- %rsp on resume
737c478bd9Sstevel@tonic-gate  *
747c478bd9Sstevel@tonic-gate  * The bottom-most struct frame is actually constructed by the kernel by
757c478bd9Sstevel@tonic-gate  * copying the previous stack frame, allowing naive backtrace code to simply
767c478bd9Sstevel@tonic-gate  * skip over the interrupted frame.  The copied frame is never really used,
777257d1b4Sraf  * since it is presumed the signal handler wrapper function
787c478bd9Sstevel@tonic-gate  * will explicitly setcontext(2) to the interrupted context if the user
797c478bd9Sstevel@tonic-gate  * program's handler returns.  If we detect a signal handler frame, we simply
807c478bd9Sstevel@tonic-gate  * read the interrupted context structure from the stack, use its embedded
817c478bd9Sstevel@tonic-gate  * gregs to construct the register set for the interrupted frame, and then
827c478bd9Sstevel@tonic-gate  * continue our backtrace.  Detecting the frame itself is easy according to
837c478bd9Sstevel@tonic-gate  * the diagram ("oldcontext" represents any element in the uc_link chain):
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  * On SPARC v7 or v9:
867c478bd9Sstevel@tonic-gate  * %fp + sizeof (struct frame) == oldcontext
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * On i386:
897c478bd9Sstevel@tonic-gate  * %ebp + sizeof (struct frame) + (3 words) == oldcontext
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * On amd64:
927c478bd9Sstevel@tonic-gate  * %rbp + sizeof (struct frame) + (2 words) == oldcontext
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * Since we want to provide the signal number that generated a signal stack
957c478bd9Sstevel@tonic-gate  * frame and on sparc this information isn't written to the stack by the kernel
967c478bd9Sstevel@tonic-gate  * the way it's done on i386, we're forced to read the signo from the stack as
977257d1b4Sraf  * one of the arguments to the signal handler.  We use the thr_sighndlrinfo
987257d1b4Sraf  * interface to find the correct frame.
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate 
1017257d1b4Sraf #include "lint.h"
1027c478bd9Sstevel@tonic-gate #include <assert.h>
1037c478bd9Sstevel@tonic-gate #include <dlfcn.h>
1047c478bd9Sstevel@tonic-gate #include <fcntl.h>
1057c478bd9Sstevel@tonic-gate #include <link.h>
1067c478bd9Sstevel@tonic-gate #include <procfs.h>
1077c478bd9Sstevel@tonic-gate #include <strings.h>
1087c478bd9Sstevel@tonic-gate #include <signal.h>
1097c478bd9Sstevel@tonic-gate #include <sys/frame.h>
1107c478bd9Sstevel@tonic-gate #include <sys/regset.h>
1117c478bd9Sstevel@tonic-gate #include <sys/types.h>
1127c478bd9Sstevel@tonic-gate #include <sys/uio.h>
1137c478bd9Sstevel@tonic-gate #include <thread.h>
1147c478bd9Sstevel@tonic-gate #include <ucontext.h>
1157c478bd9Sstevel@tonic-gate #include <unistd.h>
1167c478bd9Sstevel@tonic-gate #include <stdarg.h>
1177c478bd9Sstevel@tonic-gate #include <sys/stack.h>
1187c478bd9Sstevel@tonic-gate #include <errno.h>
1197c478bd9Sstevel@tonic-gate #include <stdio.h>
1207c478bd9Sstevel@tonic-gate #include <alloca.h>
1217c478bd9Sstevel@tonic-gate #include <limits.h>
122f151e4bfSbarts #include <stdlib.h>
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #ifdef _LP64
1257c478bd9Sstevel@tonic-gate #define	_ELF64
1267c478bd9Sstevel@tonic-gate #endif
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate #if defined(__sparc)
1327c478bd9Sstevel@tonic-gate #define	FRAME_PTR_REGISTER REG_SP
1337c478bd9Sstevel@tonic-gate #define	PC_REGISTER REG_PC
1347c478bd9Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((fp) + SA(sizeof (struct frame)) \
1357c478bd9Sstevel@tonic-gate 	== (oldctx))
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate #elif defined(__amd64)
1387c478bd9Sstevel@tonic-gate #define	FRAME_PTR_REGISTER	REG_RBP
1397c478bd9Sstevel@tonic-gate #define	PC_REGISTER		REG_RIP
1407c478bd9Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
1417c478bd9Sstevel@tonic-gate 	2 * sizeof (long) == (oldctx)) && \
1427c478bd9Sstevel@tonic-gate 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate #elif defined(__i386)
1457c478bd9Sstevel@tonic-gate #define	FRAME_PTR_REGISTER EBP
1467c478bd9Sstevel@tonic-gate #define	PC_REGISTER EIP
1477c478bd9Sstevel@tonic-gate #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
1487c478bd9Sstevel@tonic-gate 	3 * sizeof (int) == (oldctx)) && \
1497c478bd9Sstevel@tonic-gate 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
1507c478bd9Sstevel@tonic-gate #else
1517c478bd9Sstevel@tonic-gate #error no arch defined
1527c478bd9Sstevel@tonic-gate #endif
1537c478bd9Sstevel@tonic-gate 
154f151e4bfSbarts #define	MAX_LINE 2048 /* arbitrary large value */
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * use /proc/self/as to safely dereference pointers so we don't
1587c478bd9Sstevel@tonic-gate  * die in the case of a stack smash
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static int
read_safe(int fd,struct frame * fp,struct frame ** savefp,uintptr_t * savepc)1627c478bd9Sstevel@tonic-gate read_safe(int fd, struct frame *fp, struct frame **savefp, uintptr_t *savepc)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	uintptr_t newfp;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if ((uintptr_t)fp & (sizeof (void *) - 1))
1677c478bd9Sstevel@tonic-gate 		return (-1); /* misaligned */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp),
1707c478bd9Sstevel@tonic-gate 	    (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) ||
1717c478bd9Sstevel@tonic-gate 	    pread(fd, (void *)savepc, sizeof (fp->fr_savpc),
1727c478bd9Sstevel@tonic-gate 	    (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc))
1737c478bd9Sstevel@tonic-gate 		return (-1);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
1767c478bd9Sstevel@tonic-gate 	 * handle stack bias on sparcv9
1777c478bd9Sstevel@tonic-gate 	 */
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	if (newfp != 0)
1807c478bd9Sstevel@tonic-gate 		newfp += STACK_BIAS;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	*savefp = (struct frame *)newfp;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	return (0);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate int
walkcontext(const ucontext_t * uptr,int (* operate_func)(uintptr_t,int,void *),void * usrarg)1887c478bd9Sstevel@tonic-gate walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *),
1897c478bd9Sstevel@tonic-gate     void *usrarg)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	ucontext_t *oldctx = uptr->uc_link;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	int	fd;
1947484d76eSToomas Soome 	int	sig;
1957c478bd9Sstevel@tonic-gate #if defined(__sparc)
1967484d76eSToomas Soome 	int	signo = 0;
1977c478bd9Sstevel@tonic-gate #endif
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	struct frame *savefp;
2007c478bd9Sstevel@tonic-gate 	uintptr_t savepc;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/*
2037c478bd9Sstevel@tonic-gate 	 * snag frame point from ucontext... we'll see caller of
2047c478bd9Sstevel@tonic-gate 	 * getucontext since we'll start by working up the call
2057c478bd9Sstevel@tonic-gate 	 * stack by one
2067c478bd9Sstevel@tonic-gate 	 */
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	struct frame *fp = (struct frame *)
2097c478bd9Sstevel@tonic-gate 	    ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2107c478bd9Sstevel@tonic-gate 	    STACK_BIAS);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * Since we don't write signo to the stack on sparc, we need
2147257d1b4Sraf 	 * to extract signo from the stack frames.
2157257d1b4Sraf 	 * An awkward interface is provided for this purpose:
2167257d1b4Sraf 	 * thr_sighndlrinfo; this is documented in
2177c478bd9Sstevel@tonic-gate 	 * /shared/sac/PSARC/1999/024.  When called, this function
2187c478bd9Sstevel@tonic-gate 	 * returns the PC of a special function (and its size) that
2197c478bd9Sstevel@tonic-gate 	 * will be present in the stack frame if a signal was
2207c478bd9Sstevel@tonic-gate 	 * delivered and will have the following signature
2217c478bd9Sstevel@tonic-gate 	 * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
2227c478bd9Sstevel@tonic-gate 	 *	void (*hndlr)())
2237c478bd9Sstevel@tonic-gate 	 * Since this function is written in assembler and doesn't
2247c478bd9Sstevel@tonic-gate 	 * perturb its registers, we can then read sig out of arg0
2257c478bd9Sstevel@tonic-gate 	 * when the saved pc is inside this function.
2267c478bd9Sstevel@tonic-gate 	 */
2277c478bd9Sstevel@tonic-gate #if defined(__sparc)
2287c478bd9Sstevel@tonic-gate 
2297484d76eSToomas Soome 	uintptr_t special_pc = (uintptr_t)NULL;
2307c478bd9Sstevel@tonic-gate 	int special_size = 0;
2317c478bd9Sstevel@tonic-gate 
2327257d1b4Sraf 	extern void thr_sighndlrinfo(void (**func)(), int *funcsize);
2337c478bd9Sstevel@tonic-gate 
2347257d1b4Sraf 	thr_sighndlrinfo((void (**)())&special_pc, &special_size);
2357c478bd9Sstevel@tonic-gate #endif /* sparc */
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	if ((fd = open("/proc/self/as", O_RDONLY)) < 0)
2397c478bd9Sstevel@tonic-gate 		return (-1);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		sig = 0;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		/*
2467c478bd9Sstevel@tonic-gate 		 * get value of saved fp and pc w/o crashing
2477c478bd9Sstevel@tonic-gate 		 */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		if (read_safe(fd, fp, &savefp, &savepc) != 0) {
2507c478bd9Sstevel@tonic-gate 			(void) close(fd);
2517c478bd9Sstevel@tonic-gate 			return (-1);
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		if (savefp == NULL)
2557c478bd9Sstevel@tonic-gate 			break;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		/*
2587c478bd9Sstevel@tonic-gate 		 * note that the following checks to see if we've got a
2597c478bd9Sstevel@tonic-gate 		 * special signal stack frame present; this allows us to
2607c478bd9Sstevel@tonic-gate 		 * detect signals and pass that info to the user stack walker
2617c478bd9Sstevel@tonic-gate 		 */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		if (oldctx != NULL &&
2647c478bd9Sstevel@tonic-gate 		    CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) {
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
2677c478bd9Sstevel@tonic-gate 			/*
2687c478bd9Sstevel@tonic-gate 			 * i386 and amd64 store signo on stack;
2697c478bd9Sstevel@tonic-gate 			 * simple to detect and use
2707c478bd9Sstevel@tonic-gate 			 */
2717c478bd9Sstevel@tonic-gate 			sig = *((int *)(savefp + 1));
2727c478bd9Sstevel@tonic-gate #endif
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate #if defined(__sparc)
2757c478bd9Sstevel@tonic-gate 			/*
2767c478bd9Sstevel@tonic-gate 			 * In the case of threads, since there are multiple
2777c478bd9Sstevel@tonic-gate 			 * complex routines between kernel and user handler,
2787c478bd9Sstevel@tonic-gate 			 * we need to figure out where we can read signal from
2797257d1b4Sraf 			 * using thr_sighndlrinfo - which we've already done
2807c478bd9Sstevel@tonic-gate 			 * for this signal, since it appeared on the stack
2817c478bd9Sstevel@tonic-gate 			 * before the signal frame.... sigh.
2827c478bd9Sstevel@tonic-gate 			 */
2837257d1b4Sraf 			sig = signo; /* already read - see below */
2847c478bd9Sstevel@tonic-gate #endif
2857c478bd9Sstevel@tonic-gate 			/*
2867c478bd9Sstevel@tonic-gate 			 * this is the special signal frame, so cons up
2877c478bd9Sstevel@tonic-gate 			 * the saved fp & pc to pass to user's function
2887c478bd9Sstevel@tonic-gate 			 */
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 			savefp = (struct frame *)
2917c478bd9Sstevel@tonic-gate 			    ((uintptr_t)oldctx->
2927c478bd9Sstevel@tonic-gate 			    uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2937c478bd9Sstevel@tonic-gate 			    STACK_BIAS);
2947c478bd9Sstevel@tonic-gate 			savepc = oldctx->uc_mcontext.gregs[PC_REGISTER];
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 			oldctx = oldctx->uc_link; /* handle nested signals */
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate #if defined(__sparc)
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		/*
3017c478bd9Sstevel@tonic-gate 		 * lookahead code to find right spot to read signo from...
3027c478bd9Sstevel@tonic-gate 		 */
3037c478bd9Sstevel@tonic-gate 
3047257d1b4Sraf 		if (savepc >= special_pc && savepc <
3057c478bd9Sstevel@tonic-gate 		    (special_pc + special_size))
3067c478bd9Sstevel@tonic-gate 			signo = fp->fr_arg[0];
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 		/*
3107c478bd9Sstevel@tonic-gate 		 * call user-supplied function and quit if non-zero return.
3117c478bd9Sstevel@tonic-gate 		 */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		if (operate_func((uintptr_t)savepc, sig, usrarg) != 0)
3147c478bd9Sstevel@tonic-gate 			break;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 		fp = savefp; /* up one in the call stack */
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	(void) close(fd);
3207c478bd9Sstevel@tonic-gate 	return (0);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
323f151e4bfSbarts /*
324f151e4bfSbarts  * async safe version of fprintf
325f151e4bfSbarts  */
326f151e4bfSbarts 
327f151e4bfSbarts static void
async_filenoprintf(int filenum,const char * format,...)328f151e4bfSbarts async_filenoprintf(int filenum, const char *format, ...)
3297c478bd9Sstevel@tonic-gate {
330f151e4bfSbarts 	va_list ap;
331f151e4bfSbarts 	char buffer[MAX_LINE];
3327c478bd9Sstevel@tonic-gate 
333f151e4bfSbarts 	va_start(ap, format);
334f151e4bfSbarts 	(void) vsnprintf(buffer, sizeof (buffer), format, ap);
335f151e4bfSbarts 	va_end(ap);
3367c478bd9Sstevel@tonic-gate 
337f151e4bfSbarts 	(void) write(filenum, buffer, strlen(buffer));
3387c478bd9Sstevel@tonic-gate 
339f151e4bfSbarts }
3407c478bd9Sstevel@tonic-gate 
341f151e4bfSbarts /*
342f151e4bfSbarts  *  print out stack frame info
343f151e4bfSbarts  */
3447c478bd9Sstevel@tonic-gate 
345f151e4bfSbarts static int
display_stack_info(uintptr_t pc,int signo,void * arg)346f151e4bfSbarts display_stack_info(uintptr_t pc, int signo, void *arg)
347f151e4bfSbarts {
348f151e4bfSbarts 	char buffer[MAX_LINE];
349f151e4bfSbarts 	char sigbuf[SIG2STR_MAX];
350f151e4bfSbarts 
351f151e4bfSbarts 
352f151e4bfSbarts 	int filenum = (intptr_t)arg;
353f151e4bfSbarts 
354f151e4bfSbarts 	(void) addrtosymstr((void *)pc, buffer, sizeof (buffer));
355f151e4bfSbarts 
356f151e4bfSbarts 	if (signo) {
357f151e4bfSbarts 		sigbuf[0] = '?';
358f151e4bfSbarts 		sigbuf[1] = 0;
3597c478bd9Sstevel@tonic-gate 
360f151e4bfSbarts 		(void) sig2str(signo, sigbuf);
3617c478bd9Sstevel@tonic-gate 
362f151e4bfSbarts 		async_filenoprintf(filenum, "%s [Signal %d (%s)]\n",
3637257d1b4Sraf 		    buffer, (ulong_t)signo, sigbuf);
364f151e4bfSbarts 	} else
365f151e4bfSbarts 		async_filenoprintf(filenum, "%s\n", buffer);
366f151e4bfSbarts 
367f151e4bfSbarts 	return (0);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
370f151e4bfSbarts /*
371f151e4bfSbarts  * walk current thread stack, writing symbolic stack trace to specified fd
372f151e4bfSbarts  */
373f151e4bfSbarts 
374f151e4bfSbarts int
printstack(int dofd)375f151e4bfSbarts printstack(int dofd)
3767c478bd9Sstevel@tonic-gate {
377f151e4bfSbarts 	ucontext_t u;
3787c478bd9Sstevel@tonic-gate 
379f151e4bfSbarts 	if (getcontext(&u) < 0)
380f151e4bfSbarts 		return (-1);
3817c478bd9Sstevel@tonic-gate 
382f151e4bfSbarts 	return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd));
383f151e4bfSbarts }
3847c478bd9Sstevel@tonic-gate 
385f151e4bfSbarts /*
386f151e4bfSbarts  * Some routines for better opensource compatibility w/ glibc.
387f151e4bfSbarts  */
3887c478bd9Sstevel@tonic-gate 
389f151e4bfSbarts typedef struct backtrace {
390f151e4bfSbarts 	void	**bt_buffer;
391f151e4bfSbarts 	int	bt_maxcount;
392f151e4bfSbarts 	int	bt_actcount;
393f151e4bfSbarts } backtrace_t;
3947c478bd9Sstevel@tonic-gate 
395f151e4bfSbarts static int
callback(uintptr_t pc,int signo __unused,void * arg)396*4a38094cSToomas Soome callback(uintptr_t pc, int signo __unused, void *arg)
397f151e4bfSbarts {
398f151e4bfSbarts 	backtrace_t *bt = (backtrace_t *)arg;
3997c478bd9Sstevel@tonic-gate 
400f151e4bfSbarts 	if (bt->bt_actcount >= bt->bt_maxcount)
401f151e4bfSbarts 		return (-1);
4027c478bd9Sstevel@tonic-gate 
403f151e4bfSbarts 	bt->bt_buffer[bt->bt_actcount++] = (void *)pc;
4047c478bd9Sstevel@tonic-gate 
405f151e4bfSbarts 	return (0);
406f151e4bfSbarts }
4077c478bd9Sstevel@tonic-gate 
408f151e4bfSbarts /*
409f151e4bfSbarts  * dump stack trace up to length count into buffer
410f151e4bfSbarts  */
411f151e4bfSbarts 
412f151e4bfSbarts int
backtrace(void ** buffer,int count)413f151e4bfSbarts backtrace(void **buffer, int count)
414f151e4bfSbarts {
4157484d76eSToomas Soome 	backtrace_t	bt;
4167484d76eSToomas Soome 	ucontext_t	u;
417f151e4bfSbarts 
418f151e4bfSbarts 	bt.bt_buffer = buffer;
419f151e4bfSbarts 	bt.bt_maxcount = count;
420f151e4bfSbarts 	bt.bt_actcount = 0;
421f151e4bfSbarts 
422f151e4bfSbarts 	if (getcontext(&u) < 0)
423f151e4bfSbarts 		return (0);
4247c478bd9Sstevel@tonic-gate 
425f151e4bfSbarts 	(void) walkcontext(&u, callback, &bt);
4267c478bd9Sstevel@tonic-gate 
427f151e4bfSbarts 	return (bt.bt_actcount);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
430f151e4bfSbarts /*
431f151e4bfSbarts  * format backtrace string
432f151e4bfSbarts  */
433f151e4bfSbarts 
434f151e4bfSbarts int
addrtosymstr(void * pc,char * buffer,int size)435f151e4bfSbarts addrtosymstr(void *pc, char *buffer, int size)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	Dl_info info;
4387c478bd9Sstevel@tonic-gate 	Sym *sym;
4397c478bd9Sstevel@tonic-gate 
440f151e4bfSbarts 	if (dladdr1(pc, &info, (void **)&sym,
441f151e4bfSbarts 	    RTLD_DL_SYMENT) == 0) {
442f151e4bfSbarts 		return (snprintf(buffer, size, "[0x%p]", pc));
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
445f151e4bfSbarts 	if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
446f151e4bfSbarts 	    ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
447f151e4bfSbarts 		/*
448f151e4bfSbarts 		 * we have containing symbol info
449f151e4bfSbarts 		 */
450f151e4bfSbarts 		return (snprintf(buffer, size, "%s'%s+0x%x [0x%p]",
451f151e4bfSbarts 		    info.dli_fname,
452f151e4bfSbarts 		    info.dli_sname,
453f151e4bfSbarts 		    (unsigned long)pc - (unsigned long)info.dli_saddr,
454f151e4bfSbarts 		    pc));
4557c478bd9Sstevel@tonic-gate 	} else {
456f151e4bfSbarts 		/*
457f151e4bfSbarts 		 * no local symbol info
458f151e4bfSbarts 		 */
459f151e4bfSbarts 		return (snprintf(buffer, size, "%s'0x%p [0x%p]",
460f151e4bfSbarts 		    info.dli_fname,
461f151e4bfSbarts 		    (unsigned long)pc - (unsigned long)info.dli_fbase,
462f151e4bfSbarts 		    pc));
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
466f151e4bfSbarts /*
467f151e4bfSbarts  * This function returns the symbolic representation of stack trace; calls
468f151e4bfSbarts  * malloc so it is NOT async safe!  A rather mis-designed and certainly misused
469f151e4bfSbarts  * interface.
470f151e4bfSbarts  */
471f151e4bfSbarts 
472f151e4bfSbarts char **
backtrace_symbols(void * const * array,int size)473f151e4bfSbarts backtrace_symbols(void *const *array, int size)
4747c478bd9Sstevel@tonic-gate {
475f151e4bfSbarts 	int bufferlen, len;
476f151e4bfSbarts 	char **ret_buffer;
477f151e4bfSbarts 	char **ret;
478f151e4bfSbarts 	char linebuffer[MAX_LINE];
479f151e4bfSbarts 	int i;
4807c478bd9Sstevel@tonic-gate 
481f151e4bfSbarts 	bufferlen = size * sizeof (char *);
4827c478bd9Sstevel@tonic-gate 
483f151e4bfSbarts 	/*
484f151e4bfSbarts 	 *  tmp buffer to hold strings while finding all symbol names
485f151e4bfSbarts 	 */
486f151e4bfSbarts 
487f151e4bfSbarts 	ret_buffer = (char **)alloca(bufferlen);
488f151e4bfSbarts 
489f151e4bfSbarts 	for (i = 0; i < size; i++) {
490f151e4bfSbarts 		(void) addrtosymstr(array[i], linebuffer, sizeof (linebuffer));
491f151e4bfSbarts 		ret_buffer[i] = strcpy(alloca(len = strlen(linebuffer) + 1),
492f151e4bfSbarts 		    linebuffer);
493f151e4bfSbarts 		bufferlen += len;
494f151e4bfSbarts 	}
495f151e4bfSbarts 
496f151e4bfSbarts 	/*
497f151e4bfSbarts 	 * allocate total amount of storage required and copy strings
498f151e4bfSbarts 	 */
499f151e4bfSbarts 
500f151e4bfSbarts 	if ((ret = (char **)malloc(bufferlen)) == NULL)
501f151e4bfSbarts 		return (NULL);
502f151e4bfSbarts 
503f151e4bfSbarts 
504f151e4bfSbarts 	for (len = i = 0; i < size; i++) {
505f151e4bfSbarts 		ret[i] = (char *)ret + size * sizeof (char *) + len;
5065ad42b1bSSurya Prakki 		(void) strcpy(ret[i], ret_buffer[i]);
507f151e4bfSbarts 		len += strlen(ret_buffer[i]) + 1;
508f151e4bfSbarts 	}
509f151e4bfSbarts 
510f151e4bfSbarts 	return (ret);
511f151e4bfSbarts }
512f151e4bfSbarts 
513f151e4bfSbarts /*
514f151e4bfSbarts  * Write out symbolic stack trace in an async-safe way.
515f151e4bfSbarts  */
516f151e4bfSbarts 
517f151e4bfSbarts void
backtrace_symbols_fd(void * const * array,int size,int fd)518f151e4bfSbarts backtrace_symbols_fd(void *const *array, int size, int fd)
519f151e4bfSbarts {
520f151e4bfSbarts 	char linebuffer[MAX_LINE];
521f151e4bfSbarts 	int i;
522f151e4bfSbarts 	int len;
523f151e4bfSbarts 
524f151e4bfSbarts 	for (i = 0; i < size; i++) {
525f151e4bfSbarts 		len = addrtosymstr(array[i], linebuffer,
526f151e4bfSbarts 		    sizeof (linebuffer) - 1);
527f151e4bfSbarts 		if (len >= sizeof (linebuffer))
528f151e4bfSbarts 			len = sizeof (linebuffer) - 1;
529f151e4bfSbarts 		linebuffer[len] = '\n';
530f151e4bfSbarts 		(void) write(fd, linebuffer, len + 1);
531f151e4bfSbarts 	}
5327c478bd9Sstevel@tonic-gate }
533