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