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