Back to index

glibc  2.9
mcount.c
Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1983, 1992, 1993
00003  *     The Regents of the University of California.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 4. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #if !defined(lint) && !defined(KERNEL) && defined(LIBC_SCCS)
00031 static char sccsid[] = "@(#)mcount.c      8.1 (Berkeley) 6/4/93";
00032 #endif
00033 
00034 #include <unistd.h>
00035 #include <sys/param.h>
00036 #include <sys/gmon.h>
00037 
00038 /* This file provides the machine-dependent definitions of the _MCOUNT_DECL
00039    and MCOUNT macros.  */
00040 #include <machine-gmon.h>
00041 
00042 #include <atomic.h>
00043 
00044 /*
00045  * mcount is called on entry to each function compiled with the profiling
00046  * switch set.  _mcount(), which is declared in a machine-dependent way
00047  * with _MCOUNT_DECL, does the actual work and is either inlined into a
00048  * C routine or called by an assembly stub.  In any case, this magic is
00049  * taken care of by the MCOUNT definition in <machine/profile.h>.
00050  *
00051  * _mcount updates data structures that represent traversals of the
00052  * program's call graph edges.  frompc and selfpc are the return
00053  * address and function address that represents the given call graph edge.
00054  *
00055  * Note: the original BSD code used the same variable (frompcindex) for
00056  * both frompcindex and frompc.  Any reasonable, modern compiler will
00057  * perform this optimization.
00058  */
00059 _MCOUNT_DECL(frompc, selfpc)       /* _mcount; may be static, inline, etc */
00060 {
00061        register ARCINDEX *frompcindex;
00062        register struct tostruct *top, *prevtop;
00063        register struct gmonparam *p;
00064        register ARCINDEX toindex;
00065        int i;
00066 
00067        p = &_gmonparam;
00068        /*
00069         * check that we are profiling
00070         * and that we aren't recursively invoked.
00071         */
00072        if (catomic_compare_and_exchange_bool_acq (&p->state, GMON_PROF_BUSY,
00073                                              GMON_PROF_ON))
00074          return;
00075 
00076        /*
00077         * check that frompcindex is a reasonable pc value.
00078         * for example:      signal catchers get called from the stack,
00079         *            not from text space.  too bad.
00080         */
00081        frompc -= p->lowpc;
00082        if (frompc > p->textsize)
00083               goto done;
00084 
00085        /* The following test used to be
00086               if (p->log_hashfraction >= 0)
00087           But we can simplify this if we assume the profiling data
00088           is always initialized by the functions in gmon.c.  But
00089           then it is possible to avoid a runtime check and use the
00090           smae `if' as in gmon.c.  So keep these tests in sync.  */
00091        if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
00092          /* avoid integer divide if possible: */
00093            i = frompc >> p->log_hashfraction;
00094        } else {
00095            i = frompc / (p->hashfraction * sizeof(*p->froms));
00096        }
00097        frompcindex = &p->froms[i];
00098        toindex = *frompcindex;
00099        if (toindex == 0) {
00100               /*
00101                *     first time traversing this arc
00102                */
00103               toindex = ++p->tos[0].link;
00104               if (toindex >= p->tolimit)
00105                      /* halt further profiling */
00106                      goto overflow;
00107 
00108               *frompcindex = toindex;
00109               top = &p->tos[toindex];
00110               top->selfpc = selfpc;
00111               top->count = 1;
00112               top->link = 0;
00113               goto done;
00114        }
00115        top = &p->tos[toindex];
00116        if (top->selfpc == selfpc) {
00117               /*
00118                * arc at front of chain; usual case.
00119                */
00120               top->count++;
00121               goto done;
00122        }
00123        /*
00124         * have to go looking down chain for it.
00125         * top points to what we are looking at,
00126         * prevtop points to previous top.
00127         * we know it is not at the head of the chain.
00128         */
00129        for (; /* goto done */; ) {
00130               if (top->link == 0) {
00131                      /*
00132                       * top is end of the chain and none of the chain
00133                       * had top->selfpc == selfpc.
00134                       * so we allocate a new tostruct
00135                       * and link it to the head of the chain.
00136                       */
00137                      toindex = ++p->tos[0].link;
00138                      if (toindex >= p->tolimit)
00139                             goto overflow;
00140 
00141                      top = &p->tos[toindex];
00142                      top->selfpc = selfpc;
00143                      top->count = 1;
00144                      top->link = *frompcindex;
00145                      *frompcindex = toindex;
00146                      goto done;
00147               }
00148               /*
00149                * otherwise, check the next arc on the chain.
00150                */
00151               prevtop = top;
00152               top = &p->tos[top->link];
00153               if (top->selfpc == selfpc) {
00154                      /*
00155                       * there it is.
00156                       * increment its count
00157                       * move it to the head of the chain.
00158                       */
00159                      top->count++;
00160                      toindex = prevtop->link;
00161                      prevtop->link = top->link;
00162                      top->link = *frompcindex;
00163                      *frompcindex = toindex;
00164                      goto done;
00165               }
00166 
00167        }
00168 done:
00169        p->state = GMON_PROF_ON;
00170        return;
00171 overflow:
00172        p->state = GMON_PROF_ERROR;
00173        return;
00174 }
00175 
00176 /*
00177  * Actual definition of mcount function.  Defined in <machine/profile.h>,
00178  * which is included by <sys/gmon.h>.
00179  */
00180 MCOUNT