1 /* $OpenBSD: mcount.c,v 1.15 2015/01/16 16:48:51 deraadt 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/types.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 _MCOUNT_DECL(u_long frompc, u_long selfpc) __used; 46 /* _mcount; may be static, inline, etc */ 47 _MCOUNT_DECL(u_long frompc, u_long selfpc) 48 { 49 u_short *frompcindex; 50 struct tostruct *top, *prevtop; 51 struct gmonparam *p; 52 long toindex; 53 #ifdef _KERNEL 54 int s; 55 56 /* 57 * Do not profile execution if memory for the current CPU 58 * desciptor and profiling buffers has not yet been allocated 59 * or if the CPU we are running on has not yet set its trap 60 * handler. 61 */ 62 if (gmoninit == 0) 63 return; 64 65 if ((p = curcpu()->ci_gmon) == NULL) 66 return; 67 #else 68 p = &_gmonparam; 69 #endif 70 /* 71 * check that we are profiling 72 * and that we aren't recursively invoked. 73 */ 74 if (p->state != GMON_PROF_ON) 75 return; 76 #ifdef _KERNEL 77 MCOUNT_ENTER; 78 #else 79 p->state = GMON_PROF_BUSY; 80 #endif 81 /* 82 * check that frompcindex is a reasonable pc value. 83 * for example: signal catchers get called from the stack, 84 * not from text space. too bad. 85 */ 86 frompc -= p->lowpc; 87 if (frompc > p->textsize) 88 goto done; 89 90 #if (HASHFRACTION & (HASHFRACTION - 1)) == 0 91 if (p->hashfraction == HASHFRACTION) 92 frompcindex = 93 &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; 94 else 95 #endif 96 frompcindex = 97 &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; 98 toindex = *frompcindex; 99 if (toindex == 0) { 100 /* 101 * first time traversing this arc 102 */ 103 toindex = ++p->tos[0].link; 104 if (toindex >= p->tolimit) 105 /* halt further profiling */ 106 goto overflow; 107 108 *frompcindex = toindex; 109 top = &p->tos[toindex]; 110 top->selfpc = selfpc; 111 top->count = 1; 112 top->link = 0; 113 goto done; 114 } 115 top = &p->tos[toindex]; 116 if (top->selfpc == selfpc) { 117 /* 118 * arc at front of chain; usual case. 119 */ 120 top->count++; 121 goto done; 122 } 123 /* 124 * have to go looking down chain for it. 125 * top points to what we are looking at, 126 * prevtop points to previous top. 127 * we know it is not at the head of the chain. 128 */ 129 for (; /* goto done */; ) { 130 if (top->link == 0) { 131 /* 132 * top is end of the chain and none of the chain 133 * had top->selfpc == selfpc. 134 * so we allocate a new tostruct 135 * and link it to the head of the chain. 136 */ 137 toindex = ++p->tos[0].link; 138 if (toindex >= p->tolimit) 139 goto overflow; 140 141 top = &p->tos[toindex]; 142 top->selfpc = selfpc; 143 top->count = 1; 144 top->link = *frompcindex; 145 *frompcindex = toindex; 146 goto done; 147 } 148 /* 149 * otherwise, check the next arc on the chain. 150 */ 151 prevtop = top; 152 top = &p->tos[top->link]; 153 if (top->selfpc == selfpc) { 154 /* 155 * there it is. 156 * increment its count 157 * move it to the head of the chain. 158 */ 159 top->count++; 160 toindex = prevtop->link; 161 prevtop->link = top->link; 162 top->link = *frompcindex; 163 *frompcindex = toindex; 164 goto done; 165 } 166 } 167 done: 168 #ifdef _KERNEL 169 MCOUNT_EXIT; 170 #else 171 p->state = GMON_PROF_ON; 172 #endif 173 return; 174 overflow: 175 p->state = GMON_PROF_ERROR; 176 #ifdef _KERNEL 177 MCOUNT_EXIT; 178 #endif 179 return; 180 } 181 182 /* 183 * Actual definition of mcount function. Defined in <machine/profile.h>, 184 * which is included by <sys/gmon.h>. 185 */ 186 MCOUNT 187