Blame gmon/mcount.c

Packit 6c4009
/*-
Packit 6c4009
 * Copyright (c) 1983, 1992, 1993
Packit 6c4009
 *	The Regents of the University of California.  All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions
Packit 6c4009
 * are met:
Packit 6c4009
 * 1. Redistributions of source code must retain the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer.
Packit 6c4009
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer in the
Packit 6c4009
 *    documentation and/or other materials provided with the distribution.
Packit 6c4009
 * 4. Neither the name of the University nor the names of its contributors
Packit 6c4009
 *    may be used to endorse or promote products derived from this software
Packit 6c4009
 *    without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 6c4009
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 6c4009
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6c4009
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 6c4009
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 6c4009
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 6c4009
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 6c4009
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 6c4009
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 6c4009
 * SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#if !defined(lint) && !defined(KERNEL) && defined(LIBC_SCCS)
Packit 6c4009
static char sccsid[] = "@(#)mcount.c	8.1 (Berkeley) 6/4/93";
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/gmon.h>
Packit 6c4009
Packit 6c4009
/* This file provides the machine-dependent definitions of the _MCOUNT_DECL
Packit 6c4009
   and MCOUNT macros.  */
Packit 6c4009
#include <machine-gmon.h>
Packit 6c4009
Packit 6c4009
#include <atomic.h>
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * mcount is called on entry to each function compiled with the profiling
Packit 6c4009
 * switch set.  _mcount(), which is declared in a machine-dependent way
Packit 6c4009
 * with _MCOUNT_DECL, does the actual work and is either inlined into a
Packit 6c4009
 * C routine or called by an assembly stub.  In any case, this magic is
Packit 6c4009
 * taken care of by the MCOUNT definition in <machine/profile.h>.
Packit 6c4009
 *
Packit 6c4009
 * _mcount updates data structures that represent traversals of the
Packit 6c4009
 * program's call graph edges.  frompc and selfpc are the return
Packit 6c4009
 * address and function address that represents the given call graph edge.
Packit 6c4009
 *
Packit 6c4009
 * Note: the original BSD code used the same variable (frompcindex) for
Packit 6c4009
 * both frompcindex and frompc.  Any reasonable, modern compiler will
Packit 6c4009
 * perform this optimization.
Packit 6c4009
 */
Packit 6c4009
_MCOUNT_DECL(frompc, selfpc)	/* _mcount; may be static, inline, etc */
Packit 6c4009
{
Packit 6c4009
	ARCINDEX *frompcindex;
Packit 6c4009
	struct tostruct *top, *prevtop;
Packit 6c4009
	struct gmonparam *p;
Packit 6c4009
	ARCINDEX toindex;
Packit 6c4009
	int i;
Packit 6c4009
Packit 6c4009
	p = &_gmonparam;
Packit 6c4009
	/*
Packit 6c4009
	 * check that we are profiling
Packit 6c4009
	 * and that we aren't recursively invoked.
Packit 6c4009
	 */
Packit 6c4009
	if (atomic_compare_and_exchange_bool_acq (&p->state, GMON_PROF_BUSY,
Packit 6c4009
						  GMON_PROF_ON))
Packit 6c4009
	  return;
Packit 6c4009
Packit 6c4009
	/*
Packit 6c4009
	 * check that frompcindex is a reasonable pc value.
Packit 6c4009
	 * for example:	signal catchers get called from the stack,
Packit 6c4009
	 *		not from text space.  too bad.
Packit 6c4009
	 */
Packit 6c4009
	frompc -= p->lowpc;
Packit 6c4009
	if (frompc > p->textsize)
Packit 6c4009
		goto done;
Packit 6c4009
Packit 6c4009
	/* The following test used to be
Packit 6c4009
		if (p->log_hashfraction >= 0)
Packit 6c4009
	   But we can simplify this if we assume the profiling data
Packit 6c4009
	   is always initialized by the functions in gmon.c.  But
Packit 6c4009
	   then it is possible to avoid a runtime check and use the
Packit 6c4009
	   smae `if' as in gmon.c.  So keep these tests in sync.  */
Packit 6c4009
	if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
Packit 6c4009
	  /* avoid integer divide if possible: */
Packit 6c4009
	    i = frompc >> p->log_hashfraction;
Packit 6c4009
	} else {
Packit 6c4009
	    i = frompc / (p->hashfraction * sizeof(*p->froms));
Packit 6c4009
	}
