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