10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*5891Sraf * Common Development and Distribution License (the "License"). 6*5891Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*5891Sraf 220Sstevel@tonic-gate /* 23*5891Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 29*5891Sraf #include "c_synonyms.h" 300Sstevel@tonic-gate #include "misc.h" 310Sstevel@tonic-gate #include <ucontext.h> 320Sstevel@tonic-gate #include <sys/frame.h> 330Sstevel@tonic-gate #include <sys/stack.h> 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate 360Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9) 370Sstevel@tonic-gate extern void flush_windows(void); 380Sstevel@tonic-gate #define UMEM_FRAMESIZE MINFRAME 390Sstevel@tonic-gate 400Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * On x86, MINFRAME is defined to be 0, but we want to be sure we can 430Sstevel@tonic-gate * dereference the entire frame structure. 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate #define UMEM_FRAMESIZE (sizeof (struct frame)) 460Sstevel@tonic-gate 470Sstevel@tonic-gate #else 480Sstevel@tonic-gate #error needs update for new architecture 490Sstevel@tonic-gate #endif 500Sstevel@tonic-gate 510Sstevel@tonic-gate /* 520Sstevel@tonic-gate * Get a pc-only stacktrace. Used for kmem_alloc() buffer ownership tracking. 530Sstevel@tonic-gate * Returns MIN(current stack depth, pcstack_limit). 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate /*ARGSUSED*/ 560Sstevel@tonic-gate int 570Sstevel@tonic-gate getpcstack(uintptr_t *pcstack, int pcstack_limit, int check_signal) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate struct frame *fp; 600Sstevel@tonic-gate struct frame *nextfp, *minfp; 610Sstevel@tonic-gate int depth = 0; 620Sstevel@tonic-gate uintptr_t base = 0; 630Sstevel@tonic-gate size_t size = 0; 640Sstevel@tonic-gate #ifndef UMEM_STANDALONE 650Sstevel@tonic-gate int on_altstack = 0; 660Sstevel@tonic-gate uintptr_t sigbase = 0; 670Sstevel@tonic-gate size_t sigsize = 0; 680Sstevel@tonic-gate 690Sstevel@tonic-gate stack_t st; 700Sstevel@tonic-gate 710Sstevel@tonic-gate if (stack_getbounds(&st) != 0) { 720Sstevel@tonic-gate if (thr_stksegment(&st) != 0 || 730Sstevel@tonic-gate (uintptr_t)st.ss_sp < st.ss_size) { 740Sstevel@tonic-gate return (0); /* unable to get stack bounds */ 750Sstevel@tonic-gate } 760Sstevel@tonic-gate /* 770Sstevel@tonic-gate * thr_stksegment(3C) has a slightly different interface than 780Sstevel@tonic-gate * stack_getbounds(3C) -- correct it 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate st.ss_sp = (void *)(((uintptr_t)st.ss_sp) - st.ss_size); 810Sstevel@tonic-gate st.ss_flags = 0; /* can't be on-stack */ 820Sstevel@tonic-gate } 830Sstevel@tonic-gate on_altstack = (st.ss_flags & SS_ONSTACK); 840Sstevel@tonic-gate 850Sstevel@tonic-gate if (st.ss_size != 0) { 860Sstevel@tonic-gate base = (uintptr_t)st.ss_sp; 870Sstevel@tonic-gate size = st.ss_size; 880Sstevel@tonic-gate } else { 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * If size == 0, then ss_sp is the *top* of the stack. 910Sstevel@tonic-gate * 920Sstevel@tonic-gate * Since we only allow increasing frame pointers, and we 930Sstevel@tonic-gate * know our caller set his up correctly, we can treat ss_sp 940Sstevel@tonic-gate * as an upper bound safely. 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate base = 0; 970Sstevel@tonic-gate size = (uintptr_t)st.ss_sp; 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate if (check_signal != 0) { 1010Sstevel@tonic-gate void (*sigfunc)() = NULL; 1020Sstevel@tonic-gate int sigfuncsize = 0; 1030Sstevel@tonic-gate extern void thr_sighndlrinfo(void (**)(), int *); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate thr_sighndlrinfo(&sigfunc, &sigfuncsize); 1060Sstevel@tonic-gate sigbase = (uintptr_t)sigfunc; 1070Sstevel@tonic-gate sigsize = sigfuncsize; 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate #else /* UMEM_STANDALONE */ 1100Sstevel@tonic-gate base = (uintptr_t)umem_min_stack; 1110Sstevel@tonic-gate size = umem_max_stack - umem_min_stack; 1120Sstevel@tonic-gate #endif 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * shorten size so that fr_savfp and fr_savpc will be within the stack 1160Sstevel@tonic-gate * bounds. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate if (size >= UMEM_FRAMESIZE - 1) 1190Sstevel@tonic-gate size -= (UMEM_FRAMESIZE - 1); 1200Sstevel@tonic-gate else 1210Sstevel@tonic-gate size = 0; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9) 1240Sstevel@tonic-gate flush_windows(); 1250Sstevel@tonic-gate #endif 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* LINTED alignment */ 1280Sstevel@tonic-gate fp = (struct frame *)((caddr_t)getfp() + STACK_BIAS); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate minfp = fp; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate if (((uintptr_t)fp - base) >= size) 1330Sstevel@tonic-gate return (0); /* the frame pointer isn't in our stack */ 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate while (depth < pcstack_limit) { 1360Sstevel@tonic-gate uintptr_t tmp; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* LINTED alignment */ 1390Sstevel@tonic-gate nextfp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); 1400Sstevel@tonic-gate tmp = (uintptr_t)nextfp; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /* 1430Sstevel@tonic-gate * Check nextfp for validity. It must be properly aligned, 1440Sstevel@tonic-gate * increasing compared to the last %fp (or the top of the 1450Sstevel@tonic-gate * stack we just switched to), and it must be inside 1460Sstevel@tonic-gate * [base, base + size). 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate if (tmp != SA(tmp)) 1490Sstevel@tonic-gate break; 1500Sstevel@tonic-gate else if (nextfp <= minfp || (tmp - base) >= size) { 1510Sstevel@tonic-gate #ifndef UMEM_STANDALONE 1520Sstevel@tonic-gate if (tmp == NULL || !on_altstack) 1530Sstevel@tonic-gate break; 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * If we're on an alternate signal stack, try jumping 1560Sstevel@tonic-gate * to the main thread stack. 1570Sstevel@tonic-gate * 1580Sstevel@tonic-gate * If the main thread stack has an unlimited size, we 1590Sstevel@tonic-gate * punt, since we don't know where the frame pointer's 1600Sstevel@tonic-gate * been. 1610Sstevel@tonic-gate * 1620Sstevel@tonic-gate * (thr_stksegment() returns the *top of stack* 1630Sstevel@tonic-gate * in ss_sp, not the bottom) 1640Sstevel@tonic-gate */ 1650Sstevel@tonic-gate if (thr_stksegment(&st) == 0) { 1660Sstevel@tonic-gate if (st.ss_size >= (uintptr_t)st.ss_sp || 1670Sstevel@tonic-gate st.ss_size < UMEM_FRAMESIZE - 1) 1680Sstevel@tonic-gate break; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate on_altstack = 0; 1710Sstevel@tonic-gate base = (uintptr_t)st.ss_sp - st.ss_size; 1720Sstevel@tonic-gate size = st.ss_size - (UMEM_FRAMESIZE - 1); 1730Sstevel@tonic-gate minfp = (struct frame *)base; 1740Sstevel@tonic-gate continue; /* try again */ 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate #endif 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate #ifndef UMEM_STANDALONE 1810Sstevel@tonic-gate if (check_signal && (fp->fr_savpc - sigbase) <= sigsize) 1820Sstevel@tonic-gate umem_panic("called from signal handler"); 1830Sstevel@tonic-gate #endif 1840Sstevel@tonic-gate pcstack[depth++] = fp->fr_savpc; 1850Sstevel@tonic-gate fp = nextfp; 1860Sstevel@tonic-gate minfp = fp; 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate return (depth); 1890Sstevel@tonic-gate } 190