Packit 6c4009
	frompcindex = &p->froms[i];
Packit 6c4009
	toindex = *frompcindex;
Packit 6c4009
	if (toindex == 0) {
Packit 6c4009
		/*
Packit 6c4009
		 *	first time traversing this arc
Packit 6c4009
		 */
Packit 6c4009
		toindex = ++p->tos[0].link;
Packit 6c4009
		if (toindex >= p->tolimit)
Packit 6c4009
			/* halt further profiling */
Packit 6c4009
			goto overflow;
Packit 6c4009
Packit 6c4009
		*frompcindex = toindex;
Packit 6c4009
		top = &p->tos[toindex];
Packit 6c4009
		top->selfpc = selfpc;
Packit 6c4009
		top->count = 1;
Packit 6c4009
		top->link = 0;
Packit 6c4009
		goto done;
Packit 6c4009
	}
Packit 6c4009
	top = &p->tos[toindex];
Packit 6c4009
	if (top->selfpc == selfpc) {
Packit 6c4009
		/*
Packit 6c4009
		 * arc at front of chain; usual case.
Packit 6c4009
		 */
Packit 6c4009
		top->count++;
Packit 6c4009
		goto done;
Packit 6c4009
	}
Packit 6c4009
	/*
Packit 6c4009
	 * have to go looking down chain for it.
Packit 6c4009
	 * top points to what we are looking at,
Packit 6c4009
	 * prevtop points to previous top.
Packit 6c4009
	 * we know it is not at the head of the chain.
Packit 6c4009
	 */
Packit 6c4009
	for (; /* goto done */; ) {
Packit 6c4009
		if (top->link == 0) {
Packit 6c4009
			/*
Packit 6c4009
			 * top is end of the chain and none of the chain
Packit 6c4009
			 * had top->selfpc == selfpc.
Packit 6c4009
			 * so we allocate a new tostruct
Packit 6c4009
			 * and link it to the head of the chain.
Packit 6c4009
			 */
Packit 6c4009
			toindex = ++p->tos[0].link;
Packit 6c4009
			if (toindex >= p->tolimit)
Packit 6c4009
				goto overflow;
Packit 6c4009
Packit 6c4009
			top = &p->tos[toindex];
Packit 6c4009
			top->selfpc = selfpc;
Packit 6c4009
			top->count = 1;
Packit 6c4009
			top->link = *frompcindex;
Packit 6c4009
			*frompcindex = toindex;
Packit 6c4009
			goto done;
Packit 6c4009
		}
Packit 6c4009
		/*
Packit 6c4009
		 * otherwise, check the next arc on the chain.
Packit 6c4009
		 */
Packit 6c4009
		prevtop = top;
Packit 6c4009
		top = &p->tos[top->link];
Packit 6c4009
		if (top->selfpc == selfpc) {
Packit 6c4009
			/*
Packit 6c4009
			 * there it is.
Packit 6c4009
			 * increment its count
Packit 6c4009
			 * move it to the head of the chain.
Packit 6c4009
			 */
Packit 6c4009
			top->count++;
Packit 6c4009
			toindex = prevtop->link;
Packit 6c4009
			prevtop->link = top->link;
Packit 6c4009
			top->link = *frompcindex;
Packit 6c4009
			*frompcindex = toindex;
Packit 6c4009
			goto done;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	}
Packit 6c4009
done:
Packit 6c4009
	p->state = GMON_PROF_ON;
Packit 6c4009
	return;
Packit 6c4009
overflow:
Packit 6c4009
	p->state = GMON_PROF_ERROR;
Packit 6c4009
	return;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Actual definition of mcount function.  Defined in <machine/profile.h>,
Packit 6c4009
 * which is included by <sys/gmon.h>.
Packit 6c4009
 */
Packit 6c4009
MCOUNT