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 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Pstack.c 31 * 32 * Common helper functions for stack walking. The ISA-specific code is found in 33 * Pstack_iter() in Pisadep.c. 34 */ 35 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <errno.h> 40 41 #include "libproc.h" 42 #include "Pcontrol.h" 43 #include "P32ton.h" 44 #include "Pstack.h" 45 46 /* 47 * Utility function to prevent stack loops from running on forever by 48 * detecting when there is a stack loop (the %fp has been seen before). 49 */ 50 int 51 stack_loop(prgreg_t fp, prgreg_t **prevfpp, int *nfpp, uint_t *pfpsizep) 52 { 53 prgreg_t *prevfp = *prevfpp; 54 uint_t pfpsize = *pfpsizep; 55 int nfp = *nfpp; 56 int i; 57 58 for (i = 0; i < nfp; i++) { 59 if (fp == prevfp[i]) 60 return (1); /* stack loop detected */ 61 } 62 63 if (nfp == pfpsize) { 64 pfpsize = pfpsize ? pfpsize * 2 : 16; 65 prevfp = realloc(prevfp, pfpsize * sizeof (prgreg_t)); 66 /* 67 * Just assume there is no loop in the face of allocation 68 * failure; the caller still has the original prevfp pointer. 69 */ 70 if (prevfp == NULL) 71 return (0); 72 } 73 74 prevfp[nfp++] = fp; 75 *prevfpp = prevfp; 76 *pfpsizep = pfpsize; 77 *nfpp = nfp; 78 79 return (0); 80 } 81 82 /* 83 * Signal Frame Detection 84 * 85 * In order to facilitate detection and processing of signal handler frames 86 * during a stack backtrace, we define a set of utility routines to operate on 87 * a uclist (ucontext address list), and then use these routines in the various 88 * implementations of Pstack_iter below. Certain source-level debuggers and 89 * virtual machines that shall remain nameless believe that in order to detect 90 * signal handler frames, one must hard-code checks for symbol names defined 91 * in libc and libthread and knowledge of their implementation. We make no 92 * such assumptions, allowing us to operate on programs that manipulate their 93 * underlying kernel signal handlers (i.e. use __sigaction) and to not require 94 * changes in the face of future library modifications. 95 * 96 * A signal handler frame is essentially a set of data pushed on to the user 97 * stack by the kernel prior to returning to the user program in one of the 98 * pre-defined signal handlers. The signal handler itself receives the signal 99 * number, an optional pointer to a siginfo_t, and a pointer to the interrupted 100 * ucontext as arguments. When performing a stack backtrace, we would like to 101 * detect these frames so that we can correctly return the interrupted program 102 * counter and frame pointer as a separate frame. When a signal handler frame 103 * is constructed on the stack by the kernel, the signalled LWP has its 104 * lwp_oldcontext member (exported through /proc as lwpstatus.pr_oldcontext) 105 * set to the user address at which the ucontext_t was placed on the LWP's 106 * stack. The ucontext_t's uc_link member is set to the previous value of 107 * lwp_oldcontext. Thus when signal handlers are active, pr_oldcontext will 108 * point to the first element of a linked list of ucontext_t addresses. 109 * 110 * The stack layout for a signal handler frame is as follows: 111 * 112 * SPARC v7/v9: Intel ia32: 113 * +--------------+ - high +--------------+ - 114 * | struct fq | ^ addrs | siginfo_t | optional 115 * +--------------+ | ^ +--------------+ - 116 * | gwindows_t | | | ucontext_t | ^ 117 * +--------------+ optional +--------------+ | 118 * | siginfo_t | | ucontext_t * | | 119 * +--------------+ | | +--------------+ 120 * | xregs data | v v | siginfo_t * | mandatory 121 * +--------------+ - low +--------------+ 122 * | ucontext_t | ^ addrs | int (signo) | | 123 * +--------------+ mandatory +--------------+ | 124 * | struct frame | v | struct frame | v 125 * +--------------+ - <- %sp on resume +--------------+ - <- %esp on resume 126 * 127 * amd64 (64-bit): 128 * +--------------+ - 129 * | siginfo_t | optional 130 * +--------------+ - 131 * | ucontext_t | ^ 132 * +--------------+ | 133 * | siginfo_t * | 134 * +--------------+ mandatory 135 * | int (signo) | 136 * +--------------+ | 137 * | struct frame | v 138 * +--------------+ - <- %rsp on resume 139 * 140 * The bottom-most struct frame is actually constructed by the kernel by 141 * copying the previous stack frame, allowing naive backtrace code to simply 142 * skip over the interrupted frame. The copied frame is never really used, 143 * since it is presumed the libc or libthread signal handler wrapper function 144 * will explicitly setcontext(2) to the interrupted context if the user 145 * program's handler returns. If we detect a signal handler frame, we simply 146 * read the interrupted context structure from the stack, use its embedded 147 * gregs to construct the register set for the interrupted frame, and then 148 * continue our backtrace. Detecting the frame itself is easy according to 149 * the diagram ("oldcontext" represents any element in the uc_link chain): 150 * 151 * On SPARC v7 or v9: 152 * %fp + sizeof (struct frame) == oldcontext 153 * 154 * On Intel ia32: 155 * %ebp + sizeof (struct frame) + (3 * regsize) == oldcontext 156 * 157 * On amd64: 158 * %rbp + sizeof (struct frame) + (2 * regsize) == oldcontext 159 * 160 * A final complication is that we want libproc to support backtraces from 161 * arbitrary addresses without the caller passing in an LWP id. To do this, 162 * we must first determine all the known oldcontexts by iterating over all 163 * LWPs and following their pr_oldcontext pointers. We optimize our search 164 * by discarding NULL pointers and pointers whose value is less than that 165 * of the initial stack pointer (since stacks grow down from high memory), 166 * and then sort the resulting list by virtual address so we can binary search. 167 */ 168 169 int 170 load_uclist(uclist_t *ucl, const lwpstatus_t *psp) 171 { 172 struct ps_prochandle *P = ucl->uc_proc; 173 uintptr_t addr = psp->pr_oldcontext; 174 175 uintptr_t *new_addrs; 176 uint_t new_size, i; 177 ucontext_t uc; 178 179 if (addr == NULL) 180 return (0); 181 182 for (;;) { 183 if (ucl->uc_nelems == ucl->uc_size) { 184 new_size = ucl->uc_size ? ucl->uc_size * 2 : 16; 185 new_addrs = realloc(ucl->uc_addrs, 186 new_size * sizeof (uintptr_t)); 187 188 if (new_addrs != NULL) { 189 ucl->uc_addrs = new_addrs; 190 ucl->uc_size = new_size; 191 } else 192 break; /* abort if allocation failure */ 193 } 194 #ifdef _LP64 195 if (P->status.pr_dmodel == PR_MODEL_ILP32) { 196 ucontext32_t u32; 197 198 if (Pread(P, &u32, sizeof (u32), addr) != sizeof (u32)) 199 break; /* abort if we fail to read ucontext */ 200 uc.uc_link = (ucontext_t *)(uintptr_t)u32.uc_link; 201 } else 202 #endif 203 if (Pread(P, &uc, sizeof (uc), addr) != sizeof (uc)) 204 break; /* abort if we fail to read ucontext */ 205 206 dprintf("detected lwp %d signal context at %p\n", 207 (int)psp->pr_lwpid, (void *)addr); 208 ucl->uc_addrs[ucl->uc_nelems++] = addr; 209 210 addr = (uintptr_t)uc.uc_link; 211 212 /* 213 * Abort if we find a NULL uc_link pointer or a duplicate 214 * entry which could indicate a cycle or a very peculiar 215 * interference pattern between threads. 216 */ 217 if (addr == NULL) 218 break; 219 220 for (i = 0; i < ucl->uc_nelems - 1; i++) { 221 if (ucl->uc_addrs[i] == addr) 222 return (0); 223 } 224 } 225 226 return (0); 227 } 228 229 int 230 sort_uclist(const void *lhp, const void *rhp) 231 { 232 uintptr_t lhs = *((const uintptr_t *)lhp); 233 uintptr_t rhs = *((const uintptr_t *)rhp); 234 235 if (lhs < rhs) 236 return (-1); 237 if (lhs > rhs) 238 return (+1); 239 return (0); 240 } 241 242 void 243 init_uclist(uclist_t *ucl, struct ps_prochandle *P) 244 { 245 if ((P->state == PS_STOP || P->state == PS_DEAD) && 246 P->ucaddrs != NULL) { 247 ucl->uc_proc = P; 248 ucl->uc_addrs = P->ucaddrs; 249 ucl->uc_nelems = P->ucnelems; 250 ucl->uc_size = P->ucnelems; 251 ucl->uc_cached = 1; 252 return; 253 } 254 255 ucl->uc_proc = P; 256 ucl->uc_addrs = NULL; 257 ucl->uc_nelems = 0; 258 ucl->uc_size = 0; 259 260 (void) Plwp_iter(P, (proc_lwp_f *)load_uclist, ucl); 261 qsort(ucl->uc_addrs, ucl->uc_nelems, sizeof (uintptr_t), sort_uclist); 262 263 if (P->state == PS_STOP || P->state == PS_DEAD) { 264 P->ucaddrs = ucl->uc_addrs; 265 P->ucnelems = ucl->uc_nelems; 266 ucl->uc_cached = 1; 267 } else { 268 ucl->uc_cached = 0; 269 } 270 } 271 272 void 273 free_uclist(uclist_t *ucl) 274 { 275 if (!ucl->uc_cached && ucl->uc_addrs != NULL) 276 free(ucl->uc_addrs); 277 } 278 279 int 280 find_uclink(uclist_t *ucl, uintptr_t addr) 281 { 282 if (ucl->uc_nelems != 0) { 283 return (bsearch(&addr, ucl->uc_addrs, ucl->uc_nelems, 284 sizeof (uintptr_t), sort_uclist) != NULL); 285 } 286 287 return (0); 288 } 289