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