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