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