1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate * 22*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23*0Sstevel@tonic-gate * Use is subject to license terms. 24*0Sstevel@tonic-gate */ 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate /* 29*0Sstevel@tonic-gate * This file provides a general purpose mechanism 30*0Sstevel@tonic-gate * for a user thread to walk its own call stack, 31*0Sstevel@tonic-gate * calling a user-specified iterator function for each 32*0Sstevel@tonic-gate * stack frame. Special handling is provided to indicate 33*0Sstevel@tonic-gate * kernel-constructed signal handler frames. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * Adapted from usr/src/lib/libproc/common/Pstack.c: 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * A signal handler frame is essentially a set of data pushed on to the user 38*0Sstevel@tonic-gate * stack by the kernel prior to returning to the user program in one of the 39*0Sstevel@tonic-gate * pre-defined signal handlers. The signal handler itself receives the signal 40*0Sstevel@tonic-gate * number, an optional pointer to a siginfo_t, and a pointer to the interrupted 41*0Sstevel@tonic-gate * ucontext as arguments. 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * When performing a stack backtrace, we would like to 44*0Sstevel@tonic-gate * detect these frames so that we can correctly return the interrupted program 45*0Sstevel@tonic-gate * counter and frame pointer as a separate frame. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * The stack layout for a signal handler frame is as follows: 48*0Sstevel@tonic-gate * 49*0Sstevel@tonic-gate * SPARC v7/v9: Intel ia32: 50*0Sstevel@tonic-gate * +--------------+ - high +--------------+ - 51*0Sstevel@tonic-gate * | struct fq | ^ addrs | siginfo_t | optional 52*0Sstevel@tonic-gate * +--------------+ | ^ +--------------+ - 53*0Sstevel@tonic-gate * | gwindows_t | | | ucontext_t | ^ 54*0Sstevel@tonic-gate * +--------------+ optional +--------------+ | 55*0Sstevel@tonic-gate * | siginfo_t | | ucontext_t * | | 56*0Sstevel@tonic-gate * +--------------+ | | +--------------+ 57*0Sstevel@tonic-gate * | xregs data | v v | siginfo_t * | mandatory 58*0Sstevel@tonic-gate * +--------------+ - low +--------------+ 59*0Sstevel@tonic-gate * | ucontext_t | ^ addrs | int (signo) | | 60*0Sstevel@tonic-gate * +--------------+ mandatory +--------------+ | 61*0Sstevel@tonic-gate * | struct frame | v | struct frame | v 62*0Sstevel@tonic-gate * +--------------+ - <- %sp on resume +--------------+ - <- %esp on resume 63*0Sstevel@tonic-gate * 64*0Sstevel@tonic-gate * amd64 (64-bit) 65*0Sstevel@tonic-gate * +--------------+ - 66*0Sstevel@tonic-gate * | siginfo_t | optional 67*0Sstevel@tonic-gate * +--------------+ - 68*0Sstevel@tonic-gate * | ucontext_t | ^ 69*0Sstevel@tonic-gate * +--------------+ | 70*0Sstevel@tonic-gate * | siginfo_t * | 71*0Sstevel@tonic-gate * +--------------+ mandatory 72*0Sstevel@tonic-gate * | int (signo) | 73*0Sstevel@tonic-gate * +--------------+ | 74*0Sstevel@tonic-gate * | struct frame | v 75*0Sstevel@tonic-gate * +--------------+ - <- %rsp on resume 76*0Sstevel@tonic-gate * 77*0Sstevel@tonic-gate * The bottom-most struct frame is actually constructed by the kernel by 78*0Sstevel@tonic-gate * copying the previous stack frame, allowing naive backtrace code to simply 79*0Sstevel@tonic-gate * skip over the interrupted frame. The copied frame is never really used, 80*0Sstevel@tonic-gate * since it is presumed the libc or libthread signal handler wrapper function 81*0Sstevel@tonic-gate * will explicitly setcontext(2) to the interrupted context if the user 82*0Sstevel@tonic-gate * program's handler returns. If we detect a signal handler frame, we simply 83*0Sstevel@tonic-gate * read the interrupted context structure from the stack, use its embedded 84*0Sstevel@tonic-gate * gregs to construct the register set for the interrupted frame, and then 85*0Sstevel@tonic-gate * continue our backtrace. Detecting the frame itself is easy according to 86*0Sstevel@tonic-gate * the diagram ("oldcontext" represents any element in the uc_link chain): 87*0Sstevel@tonic-gate * 88*0Sstevel@tonic-gate * On SPARC v7 or v9: 89*0Sstevel@tonic-gate * %fp + sizeof (struct frame) == oldcontext 90*0Sstevel@tonic-gate * 91*0Sstevel@tonic-gate * On i386: 92*0Sstevel@tonic-gate * %ebp + sizeof (struct frame) + (3 words) == oldcontext 93*0Sstevel@tonic-gate * 94*0Sstevel@tonic-gate * On amd64: 95*0Sstevel@tonic-gate * %rbp + sizeof (struct frame) + (2 words) == oldcontext 96*0Sstevel@tonic-gate * 97*0Sstevel@tonic-gate * Since we want to provide the signal number that generated a signal stack 98*0Sstevel@tonic-gate * frame and on sparc this information isn't written to the stack by the kernel 99*0Sstevel@tonic-gate * the way it's done on i386, we're forced to read the signo from the stack as 100*0Sstevel@tonic-gate * one of the arguments to the signal handler. What we hope is that no one has 101*0Sstevel@tonic-gate * used __sigaction directly; if we're not linked with libthread 102*0Sstevel@tonic-gate * (_thr_sighndlrinfo is NULL) then we attempt to read the signo directly from 103*0Sstevel@tonic-gate * the register window. Otherwise we use the _thr_sighndlrinfo interface to find 104*0Sstevel@tonic-gate * the correct frame. 105*0Sstevel@tonic-gate * 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate #pragma weak walkcontext = _walkcontext 109*0Sstevel@tonic-gate #pragma weak printstack = _printstack 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate #include "synonyms.h" 112*0Sstevel@tonic-gate #include <assert.h> 113*0Sstevel@tonic-gate #include <dlfcn.h> 114*0Sstevel@tonic-gate #include <fcntl.h> 115*0Sstevel@tonic-gate #include <link.h> 116*0Sstevel@tonic-gate #include <procfs.h> 117*0Sstevel@tonic-gate #include <strings.h> 118*0Sstevel@tonic-gate #include <signal.h> 119*0Sstevel@tonic-gate #include <sys/frame.h> 120*0Sstevel@tonic-gate #include <sys/regset.h> 121*0Sstevel@tonic-gate #include <sys/types.h> 122*0Sstevel@tonic-gate #include <sys/uio.h> 123*0Sstevel@tonic-gate #include <thread.h> 124*0Sstevel@tonic-gate #include <ucontext.h> 125*0Sstevel@tonic-gate #include <unistd.h> 126*0Sstevel@tonic-gate #include <stdarg.h> 127*0Sstevel@tonic-gate #include <sys/stack.h> 128*0Sstevel@tonic-gate #include <errno.h> 129*0Sstevel@tonic-gate #include <stdio.h> 130*0Sstevel@tonic-gate #include <alloca.h> 131*0Sstevel@tonic-gate #include <limits.h> 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate #ifdef _LP64 134*0Sstevel@tonic-gate #define _ELF64 135*0Sstevel@tonic-gate #endif 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate #include <sys/machelf.h> 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate #if defined(__sparc) 141*0Sstevel@tonic-gate #define FRAME_PTR_REGISTER REG_SP 142*0Sstevel@tonic-gate #define PC_REGISTER REG_PC 143*0Sstevel@tonic-gate #define CHECK_FOR_SIGFRAME(fp, oldctx) ((fp) + SA(sizeof (struct frame)) \ 144*0Sstevel@tonic-gate == (oldctx)) 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate #elif defined(__amd64) 147*0Sstevel@tonic-gate #define FRAME_PTR_REGISTER REG_RBP 148*0Sstevel@tonic-gate #define PC_REGISTER REG_RIP 149*0Sstevel@tonic-gate #define CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \ 150*0Sstevel@tonic-gate 2 * sizeof (long) == (oldctx)) && \ 151*0Sstevel@tonic-gate (((struct frame *)fp)->fr_savpc == (greg_t)-1)) 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate #elif defined(__i386) 154*0Sstevel@tonic-gate #define FRAME_PTR_REGISTER EBP 155*0Sstevel@tonic-gate #define PC_REGISTER EIP 156*0Sstevel@tonic-gate #define CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \ 157*0Sstevel@tonic-gate 3 * sizeof (int) == (oldctx)) && \ 158*0Sstevel@tonic-gate (((struct frame *)fp)->fr_savpc == (greg_t)-1)) 159*0Sstevel@tonic-gate #else 160*0Sstevel@tonic-gate #error no arch defined 161*0Sstevel@tonic-gate #endif 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * use /proc/self/as to safely dereference pointers so we don't 166*0Sstevel@tonic-gate * die in the case of a stack smash 167*0Sstevel@tonic-gate */ 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate static int 170*0Sstevel@tonic-gate read_safe(int fd, struct frame *fp, struct frame **savefp, uintptr_t *savepc) 171*0Sstevel@tonic-gate { 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate uintptr_t newfp; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if ((uintptr_t)fp & (sizeof (void *) - 1)) 176*0Sstevel@tonic-gate return (-1); /* misaligned */ 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp), 179*0Sstevel@tonic-gate (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) || 180*0Sstevel@tonic-gate pread(fd, (void *)savepc, sizeof (fp->fr_savpc), 181*0Sstevel@tonic-gate (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc)) 182*0Sstevel@tonic-gate return (-1); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * handle stack bias on sparcv9 186*0Sstevel@tonic-gate */ 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate if (newfp != 0) 189*0Sstevel@tonic-gate newfp += STACK_BIAS; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate *savefp = (struct frame *)newfp; 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate return (0); 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate int 197*0Sstevel@tonic-gate walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *), 198*0Sstevel@tonic-gate void *usrarg) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate ucontext_t *oldctx = uptr->uc_link; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate int fd; 203*0Sstevel@tonic-gate int sig; 204*0Sstevel@tonic-gate #if defined(__sparc) 205*0Sstevel@tonic-gate int signo = 0; 206*0Sstevel@tonic-gate #endif 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate struct frame *savefp; 209*0Sstevel@tonic-gate uintptr_t savepc; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * snag frame point from ucontext... we'll see caller of 213*0Sstevel@tonic-gate * getucontext since we'll start by working up the call 214*0Sstevel@tonic-gate * stack by one 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate struct frame *fp = (struct frame *) 218*0Sstevel@tonic-gate ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] + 219*0Sstevel@tonic-gate STACK_BIAS); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Since we don't write signo to the stack on sparc, we need 223*0Sstevel@tonic-gate * to extract signo from the stack frames. This is problematic 224*0Sstevel@tonic-gate * in the case of libthread (libc has deterministic behavior) 225*0Sstevel@tonic-gate * since we're not sure where we can do that safely. An awkward 226*0Sstevel@tonic-gate * interface was provided for this purpose in libthread: 227*0Sstevel@tonic-gate * _thr_sighndlrinfo; this is documented in 228*0Sstevel@tonic-gate * /shared/sac/PSARC/1999/024. When called, this function 229*0Sstevel@tonic-gate * returns the PC of a special function (and its size) that 230*0Sstevel@tonic-gate * will be present in the stack frame if a signal was 231*0Sstevel@tonic-gate * delivered and will have the following signature 232*0Sstevel@tonic-gate * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc, 233*0Sstevel@tonic-gate * void (*hndlr)()) 234*0Sstevel@tonic-gate * Since this function is written in assembler and doesn't 235*0Sstevel@tonic-gate * perturb its registers, we can then read sig out of arg0 236*0Sstevel@tonic-gate * when the saved pc is inside this function. 237*0Sstevel@tonic-gate * 238*0Sstevel@tonic-gate */ 239*0Sstevel@tonic-gate #if defined(__sparc) 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate uintptr_t special_pc = NULL; 242*0Sstevel@tonic-gate int special_size = 0; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate extern void _thr_sighndlrinfo(void (**func)(), int *funcsize); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate #pragma weak _thr_sighndlrinfo 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate if (_thr_sighndlrinfo != NULL) { 249*0Sstevel@tonic-gate _thr_sighndlrinfo((void (**)())&special_pc, &special_size); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate #endif /* sparc */ 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate if ((fd = open("/proc/self/as", O_RDONLY)) < 0) 255*0Sstevel@tonic-gate return (-1); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate while (fp != NULL) { 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate sig = 0; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * get value of saved fp and pc w/o crashing 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate if (read_safe(fd, fp, &savefp, &savepc) != 0) { 266*0Sstevel@tonic-gate (void) close(fd); 267*0Sstevel@tonic-gate return (-1); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate if (savefp == NULL) 271*0Sstevel@tonic-gate break; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * note that the following checks to see if we've got a 275*0Sstevel@tonic-gate * special signal stack frame present; this allows us to 276*0Sstevel@tonic-gate * detect signals and pass that info to the user stack walker 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (oldctx != NULL && 280*0Sstevel@tonic-gate CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) { 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 283*0Sstevel@tonic-gate /* 284*0Sstevel@tonic-gate * i386 and amd64 store signo on stack; 285*0Sstevel@tonic-gate * simple to detect and use 286*0Sstevel@tonic-gate */ 287*0Sstevel@tonic-gate sig = *((int *)(savefp + 1)); 288*0Sstevel@tonic-gate #endif 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate #if defined(__sparc) 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * with sparc we need to handle 293*0Sstevel@tonic-gate * single and multi-threaded cases 294*0Sstevel@tonic-gate * separately 295*0Sstevel@tonic-gate * If we're single threaded, the trampoline 296*0Sstevel@tonic-gate * in libc will have the signo as the first 297*0Sstevel@tonic-gate * argumment; we can snag that directly. 298*0Sstevel@tonic-gate * In the case of threads, since there are multiple 299*0Sstevel@tonic-gate * complex routines between kernel and user handler, 300*0Sstevel@tonic-gate * we need to figure out where we can read signal from 301*0Sstevel@tonic-gate * using _thr_sighndlrinfo - which we've already done 302*0Sstevel@tonic-gate * for this signal, since it appeared on the stack 303*0Sstevel@tonic-gate * before the signal frame.... sigh. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate if (_thr_sighndlrinfo == NULL) /* single threaded */ 307*0Sstevel@tonic-gate sig = fp->fr_arg[0]; 308*0Sstevel@tonic-gate else 309*0Sstevel@tonic-gate sig = signo; /* already read - see below */ 310*0Sstevel@tonic-gate #endif 311*0Sstevel@tonic-gate /* 312*0Sstevel@tonic-gate * this is the special signal frame, so cons up 313*0Sstevel@tonic-gate * the saved fp & pc to pass to user's function 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate savefp = (struct frame *) 317*0Sstevel@tonic-gate ((uintptr_t)oldctx-> 318*0Sstevel@tonic-gate uc_mcontext.gregs[FRAME_PTR_REGISTER] + 319*0Sstevel@tonic-gate STACK_BIAS); 320*0Sstevel@tonic-gate savepc = oldctx->uc_mcontext.gregs[PC_REGISTER]; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate oldctx = oldctx->uc_link; /* handle nested signals */ 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate #if defined(__sparc) 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate * lookahead code to find right spot to read signo from... 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (_thr_sighndlrinfo && 331*0Sstevel@tonic-gate savepc >= special_pc && savepc < 332*0Sstevel@tonic-gate (special_pc + special_size)) 333*0Sstevel@tonic-gate signo = fp->fr_arg[0]; 334*0Sstevel@tonic-gate #endif 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * call user-supplied function and quit if non-zero return. 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate if (operate_func((uintptr_t)savepc, sig, usrarg) != 0) 341*0Sstevel@tonic-gate break; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate fp = savefp; /* up one in the call stack */ 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate (void) close(fd); 347*0Sstevel@tonic-gate return (0); 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate static size_t 351*0Sstevel@tonic-gate ulongtos(char *buffer, unsigned long x, int base) 352*0Sstevel@tonic-gate { 353*0Sstevel@tonic-gate char local[80]; 354*0Sstevel@tonic-gate static const char digits[] = "0123456789abcdef"; 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate unsigned int n = sizeof (local) - 1; 357*0Sstevel@tonic-gate unsigned long rem; 358*0Sstevel@tonic-gate unsigned int mod; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate local[n] = 0; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate rem = x; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate do { 365*0Sstevel@tonic-gate switch (base) { 366*0Sstevel@tonic-gate case 10: 367*0Sstevel@tonic-gate mod = rem % 10; 368*0Sstevel@tonic-gate rem = rem / 10; 369*0Sstevel@tonic-gate break; 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate case 16: 372*0Sstevel@tonic-gate mod = rem & 15; 373*0Sstevel@tonic-gate rem = rem >> 4; 374*0Sstevel@tonic-gate break; 375*0Sstevel@tonic-gate default: 376*0Sstevel@tonic-gate return (0); 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate local[--n] = digits[mod]; 379*0Sstevel@tonic-gate } while (rem != 0); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate (void) strcpy(buffer, local + n); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate return (sizeof (local) - n - 1); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate static void 387*0Sstevel@tonic-gate async_filenoprintf(int filenum, const char *format, ...) 388*0Sstevel@tonic-gate { 389*0Sstevel@tonic-gate const char *src = format; 390*0Sstevel@tonic-gate va_list ap; 391*0Sstevel@tonic-gate long i; 392*0Sstevel@tonic-gate struct iovec *iov; 393*0Sstevel@tonic-gate int cnt; 394*0Sstevel@tonic-gate int iter = 0; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * count # of %'s.. max # of iovs is 2n + 1 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate for (cnt = i = 0; src[i] != '\0'; i++) 401*0Sstevel@tonic-gate if (src[i] == '%') 402*0Sstevel@tonic-gate cnt++; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate iov = alloca((2 * cnt + 1) * sizeof (struct iovec)); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate va_start(ap, format); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate while (*src) { 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate iov[iter].iov_base = (char *)src; 412*0Sstevel@tonic-gate iov[iter].iov_len = 0; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate while (*src && *src != '%') { 415*0Sstevel@tonic-gate iov[iter].iov_len++; 416*0Sstevel@tonic-gate src++; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (iov[iter].iov_len != 0) 420*0Sstevel@tonic-gate iter++; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (*src == '%') { 423*0Sstevel@tonic-gate switch (*++src) { 424*0Sstevel@tonic-gate case 's': 425*0Sstevel@tonic-gate iov[iter].iov_base = va_arg(ap, char *); 426*0Sstevel@tonic-gate iov[iter].iov_len = strlen(iov[iter].iov_base); 427*0Sstevel@tonic-gate iter++; 428*0Sstevel@tonic-gate break; 429*0Sstevel@tonic-gate case 'd': 430*0Sstevel@tonic-gate iov[iter].iov_base = alloca(24); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate i = va_arg(ap, long); 433*0Sstevel@tonic-gate if (i < 0) { 434*0Sstevel@tonic-gate *iov[iter].iov_base = '-'; 435*0Sstevel@tonic-gate iov[iter].iov_len = 436*0Sstevel@tonic-gate ulongtos(iov[iter].iov_base + 1, 437*0Sstevel@tonic-gate -i, 10) + 1; 438*0Sstevel@tonic-gate } else 439*0Sstevel@tonic-gate iov[iter].iov_len = 440*0Sstevel@tonic-gate ulongtos(iov[iter].iov_base, 441*0Sstevel@tonic-gate i, 10); 442*0Sstevel@tonic-gate iter++; 443*0Sstevel@tonic-gate break; 444*0Sstevel@tonic-gate case 'x': 445*0Sstevel@tonic-gate iov[iter].iov_base = alloca(24); 446*0Sstevel@tonic-gate iov[iter].iov_len = ulongtos(iov[iter].iov_base, 447*0Sstevel@tonic-gate va_arg(ap, unsigned long), 16); 448*0Sstevel@tonic-gate iter++; 449*0Sstevel@tonic-gate break; 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate case '%': 452*0Sstevel@tonic-gate iov[iter].iov_base = (char *)src; 453*0Sstevel@tonic-gate iov[iter].iov_len = 1; 454*0Sstevel@tonic-gate iter++; 455*0Sstevel@tonic-gate break; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate src++; 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate va_end(ap); 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate (void) writev(filenum, iov, iter); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate static int 467*0Sstevel@tonic-gate display_stack_info(uintptr_t pc, int signo, void *arg) 468*0Sstevel@tonic-gate { 469*0Sstevel@tonic-gate Dl_info info; 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate char sigbuf[SIG2STR_MAX]; 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate Sym *sym; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate int filenum = (intptr_t)arg; 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate if (signo) { 478*0Sstevel@tonic-gate if (sig2str(signo, sigbuf) != 0) 479*0Sstevel@tonic-gate (void) strcpy(sigbuf, "?"); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (dladdr1((void *) pc, &info, (void**) &sym, RTLD_DL_SYMENT) == 0) { 483*0Sstevel@tonic-gate /* no info at all */ 484*0Sstevel@tonic-gate if (signo == 0) 485*0Sstevel@tonic-gate async_filenoprintf(filenum, "0x%x\n", pc); 486*0Sstevel@tonic-gate else 487*0Sstevel@tonic-gate async_filenoprintf(filenum, 488*0Sstevel@tonic-gate "0x%x [ Signal %d (%s)]\n", pc, 489*0Sstevel@tonic-gate (ulong_t)signo, sigbuf); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate } else if ((pc - (unsigned long)info.dli_saddr) < 492*0Sstevel@tonic-gate sym->st_size) { 493*0Sstevel@tonic-gate /* found a global symbol */ 494*0Sstevel@tonic-gate if (signo == 0) 495*0Sstevel@tonic-gate async_filenoprintf(filenum, "%s:%s+0x%x\n", 496*0Sstevel@tonic-gate info.dli_fname, 497*0Sstevel@tonic-gate info.dli_sname, 498*0Sstevel@tonic-gate pc - (unsigned long)info.dli_saddr); 499*0Sstevel@tonic-gate else 500*0Sstevel@tonic-gate async_filenoprintf(filenum, 501*0Sstevel@tonic-gate "%s:%s+0x%x [ Signal %d (%s)]\n", 502*0Sstevel@tonic-gate info.dli_fname, 503*0Sstevel@tonic-gate info.dli_sname, 504*0Sstevel@tonic-gate pc - (unsigned long)info.dli_saddr, 505*0Sstevel@tonic-gate (ulong_t)signo, sigbuf); 506*0Sstevel@tonic-gate } else { 507*0Sstevel@tonic-gate /* found a static symbol */ 508*0Sstevel@tonic-gate if (signo == 0) 509*0Sstevel@tonic-gate async_filenoprintf(filenum, "%s:0x%x\n", 510*0Sstevel@tonic-gate info.dli_fname, 511*0Sstevel@tonic-gate pc - (unsigned long)info.dli_fbase); 512*0Sstevel@tonic-gate else 513*0Sstevel@tonic-gate async_filenoprintf(filenum, 514*0Sstevel@tonic-gate "%s:0x%x [ Signal %d (%s)]\n", 515*0Sstevel@tonic-gate info.dli_fname, 516*0Sstevel@tonic-gate pc - (unsigned long)info.dli_fbase, 517*0Sstevel@tonic-gate (ulong_t)signo, sigbuf); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate return (0); 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate int 524*0Sstevel@tonic-gate printstack(int dofd) 525*0Sstevel@tonic-gate { 526*0Sstevel@tonic-gate ucontext_t u; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate if (getcontext(&u) < 0) 529*0Sstevel@tonic-gate return (-1); 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd)); 532*0Sstevel@tonic-gate } 533