1 /* $NetBSD: mcount.c,v 1.3 1995/02/27 12:54:42 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 1995/02/27 12:54:42 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 frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; 95 toindex = *frompcindex; 96 if (toindex == 0) { 97 /* 98 * first time traversing this arc 99 */ 100 toindex = ++p->tos[0].link; 101 if (toindex >= p->tolimit) 102 /* halt further profiling */ 103 goto overflow; 104 105 *frompcindex = toindex; 106 top = &p->tos[toindex]; 107 top->selfpc = selfpc; 108 top->count = 1; 109 top->link = 0; 110 goto done; 111 } 112 top = &p->tos[toindex]; 113 if (top->selfpc == selfpc) { 114 /* 115 * arc at front of chain; usual case. 116 */ 117 top->count++; 118 goto done; 119 } 120 /* 121 * have to go looking down chain for it. 122 * top points to what we are looking at, 123 * prevtop points to previous top. 124 * we know it is not at the head of the chain. 125 */ 126 for (; /* goto done */; ) { 127 if (top->link == 0) { 128 /* 129 * top is end of the chain and none of the chain 130 * had top->selfpc == selfpc. 131 * so we allocate a new tostruct 132 * and link it to the head of the chain. 133 */ 134 toindex = ++p->tos[0].link; 135 if (toindex >= p->tolimit) 136 goto overflow; 137 138 top = &p->tos[toindex]; 139 top->selfpc = selfpc; 140 top->count = 1; 141 top->link = *frompcindex; 142 *frompcindex = toindex; 143 goto done; 144 } 145 /* 146 * otherwise, check the next arc on the chain. 147 */ 148 prevtop = top; 149 top = &p->tos[top->link]; 150 if (top->selfpc == selfpc) { 151 /* 152 * there it is. 153 * increment its count 154 * move it to the head of the chain. 155 */ 156 top->count++; 157 toindex = prevtop->link; 158 prevtop->link = top->link; 159 top->link = *frompcindex; 160 *frompcindex = toindex; 161 goto done; 162 } 163 164 } 165 done: 166 #ifdef KERNEL 167 MCOUNT_EXIT; 168 #else 169 p->state = GMON_PROF_ON; 170 #endif 171 return; 172 overflow: 173 p->state = GMON_PROF_ERROR; 174 #ifdef KERNEL 175 MCOUNT_EXIT; 176 #endif 177 return; 178 } 179 180 /* 181 * Actual definition of mcount function. Defined in <machine/profile.h>, 182 * which is included by <sys/gmon.h>. 183 */ 184 MCOUNT 185