1 /* $OpenBSD: mcount.c,v 1.8 2004/08/07 00:38:32 deraadt Exp $ */ 2 /* $NetBSD: mcount.c,v 1.3.6.1 1996/06/12 04:23:01 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1983, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #if !defined(lint) && !defined(_KERNEL) && defined(LIBC_SCCS) 34 #if 0 35 static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; 36 #else 37 static char rcsid[] = "$OpenBSD: mcount.c,v 1.8 2004/08/07 00:38:32 deraadt Exp $"; 38 #endif 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/gmon.h> 43 44 /* 45 * mcount is called on entry to each function compiled with the profiling 46 * switch set. _mcount(), which is declared in a machine-dependent way 47 * with _MCOUNT_DECL, does the actual work and is either inlined into a 48 * C routine or called by an assembly stub. In any case, this magic is 49 * taken care of by the MCOUNT definition in <machine/profile.h>. 50 * 51 * _mcount updates data structures that represent traversals of the 52 * program's call graph edges. frompc and selfpc are the return 53 * address and function address that represents the given call graph edge. 54 * 55 * Note: the original BSD code used the same variable (frompcindex) for 56 * both frompcindex and frompc. Any reasonable, modern compiler will 57 * perform this optimization. 58 * 59 * XXX - the unused attribute is there because some archs define _mcount 60 * as static and gcc doesn't check for function calls in assembler 61 * stubs. 62 */ 63 _MCOUNT_DECL(u_long frompc, u_long selfpc) __attribute__((unused)); 64 _MCOUNT_DECL(u_long frompc, u_long selfpc) /* _mcount; may be static, inline, etc */ 65 { 66 u_short *frompcindex; 67 struct tostruct *top, *prevtop; 68 struct gmonparam *p; 69 long toindex; 70 #ifdef _KERNEL 71 int s; 72 #endif 73 74 p = &_gmonparam; 75 /* 76 * check that we are profiling 77 * and that we aren't recursively invoked. 78 */ 79 if (p->state != GMON_PROF_ON) 80 return; 81 #ifdef _KERNEL 82 MCOUNT_ENTER; 83 #else 84 p->state = GMON_PROF_BUSY; 85 #endif 86 /* 87 * check that frompcindex is a reasonable pc value. 88 * for example: signal catchers get called from the stack, 89 * not from text space. too bad. 90 */ 91 frompc -= p->lowpc; 92 if (frompc > p->textsize) 93 goto done; 94 95 #if (HASHFRACTION & (HASHFRACTION - 1)) == 0 96 if (p->hashfraction == HASHFRACTION) 97 frompcindex = 98 &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; 99 else 100 #endif 101 frompcindex = 102 &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; 103 toindex = *frompcindex; 104 if (toindex == 0) { 105 /* 106 * first time traversing this arc 107 */ 108 toindex = ++p->tos[0].link; 109 if (toindex >= p->tolimit) 110 /* halt further profiling */ 111 goto overflow; 112 113 *frompcindex = toindex; 114 top = &p->tos[toindex]; 115 top->selfpc = selfpc; 116 top->count = 1; 117 top->link = 0; 118 goto done; 119 } 120 top = &p->tos[toindex]; 121 if (top->selfpc == selfpc) { 122 /* 123 * arc at front of chain; usual case. 124 */ 125 top->count++; 126 goto done; 127 } 128 /* 129 * have to go looking down chain for it. 130 * top points to what we are looking at, 131 * prevtop points to previous top. 132 * we know it is not at the head of the chain. 133 */ 134 for (; /* goto done */; ) { 135 if (top->link == 0) { 136 /* 137 * top is end of the chain and none of the chain 138 * had top->selfpc == selfpc. 139 * so we allocate a new tostruct 140 * and link it to the head of the chain. 141 */ 142 toindex = ++p->tos[0].link; 143 if (toindex >= p->tolimit) 144 goto overflow; 145 146 top = &p->tos[toindex]; 147 top->selfpc = selfpc; 148 top->count = 1; 149 top->link = *frompcindex; 150 *frompcindex = toindex; 151 goto done; 152 } 153 /* 154 * otherwise, check the next arc on the chain. 155 */ 156 prevtop = top; 157 top = &p->tos[top->link]; 158 if (top->selfpc == selfpc) { 159 /* 160 * there it is. 161 * increment its count 162 * move it to the head of the chain. 163 */ 164 top->count++; 165 toindex = prevtop->link; 166 prevtop->link = top->link; 167 top->link = *frompcindex; 168 *frompcindex = toindex; 169 goto done; 170 } 171 172 } 173 done: 174 #ifdef _KERNEL 175 MCOUNT_EXIT; 176 #else 177 p->state = GMON_PROF_ON; 178 #endif 179 return; 180 overflow: 181 p->state = GMON_PROF_ERROR; 182 #ifdef _KERNEL 183 MCOUNT_EXIT; 184 #endif 185 return; 186 } 187 188 /* 189 * Actual definition of mcount function. Defined in <machine/profile.h>, 190 * which is included by <sys/gmon.h>. 191 */ 192 MCOUNT