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