1 /*- 2 * Copyright (c) 1983, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if !defined(lint) && !defined(KERNEL) && defined(LIBC_SCCS) 9 static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 06/04/93"; 10 #endif 11 12 #include <sys/param.h> 13 #include <sys/gmon.h> 14 15 /* 16 * mcount is called on entry to each function compiled with the profiling 17 * switch set. _mcount(), which is declared in a machine-dependent way 18 * with _MCOUNT_DECL, does the actual work and is either inlined into a 19 * C routine or called by an assembly stub. In any case, this magic is 20 * taken care of by the MCOUNT definition in <machine/profile.h>. 21 * 22 * _mcount updates data structures that represent traversals of the 23 * program's call graph edges. frompc and selfpc are the return 24 * address and function address that represents the given call graph edge. 25 * 26 * Note: the original BSD code used the same variable (frompcindex) for 27 * both frompcindex and frompc. Any reasonable, modern compiler will 28 * perform this optimization. 29 */ 30 _MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ 31 register u_long frompc, selfpc; 32 { 33 register u_short *frompcindex; 34 register struct tostruct *top, *prevtop; 35 register struct gmonparam *p; 36 register long toindex; 37 #ifdef KERNEL 38 register int s; 39 #endif 40 41 p = &_gmonparam; 42 /* 43 * check that we are profiling 44 * and that we aren't recursively invoked. 45 */ 46 if (p->state != GMON_PROF_ON) 47 return; 48 #ifdef KERNEL 49 MCOUNT_ENTER; 50 #else 51 p->state = GMON_PROF_BUSY; 52 #endif 53 /* 54 * check that frompcindex is a reasonable pc value. 55 * for example: signal catchers get called from the stack, 56 * not from text space. too bad. 57 */ 58 frompc -= p->lowpc; 59 if (frompc > p->textsize) 60 goto done; 61 62 frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; 63 toindex = *frompcindex; 64 if (toindex == 0) { 65 /* 66 * first time traversing this arc 67 */ 68 toindex = ++p->tos[0].link; 69 if (toindex >= p->tolimit) 70 /* halt further profiling */ 71 goto overflow; 72 73 *frompcindex = toindex; 74 top = &p->tos[toindex]; 75 top->selfpc = selfpc; 76 top->count = 1; 77 top->link = 0; 78 goto done; 79 } 80 top = &p->tos[toindex]; 81 if (top->selfpc == selfpc) { 82 /* 83 * arc at front of chain; usual case. 84 */ 85 top->count++; 86 goto done; 87 } 88 /* 89 * have to go looking down chain for it. 90 * top points to what we are looking at, 91 * prevtop points to previous top. 92 * we know it is not at the head of the chain. 93 */ 94 for (; /* goto done */; ) { 95 if (top->link == 0) { 96 /* 97 * top is end of the chain and none of the chain 98 * had top->selfpc == selfpc. 99 * so we allocate a new tostruct 100 * and link it to the head of the chain. 101 */ 102 toindex = ++p->tos[0].link; 103 if (toindex >= p->tolimit) 104 goto overflow; 105 106 top = &p->tos[toindex]; 107 top->selfpc = selfpc; 108 top->count = 1; 109 top->link = *frompcindex; 110 *frompcindex = toindex; 111 goto done; 112 } 113 /* 114 * otherwise, check the next arc on the chain. 115 */ 116 prevtop = top; 117 top = &p->tos[top->link]; 118 if (top->selfpc == selfpc) { 119 /* 120 * there it is. 121 * increment its count 122 * move it to the head of the chain. 123 */ 124 top->count++; 125 toindex = prevtop->link; 126 prevtop->link = top->link; 127 top->link = *frompcindex; 128 *frompcindex = toindex; 129 goto done; 130 } 131 132 } 133 done: 134 #ifdef KERNEL 135 MCOUNT_EXIT; 136 #else 137 p->state = GMON_PROF_ON; 138 #endif 139 return; 140 overflow: 141 p->state = GMON_PROF_ERROR; 142 #ifdef KERNEL 143 MCOUNT_EXIT; 144 #endif 145 return; 146 } 147 148 /* 149 * Actual definition of mcount function. Defined in <machine/profile.h>, 150 * which is included by <sys/gmon.h>. 151 */ 152 MCOUNT 153