Blame gmon/mcount.c

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