1 /* $OpenBSD: mcount.c,v 1.9 2009/10/27 23:59:35 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 #include <sys/param.h> 34 #include <sys/gmon.h> 35 36 /* 37 * mcount is called on entry to each function compiled with the profiling 38 * switch set. _mcount(), which is declared in a machine-dependent way 39 * with _MCOUNT_DECL, does the actual work and is either inlined into a 40 * C routine or called by an assembly stub. In any case, this magic is 41 * taken care of by the MCOUNT definition in <machine/profile.h>. 42 * 43 * _mcount updates data structures that represent traversals of the 44 * program's call graph edges. frompc and selfpc are the return 45 * address and function address that represents the given call graph edge. 46 * 47 * Note: the original BSD code used the same variable (frompcindex) for 48 * both frompcindex and frompc. Any reasonable, modern compiler will 49 * perform this optimization. 50 * 51 * XXX - the unused attribute is there because some archs define _mcount 52 * as static and gcc doesn't check for function calls in assembler 53 * stubs. 54 */ 55 _MCOUNT_DECL(u_long frompc, u_long selfpc) __attribute__((unused)); 56 _MCOUNT_DECL(u_long frompc, u_long selfpc) /* _mcount; may be static, inline, etc */ 57 { 58 u_short *frompcindex; 59 struct tostruct *top, *prevtop; 60 struct gmonparam *p; 61 long toindex; 62 #ifdef _KERNEL 63 int s; 64 #endif 65 66 p = &_gmonparam; 67 /* 68 * check that we are profiling 69 * and that we aren't recursively invoked. 70 */ 71 if (p->state != GMON_PROF_ON) 72 return; 73 #ifdef _KERNEL 74 MCOUNT_ENTER; 75 #else 76 p->state = GMON_PROF_BUSY; 77 #endif 78 /* 79 * check that frompcindex is a reasonable pc value. 80 * for example: signal catchers get called from the stack, 81 * not from text space. too bad. 82 */ 83 frompc -= p->lowpc; 84 if (frompc > p->textsize) 85 goto done; 86 87 #if (HASHFRACTION & (HASHFRACTION - 1)) == 0 88 if (p->hashfraction == HASHFRACTION) 89 frompcindex = 90 &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; 91 else 92 #endif 93 frompcindex = 94 &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