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