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 *
21*5ad42b1bSSurya 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
1657c478bd9Sstevel@tonic-gate uintptr_t newfp;
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate if ((uintptr_t)fp & (sizeof (void *) - 1))
1687c478bd9Sstevel@tonic-gate return (-1); /* misaligned */
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp),
1717c478bd9Sstevel@tonic-gate (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) ||
1727c478bd9Sstevel@tonic-gate pread(fd, (void *)savepc, sizeof (fp->fr_savpc),
1737c478bd9Sstevel@tonic-gate (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc))
1747c478bd9Sstevel@tonic-gate return (-1);
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate * handle stack bias on sparcv9
1787c478bd9Sstevel@tonic-gate */
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate if (newfp != 0)
1817c478bd9Sstevel@tonic-gate newfp += STACK_BIAS;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate *savefp = (struct frame *)newfp;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate return (0);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate int
walkcontext(const ucontext_t * uptr,int (* operate_func)(uintptr_t,int,void *),void * usrarg)1897c478bd9Sstevel@tonic-gate walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *),
1907c478bd9Sstevel@tonic-gate void *usrarg)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate ucontext_t *oldctx = uptr->uc_link;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate int fd;
1957c478bd9Sstevel@tonic-gate int sig;
1967c478bd9Sstevel@tonic-gate #if defined(__sparc)
1977c478bd9Sstevel@tonic-gate int signo = 0;
1987c478bd9Sstevel@tonic-gate #endif
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate struct frame *savefp;
2017c478bd9Sstevel@tonic-gate uintptr_t savepc;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate * snag frame point from ucontext... we'll see caller of
2057c478bd9Sstevel@tonic-gate * getucontext since we'll start by working up the call
2067c478bd9Sstevel@tonic-gate * stack by one
2077c478bd9Sstevel@tonic-gate */
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate struct frame *fp = (struct frame *)
2107c478bd9Sstevel@tonic-gate ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2117c478bd9Sstevel@tonic-gate STACK_BIAS);
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate * Since we don't write signo to the stack on sparc, we need
2157257d1b4Sraf * to extract signo from the stack frames.
2167257d1b4Sraf * An awkward interface is provided for this purpose:
2177257d1b4Sraf * thr_sighndlrinfo; this is documented in
2187c478bd9Sstevel@tonic-gate * /shared/sac/PSARC/1999/024. When called, this function
2197c478bd9Sstevel@tonic-gate * returns the PC of a special function (and its size) that
2207c478bd9Sstevel@tonic-gate * will be present in the stack frame if a signal was
2217c478bd9Sstevel@tonic-gate * delivered and will have the following signature
2227c478bd9Sstevel@tonic-gate * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
2237c478bd9Sstevel@tonic-gate * void (*hndlr)())
2247c478bd9Sstevel@tonic-gate * Since this function is written in assembler and doesn't
2257c478bd9Sstevel@tonic-gate * perturb its registers, we can then read sig out of arg0
2267c478bd9Sstevel@tonic-gate * when the saved pc is inside this function.
2277c478bd9Sstevel@tonic-gate */
2287c478bd9Sstevel@tonic-gate #if defined(__sparc)
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate uintptr_t special_pc = NULL;
2317c478bd9Sstevel@tonic-gate int special_size = 0;
2327c478bd9Sstevel@tonic-gate
2337257d1b4Sraf extern void thr_sighndlrinfo(void (**func)(), int *funcsize);
2347c478bd9Sstevel@tonic-gate
2357257d1b4Sraf thr_sighndlrinfo((void (**)())&special_pc, &special_size);
2367c478bd9Sstevel@tonic-gate #endif /* sparc */
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate if ((fd = open("/proc/self/as", O_RDONLY)) < 0)
2407c478bd9Sstevel@tonic-gate return (-1);
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate while (fp != NULL) {
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate sig = 0;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate * get value of saved fp and pc w/o crashing
2487c478bd9Sstevel@tonic-gate */
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate if (read_safe(fd, fp, &savefp, &savepc) != 0) {
2517c478bd9Sstevel@tonic-gate (void) close(fd);
2527c478bd9Sstevel@tonic-gate return (-1);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate if (savefp == NULL)
2567c478bd9Sstevel@tonic-gate break;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate * note that the following checks to see if we've got a
2607c478bd9Sstevel@tonic-gate * special signal stack frame present; this allows us to
2617c478bd9Sstevel@tonic-gate * detect signals and pass that info to the user stack walker
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate if (oldctx != NULL &&
2657c478bd9Sstevel@tonic-gate CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) {
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate * i386 and amd64 store signo on stack;
2707c478bd9Sstevel@tonic-gate * simple to detect and use
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@tonic-gate sig = *((int *)(savefp + 1));
2737c478bd9Sstevel@tonic-gate #endif
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate #if defined(__sparc)
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate * In the case of threads, since there are multiple
2787c478bd9Sstevel@tonic-gate * complex routines between kernel and user handler,
2797c478bd9Sstevel@tonic-gate * we need to figure out where we can read signal from
2807257d1b4Sraf * using thr_sighndlrinfo - which we've already done
2817c478bd9Sstevel@tonic-gate * for this signal, since it appeared on the stack
2827c478bd9Sstevel@tonic-gate * before the signal frame.... sigh.
2837c478bd9Sstevel@tonic-gate */
2847c478bd9Sstevel@tonic-gate sig = signo; /* already read - see below */
2857c478bd9Sstevel@tonic-gate #endif
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate * this is the special signal frame, so cons up
2887c478bd9Sstevel@tonic-gate * the saved fp & pc to pass to user's function
2897c478bd9Sstevel@tonic-gate */
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate savefp = (struct frame *)
2927c478bd9Sstevel@tonic-gate ((uintptr_t)oldctx->
2937c478bd9Sstevel@tonic-gate uc_mcontext.gregs[FRAME_PTR_REGISTER] +
2947c478bd9Sstevel@tonic-gate STACK_BIAS);
2957c478bd9Sstevel@tonic-gate savepc = oldctx->uc_mcontext.gregs[PC_REGISTER];
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate oldctx = oldctx->uc_link; /* handle nested signals */
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate #if defined(__sparc)
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate * lookahead code to find right spot to read signo from...
3037c478bd9Sstevel@tonic-gate */
3047c478bd9Sstevel@tonic-gate
3057257d1b4Sraf if (savepc >= special_pc && savepc <
3067c478bd9Sstevel@tonic-gate (special_pc + special_size))
3077c478bd9Sstevel@tonic-gate signo = fp->fr_arg[0];
3087c478bd9Sstevel@tonic-gate #endif
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate * call user-supplied function and quit if non-zero return.
3127c478bd9Sstevel@tonic-gate */
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate if (operate_func((uintptr_t)savepc, sig, usrarg) != 0)
3157c478bd9Sstevel@tonic-gate break;
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate fp = savefp; /* up one in the call stack */
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate (void) close(fd);
3217c478bd9Sstevel@tonic-gate return (0);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
324f151e4bfSbarts /*
325f151e4bfSbarts * async safe version of fprintf
326f151e4bfSbarts */
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate static void
async_filenoprintf(int filenum,const char * format,...)3297c478bd9Sstevel@tonic-gate async_filenoprintf(int filenum, const char *format, ...)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate va_list ap;
332f151e4bfSbarts char buffer[MAX_LINE];
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate va_start(ap, format);
335f151e4bfSbarts (void) vsnprintf(buffer, sizeof (buffer), format, ap);
3367c478bd9Sstevel@tonic-gate va_end(ap);
3377c478bd9Sstevel@tonic-gate
338f151e4bfSbarts (void) write(filenum, buffer, strlen(buffer));
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
342f151e4bfSbarts /*
343f151e4bfSbarts * print out stack frame info
344f151e4bfSbarts */
345f151e4bfSbarts
3467c478bd9Sstevel@tonic-gate static int
display_stack_info(uintptr_t pc,int signo,void * arg)3477c478bd9Sstevel@tonic-gate display_stack_info(uintptr_t pc, int signo, void *arg)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate
350f151e4bfSbarts char buffer[MAX_LINE];
3517c478bd9Sstevel@tonic-gate char sigbuf[SIG2STR_MAX];
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate int filenum = (intptr_t)arg;
3557c478bd9Sstevel@tonic-gate
356f151e4bfSbarts (void) addrtosymstr((void *)pc, buffer, sizeof (buffer));
357f151e4bfSbarts
3587c478bd9Sstevel@tonic-gate if (signo) {
359f151e4bfSbarts sigbuf[0] = '?';
360f151e4bfSbarts sigbuf[1] = 0;
3617c478bd9Sstevel@tonic-gate
362f151e4bfSbarts (void) sig2str(signo, sigbuf);
3637c478bd9Sstevel@tonic-gate
364f151e4bfSbarts async_filenoprintf(filenum, "%s [Signal %d (%s)]\n",
365f151e4bfSbarts buffer, (ulong_t)signo, sigbuf);
366f151e4bfSbarts } else
367f151e4bfSbarts async_filenoprintf(filenum, "%s\n", buffer);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate return (0);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate
372f151e4bfSbarts /*
373f151e4bfSbarts * walk current thread stack, writing symbolic stack trace to specified fd
374f151e4bfSbarts */
375f151e4bfSbarts
3767c478bd9Sstevel@tonic-gate int
printstack(int dofd)3777c478bd9Sstevel@tonic-gate printstack(int dofd)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate ucontext_t u;
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate if (getcontext(&u) < 0)
3827c478bd9Sstevel@tonic-gate return (-1);
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd));
3857c478bd9Sstevel@tonic-gate }
386f151e4bfSbarts
387f151e4bfSbarts /*
388f151e4bfSbarts * Some routines for better opensource compatibility w/ glibc.
389f151e4bfSbarts */
390f151e4bfSbarts
391f151e4bfSbarts typedef struct backtrace {
392f151e4bfSbarts void **bt_buffer;
393f151e4bfSbarts int bt_maxcount;
394f151e4bfSbarts int bt_actcount;
395f151e4bfSbarts } backtrace_t;
396f151e4bfSbarts
397f151e4bfSbarts /* ARGSUSED */
398f151e4bfSbarts static int
callback(uintptr_t pc,int signo,void * arg)399f151e4bfSbarts callback(uintptr_t pc, int signo, void *arg)
400f151e4bfSbarts {
401f151e4bfSbarts backtrace_t *bt = (backtrace_t *)arg;
402f151e4bfSbarts
403f151e4bfSbarts if (bt->bt_actcount >= bt->bt_maxcount)
404f151e4bfSbarts return (-1);
405f151e4bfSbarts
406f151e4bfSbarts bt->bt_buffer[bt->bt_actcount++] = (void *)pc;
407f151e4bfSbarts
408f151e4bfSbarts return (0);
409f151e4bfSbarts }
410f151e4bfSbarts
411f151e4bfSbarts /*
412f151e4bfSbarts * dump stack trace up to length count into buffer
413f151e4bfSbarts */
414f151e4bfSbarts
415f151e4bfSbarts int
backtrace(void ** buffer,int count)416f151e4bfSbarts backtrace(void **buffer, int count)
417f151e4bfSbarts {
418f151e4bfSbarts backtrace_t bt;
419f151e4bfSbarts ucontext_t u;
420f151e4bfSbarts
421f151e4bfSbarts bt.bt_buffer = buffer;
422f151e4bfSbarts bt.bt_maxcount = count;
423f151e4bfSbarts bt.bt_actcount = 0;
424f151e4bfSbarts
425f151e4bfSbarts if (getcontext(&u) < 0)
426f151e4bfSbarts return (0);
427f151e4bfSbarts
428f151e4bfSbarts (void) walkcontext(&u, callback, &bt);
429f151e4bfSbarts
430f151e4bfSbarts return (bt.bt_actcount);
431f151e4bfSbarts }
432f151e4bfSbarts
433f151e4bfSbarts /*
434f151e4bfSbarts * format backtrace string
435f151e4bfSbarts */
436f151e4bfSbarts
437f151e4bfSbarts int
addrtosymstr(void * pc,char * buffer,int size)438f151e4bfSbarts addrtosymstr(void *pc, char *buffer, int size)
439f151e4bfSbarts {
440f151e4bfSbarts Dl_info info;
441f151e4bfSbarts Sym *sym;
442f151e4bfSbarts
443f151e4bfSbarts if (dladdr1(pc, &info, (void **)&sym,
444f151e4bfSbarts RTLD_DL_SYMENT) == 0) {
445f151e4bfSbarts return (snprintf(buffer, size, "[0x%p]", pc));
446f151e4bfSbarts }
447f151e4bfSbarts
448f151e4bfSbarts if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
449f151e4bfSbarts ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
450f151e4bfSbarts /*
451f151e4bfSbarts * we have containing symbol info
452f151e4bfSbarts */
453f151e4bfSbarts return (snprintf(buffer, size, "%s'%s+0x%x [0x%p]",
454f151e4bfSbarts info.dli_fname,
455f151e4bfSbarts info.dli_sname,
456f151e4bfSbarts (unsigned long)pc - (unsigned long)info.dli_saddr,
457f151e4bfSbarts pc));
458f151e4bfSbarts } else {
459f151e4bfSbarts /*
460f151e4bfSbarts * no local symbol info
461f151e4bfSbarts */
462f151e4bfSbarts return (snprintf(buffer, size, "%s'0x%p [0x%p]",
463f151e4bfSbarts info.dli_fname,
464f151e4bfSbarts (unsigned long)pc - (unsigned long)info.dli_fbase,
465f151e4bfSbarts pc));
466f151e4bfSbarts }
467f151e4bfSbarts }
468f151e4bfSbarts
469f151e4bfSbarts /*
470f151e4bfSbarts * This function returns the symbolic representation of stack trace; calls
471f151e4bfSbarts * malloc so it is NOT async safe! A rather mis-designed and certainly misused
472f151e4bfSbarts * interface.
473f151e4bfSbarts */
474f151e4bfSbarts
475f151e4bfSbarts char **
backtrace_symbols(void * const * array,int size)476f151e4bfSbarts backtrace_symbols(void *const *array, int size)
477f151e4bfSbarts {
478f151e4bfSbarts int bufferlen, len;
479f151e4bfSbarts char **ret_buffer;
480f151e4bfSbarts char **ret;
481f151e4bfSbarts char linebuffer[MAX_LINE];
482f151e4bfSbarts int i;
483f151e4bfSbarts
484f151e4bfSbarts bufferlen = size * sizeof (char *);
485f151e4bfSbarts
486f151e4bfSbarts /*
487f151e4bfSbarts * tmp buffer to hold strings while finding all symbol names
488f151e4bfSbarts */
489f151e4bfSbarts
490f151e4bfSbarts ret_buffer = (char **)alloca(bufferlen);
491f151e4bfSbarts
492f151e4bfSbarts for (i = 0; i < size; i++) {
493f151e4bfSbarts (void) addrtosymstr(array[i], linebuffer, sizeof (linebuffer));
494f151e4bfSbarts ret_buffer[i] = strcpy(alloca(len = strlen(linebuffer) + 1),
495f151e4bfSbarts linebuffer);
496f151e4bfSbarts bufferlen += len;
497f151e4bfSbarts }
498f151e4bfSbarts
499f151e4bfSbarts /*
500f151e4bfSbarts * allocate total amount of storage required and copy strings
501f151e4bfSbarts */
502f151e4bfSbarts
503f151e4bfSbarts if ((ret = (char **)malloc(bufferlen)) == NULL)
504f151e4bfSbarts return (NULL);
505f151e4bfSbarts
506f151e4bfSbarts
507f151e4bfSbarts for (len = i = 0; i < size; i++) {
508f151e4bfSbarts ret[i] = (char *)ret + size * sizeof (char *) + len;
509*5ad42b1bSSurya Prakki (void) strcpy(ret[i], ret_buffer[i]);
510f151e4bfSbarts len += strlen(ret_buffer[i]) + 1;
511f151e4bfSbarts }
512f151e4bfSbarts
513f151e4bfSbarts return (ret);
514f151e4bfSbarts }
515f151e4bfSbarts
516f151e4bfSbarts /*
517f151e4bfSbarts * Write out symbolic stack trace in an async-safe way.
518f151e4bfSbarts */
519f151e4bfSbarts
520f151e4bfSbarts void
backtrace_symbols_fd(void * const * array,int size,int fd)521f151e4bfSbarts backtrace_symbols_fd(void *const *array, int size, int fd)
522f151e4bfSbarts {
523f151e4bfSbarts char linebuffer[MAX_LINE];
524f151e4bfSbarts int i;
525f151e4bfSbarts int len;
526f151e4bfSbarts
527f151e4bfSbarts for (i = 0; i < size; i++) {
528f151e4bfSbarts len = addrtosymstr(array[i], linebuffer,
529f151e4bfSbarts sizeof (linebuffer) - 1);
530f151e4bfSbarts if (len >= sizeof (linebuffer))
531f151e4bfSbarts len = sizeof (linebuffer) - 1;
532f151e4bfSbarts linebuffer[len] = '\n';
533f151e4bfSbarts (void) write(fd, linebuffer, len + 1);
534f151e4bfSbarts }
535f151e4bfSbarts }
536