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 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 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 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 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 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 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 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 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 ** 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 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