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