profile.h revision 129446
137535Sdes/*
2135546Sdes * Copyright (c) 1992, 1993
337535Sdes *	The Regents of the University of California.  All rights reserved.
437535Sdes *
537535Sdes * Redistribution and use in source and binary forms, with or without
637535Sdes * modification, are permitted provided that the following conditions
737535Sdes * are met:
837535Sdes * 1. Redistributions of source code must retain the above copyright
937535Sdes *    notice, this list of conditions and the following disclaimer.
1037535Sdes * 2. Redistributions in binary form must reproduce the above copyright
1137535Sdes *    notice, this list of conditions and the following disclaimer in the
1237535Sdes *    documentation and/or other materials provided with the distribution.
1337535Sdes * 4. Neither the name of the University nor the names of its contributors
1437535Sdes *    may be used to endorse or promote products derived from this software
1563012Sdes *    without specific prior written permission.
1637535Sdes *
1737535Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1837535Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1937535Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2037535Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2137535Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2237535Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2337535Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2437535Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2537535Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2637535Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2737535Sdes * SUCH DAMAGE.
2837535Sdes *
2984203Sdillon *	@(#)profile.h	8.1 (Berkeley) 6/11/93
3084203Sdillon * $FreeBSD: head/sys/amd64/include/profile.h 129446 2004-05-19 16:19:11Z bde $
3184203Sdillon */
3263236Sdes
3363236Sdes#ifndef _MACHINE_PROFILE_H_
3463236Sdes#define	_MACHINE_PROFILE_H_
3563236Sdes
3663236Sdes#ifdef _KERNEL
3763236Sdes
3863236Sdes/*
3963236Sdes * Config generates something to tell the compiler to align functions on 16
4063236Sdes * byte boundaries.  A strict alignment is good for keeping the tables small.
4163236Sdes */
4263236Sdes#define	FUNCTION_ALIGNMENT	16
4363236Sdes
4463236Sdes/*
4563236Sdes * The kernel uses assembler stubs instead of unportable inlines.
4663236Sdes * This is mainly to save a little time when profiling is not enabled,
4763236Sdes * which is the usual case for the kernel.
4863236Sdes */
4990267Sdes#define	_MCOUNT_DECL void mcount
5063236Sdes#define	MCOUNT
5163236Sdes
5263236Sdes#ifdef GUPROF
5363236Sdes#define	MCOUNT_DECL(s)
5463236Sdes#define	MCOUNT_ENTER(s)
5563236Sdes#define	MCOUNT_EXIT(s)
5663236Sdes#else
5763236Sdes#define	MCOUNT_DECL(s)	u_long s;
5863236Sdes#ifdef SMP
5963236Sdesextern int	mcount_lock;
6063236Sdes#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); \
6163236Sdes 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
6263236Sdes			  	/* nothing */ ; }
6363236Sdes#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
6437535Sdes			  write_rflags(s); }
6560737Sume#else
66186124Smurray#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); }
6737535Sdes#define	MCOUNT_EXIT(s)	(write_rflags(s))
6863012Sdes#endif
6937535Sdes#endif /* GUPROF */
7063012Sdes
7160376Sdes#else /* !_KERNEL */
7260189Sdes
7337608Sdes#define	FUNCTION_ALIGNMENT	4
7437535Sdes
7537535Sdes#define	_MCOUNT_DECL \
7637535Sdesstatic void _mcount(uintfptr_t frompc, uintfptr_t selfpc) __unused; \
7760376Sdesstatic void _mcount
7837535Sdes
79202613Sdes#ifdef	__GNUC__
8037535Sdes#define	MCOUNT __asm("			\n\
81141958Skbyanc	.globl	.mcount			\n\
82141958Skbyanc	.type	.mcount @function	\n\
83141958Skbyanc.mcount:				\n\
8437535Sdes	pushq	%rbp			\n\
8540939Sdes	movq	%rsp,%rbp		\n\
8641862Sdes	pushq	%rdi			\n\
8737535Sdes	pushq	%rsi			\n\
8863012Sdes	pushq	%rdx			\n\
8963012Sdes	pushq	%rcx			\n\
9037535Sdes	pushq	%r8			\n\
9163012Sdes	pushq	%r9			\n\
9263012Sdes	movq	8(%rbp),%rsi		\n\
9363012Sdes	movq	(%rbp),%rdi		\n\
9463012Sdes	movq	8(%rdi),%rdi		\n\
9563012Sdes	call	_mcount			\n\
9663012Sdes	popq	%r9			\n\
97186124Smurray	popq	%r8			\n\
98169386Sdes	popq	%rcx			\n\
9963012Sdes	popq	%rdx			\n\
10087317Sdes	popq	%rsi			\n\
101125696Sdes	popq	%rdi			\n\
10263012Sdes	leave				\n\
10360196Sdes	ret				\n\
10463012Sdes	.size	.mcount, . - .mcount");
10590267Sdes#if 0
106169386Sdes/*
10790267Sdes * We could use this, except it doesn't preserve the registers that were
10863012Sdes * being passed with arguments to the function that we were inserted
10988771Sdes * into.  I've left it here as documentation of what the code above is
11063012Sdes * supposed to do.
11190267Sdes */
11263012Sdes#define	MCOUNT								\
11363012Sdesvoid									\
11463012Sdesmcount()								\
11563012Sdes{									\
11697859Sdes	uintfptr_t selfpc, frompc;					\
11737535Sdes	/*								\
11897858Sdes	 * Find the return address for mcount,				\
11997866Sdes	 * and the return address for mcount's caller.			\
12097858Sdes	 *								\
12197866Sdes	 * selfpc = pc pushed by call to mcount				\
12297866Sdes	 */								\
12397866Sdes	__asm("movq 8(%%rbp),%0" : "=r" (selfpc));			\
12497858Sdes	/*								\
12597858Sdes	 * frompc = pc pushed by call to mcount's caller.		\
12697858Sdes	 * The caller's stack frame has already been built, so %rbp is	\
12763281Sdes	 * the caller's frame pointer.  The caller's raddr is in the	\
12890267Sdes	 * caller's frame following the caller's caller's frame pointer.\
12963012Sdes	 */								\
13037535Sdes	__asm("movq (%%rbp),%0" : "=r" (frompc));			\
13137535Sdes	frompc = ((uintfptr_t *)frompc)[1];				\
13237608Sdes	_mcount(frompc, selfpc);					\
13363012Sdes}
13437608Sdes#endif
13537608Sdes#else /* !__GNUC__ */
136174588Sdes#define	MCOUNT								\
13737608Sdesvoid									\
13890267Sdesmcount()								\
13990267Sdes{									\
140174588Sdes}
14190267Sdes#endif /* __GNUC__ */
14290267Sdes
143174761Sdestypedef	u_long	uintfptr_t;
14490267Sdes
14590267Sdes#endif /* _KERNEL */
146174761Sdes
14790267Sdes/*
14890267Sdes * An unsigned integral type that can hold non-negative difference between
149174761Sdes * function pointers.
15090267Sdes */
151174761Sdestypedef	u_long	fptrdiff_t;
15297859Sdes
15390267Sdes#ifdef _KERNEL
15490267Sdes
15597859Sdesvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
156176036Sdes
15790267Sdes#else /* !_KERNEL */
15890267Sdes
15990267Sdes#include <sys/cdefs.h>
16063281Sdes
16190267Sdes__BEGIN_DECLS
16297859Sdes#ifdef __GNUC__
16397859Sdesvoid	mcount(void) __asm(".mcount");
164106207Sdes#endif
16590267Sdes__END_DECLS
166106207Sdes
167106207Sdes#endif /* _KERNEL */
168106207Sdes
16990267Sdes#endif /* !_MACHINE_PROFILE_H_ */
17063012Sdes