1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include "misc.h" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <ucontext.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/frame.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <stdio.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9) 39*7c478bd9Sstevel@tonic-gate extern void flush_windows(void); 40*7c478bd9Sstevel@tonic-gate #define UMEM_FRAMESIZE MINFRAME 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * On x86, MINFRAME is defined to be 0, but we want to be sure we can 45*7c478bd9Sstevel@tonic-gate * dereference the entire frame structure. 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate #define UMEM_FRAMESIZE (sizeof (struct frame)) 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #else 50*7c478bd9Sstevel@tonic-gate #error needs update for new architecture 51*7c478bd9Sstevel@tonic-gate #endif 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* 54*7c478bd9Sstevel@tonic-gate * Get a pc-only stacktrace. Used for kmem_alloc() buffer ownership tracking. 55*7c478bd9Sstevel@tonic-gate * Returns MIN(current stack depth, pcstack_limit). 56*7c478bd9Sstevel@tonic-gate */ 57*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 58*7c478bd9Sstevel@tonic-gate int 59*7c478bd9Sstevel@tonic-gate getpcstack(uintptr_t *pcstack, int pcstack_limit, int check_signal) 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate struct frame *fp; 62*7c478bd9Sstevel@tonic-gate struct frame *nextfp, *minfp; 63*7c478bd9Sstevel@tonic-gate int depth = 0; 64*7c478bd9Sstevel@tonic-gate uintptr_t base = 0; 65*7c478bd9Sstevel@tonic-gate size_t size = 0; 66*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 67*7c478bd9Sstevel@tonic-gate int on_altstack = 0; 68*7c478bd9Sstevel@tonic-gate uintptr_t sigbase = 0; 69*7c478bd9Sstevel@tonic-gate size_t sigsize = 0; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate stack_t st; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate if (stack_getbounds(&st) != 0) { 74*7c478bd9Sstevel@tonic-gate if (thr_stksegment(&st) != 0 || 75*7c478bd9Sstevel@tonic-gate (uintptr_t)st.ss_sp < st.ss_size) { 76*7c478bd9Sstevel@tonic-gate return (0); /* unable to get stack bounds */ 77*7c478bd9Sstevel@tonic-gate } 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * thr_stksegment(3C) has a slightly different interface than 80*7c478bd9Sstevel@tonic-gate * stack_getbounds(3C) -- correct it 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate st.ss_sp = (void *)(((uintptr_t)st.ss_sp) - st.ss_size); 83*7c478bd9Sstevel@tonic-gate st.ss_flags = 0; /* can't be on-stack */ 84*7c478bd9Sstevel@tonic-gate } 85*7c478bd9Sstevel@tonic-gate on_altstack = (st.ss_flags & SS_ONSTACK); 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate if (st.ss_size != 0) { 88*7c478bd9Sstevel@tonic-gate base = (uintptr_t)st.ss_sp; 89*7c478bd9Sstevel@tonic-gate size = st.ss_size; 90*7c478bd9Sstevel@tonic-gate } else { 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * If size == 0, then ss_sp is the *top* of the stack. 93*7c478bd9Sstevel@tonic-gate * 94*7c478bd9Sstevel@tonic-gate * Since we only allow increasing frame pointers, and we 95*7c478bd9Sstevel@tonic-gate * know our caller set his up correctly, we can treat ss_sp 96*7c478bd9Sstevel@tonic-gate * as an upper bound safely. 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate base = 0; 99*7c478bd9Sstevel@tonic-gate size = (uintptr_t)st.ss_sp; 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate if (check_signal != 0) { 103*7c478bd9Sstevel@tonic-gate void (*sigfunc)() = NULL; 104*7c478bd9Sstevel@tonic-gate int sigfuncsize = 0; 105*7c478bd9Sstevel@tonic-gate extern void thr_sighndlrinfo(void (**)(), int *); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate thr_sighndlrinfo(&sigfunc, &sigfuncsize); 108*7c478bd9Sstevel@tonic-gate sigbase = (uintptr_t)sigfunc; 109*7c478bd9Sstevel@tonic-gate sigsize = sigfuncsize; 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate #else /* UMEM_STANDALONE */ 112*7c478bd9Sstevel@tonic-gate base = (uintptr_t)umem_min_stack; 113*7c478bd9Sstevel@tonic-gate size = umem_max_stack - umem_min_stack; 114*7c478bd9Sstevel@tonic-gate #endif 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* 117*7c478bd9Sstevel@tonic-gate * shorten size so that fr_savfp and fr_savpc will be within the stack 118*7c478bd9Sstevel@tonic-gate * bounds. 119*7c478bd9Sstevel@tonic-gate */ 120*7c478bd9Sstevel@tonic-gate if (size >= UMEM_FRAMESIZE - 1) 121*7c478bd9Sstevel@tonic-gate size -= (UMEM_FRAMESIZE - 1); 122*7c478bd9Sstevel@tonic-gate else 123*7c478bd9Sstevel@tonic-gate size = 0; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9) 126*7c478bd9Sstevel@tonic-gate flush_windows(); 127*7c478bd9Sstevel@tonic-gate #endif 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* LINTED alignment */ 130*7c478bd9Sstevel@tonic-gate fp = (struct frame *)((caddr_t)getfp() + STACK_BIAS); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate minfp = fp; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate if (((uintptr_t)fp - base) >= size) 135*7c478bd9Sstevel@tonic-gate return (0); /* the frame pointer isn't in our stack */ 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate while (depth < pcstack_limit) { 138*7c478bd9Sstevel@tonic-gate uintptr_t tmp; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* LINTED alignment */ 141*7c478bd9Sstevel@tonic-gate nextfp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); 142*7c478bd9Sstevel@tonic-gate tmp = (uintptr_t)nextfp; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate /* 145*7c478bd9Sstevel@tonic-gate * Check nextfp for validity. It must be properly aligned, 146*7c478bd9Sstevel@tonic-gate * increasing compared to the last %fp (or the top of the 147*7c478bd9Sstevel@tonic-gate * stack we just switched to), and it must be inside 148*7c478bd9Sstevel@tonic-gate * [base, base + size). 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate if (tmp != SA(tmp)) 151*7c478bd9Sstevel@tonic-gate break; 152*7c478bd9Sstevel@tonic-gate else if (nextfp <= minfp || (tmp - base) >= size) { 153*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 154*7c478bd9Sstevel@tonic-gate if (tmp == NULL || !on_altstack) 155*7c478bd9Sstevel@tonic-gate break; 156*7c478bd9Sstevel@tonic-gate /* 157*7c478bd9Sstevel@tonic-gate * If we're on an alternate signal stack, try jumping 158*7c478bd9Sstevel@tonic-gate * to the main thread stack. 159*7c478bd9Sstevel@tonic-gate * 160*7c478bd9Sstevel@tonic-gate * If the main thread stack has an unlimited size, we 161*7c478bd9Sstevel@tonic-gate * punt, since we don't know where the frame pointer's 162*7c478bd9Sstevel@tonic-gate * been. 163*7c478bd9Sstevel@tonic-gate * 164*7c478bd9Sstevel@tonic-gate * (thr_stksegment() returns the *top of stack* 165*7c478bd9Sstevel@tonic-gate * in ss_sp, not the bottom) 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate if (thr_stksegment(&st) == 0) { 168*7c478bd9Sstevel@tonic-gate if (st.ss_size >= (uintptr_t)st.ss_sp || 169*7c478bd9Sstevel@tonic-gate st.ss_size < UMEM_FRAMESIZE - 1) 170*7c478bd9Sstevel@tonic-gate break; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate on_altstack = 0; 173*7c478bd9Sstevel@tonic-gate base = (uintptr_t)st.ss_sp - st.ss_size; 174*7c478bd9Sstevel@tonic-gate size = st.ss_size - (UMEM_FRAMESIZE - 1); 175*7c478bd9Sstevel@tonic-gate minfp = (struct frame *)base; 176*7c478bd9Sstevel@tonic-gate continue; /* try again */ 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate #endif 179*7c478bd9Sstevel@tonic-gate break; 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 183*7c478bd9Sstevel@tonic-gate if (check_signal && (fp->fr_savpc - sigbase) <= sigsize) 184*7c478bd9Sstevel@tonic-gate umem_panic("called from signal handler"); 185*7c478bd9Sstevel@tonic-gate #endif 186*7c478bd9Sstevel@tonic-gate pcstack[depth++] = fp->fr_savpc; 187*7c478bd9Sstevel@tonic-gate fp = nextfp; 188*7c478bd9Sstevel@tonic-gate minfp = fp; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate return (depth); 191*7c478bd9Sstevel@tonic-gate } 192