profile.h revision 132846
11543Srgrimes/*
21543Srgrimes * Copyright (c) 1992, 1993
31543Srgrimes *	The Regents of the University of California.  All rights reserved.
41543Srgrimes *
51543Srgrimes * Redistribution and use in source and binary forms, with or without
61543Srgrimes * modification, are permitted provided that the following conditions
71543Srgrimes * are met:
81543Srgrimes * 1. Redistributions of source code must retain the above copyright
91543Srgrimes *    notice, this list of conditions and the following disclaimer.
101543Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111543Srgrimes *    notice, this list of conditions and the following disclaimer in the
121543Srgrimes *    documentation and/or other materials provided with the distribution.
131543Srgrimes * 4. Neither the name of the University nor the names of its contributors
141543Srgrimes *    may be used to endorse or promote products derived from this software
151543Srgrimes *    without specific prior written permission.
161543Srgrimes *
171543Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181543Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191543Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201543Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211543Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221543Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231543Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241543Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251543Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261543Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271543Srgrimes * SUCH DAMAGE.
281543Srgrimes *
291543Srgrimes *	@(#)profile.h	8.1 (Berkeley) 6/11/93
3050477Speter * $FreeBSD: head/sys/amd64/include/profile.h 132846 2004-07-29 18:02:28Z kan $
311543Srgrimes */
321543Srgrimes
3313107Sbde#ifndef _MACHINE_PROFILE_H_
3413107Sbde#define	_MACHINE_PROFILE_H_
352166Spaul
3655205Speter#ifdef _KERNEL
3737542Sbde
3813157Sbde/*
3922639Sbde * Config generates something to tell the compiler to align functions on 16
4022639Sbde * byte boundaries.  A strict alignment is good for keeping the tables small.
4122639Sbde */
4222639Sbde#define	FUNCTION_ALIGNMENT	16
4322639Sbde
4422639Sbde/*
4513157Sbde * The kernel uses assembler stubs instead of unportable inlines.
4613157Sbde * This is mainly to save a little time when profiling is not enabled,
4713157Sbde * which is the usual case for the kernel.
4813157Sbde */
4913157Sbde#define	_MCOUNT_DECL void mcount
5013157Sbde#define	MCOUNT
511543Srgrimes
5217879Sbde#ifdef GUPROF
5317879Sbde#define	MCOUNT_DECL(s)
5417879Sbde#define	MCOUNT_ENTER(s)
5517879Sbde#define	MCOUNT_EXIT(s)
56129499Sbde#ifdef __GNUC__
57129499Sbde#define	MCOUNT_OVERHEAD(label)						\
58129499Sbde	__asm __volatile("pushq %0; call __mcount; popq %%rcx"		\
59129499Sbde			 :						\
60129499Sbde			 : "i" (profil)					\
61129499Sbde			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
62129499Sbde#define	MEXITCOUNT_OVERHEAD()						\
63129499Sbde	__asm __volatile("call .mexitcount; 1:"				\
64129499Sbde			 : :						\
65129499Sbde			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
66129499Sbde#define	MEXITCOUNT_OVERHEAD_GETLABEL(labelp)				\
67129499Sbde	__asm __volatile("movq $1b,%0" : "=rm" (labelp))
68129499Sbde#elif defined(lint)
69129499Sbde#define	MCOUNT_OVERHEAD(label)
70129499Sbde#define	MEXITCOUNT_OVERHEAD()
71129499Sbde#define	MEXITCOUNT_OVERHEAD_GETLABEL()
7217879Sbde#else
73129499Sbde#error
74129499Sbde#endif /* __GNUC */
75129499Sbde#else /* !GUPROF */
7617879Sbde#define	MCOUNT_DECL(s)	u_long s;
7728921Sfsmp#ifdef SMP
7890024Sbdeextern int	mcount_lock;
79114349Speter#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); \
8079734Sjhb 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
8178908Sjhb			  	/* nothing */ ; }
8278908Sjhb#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
83114349Speter			  write_rflags(s); }
8428921Sfsmp#else
85114349Speter#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); }
86114349Speter#define	MCOUNT_EXIT(s)	(write_rflags(s))
8728921Sfsmp#endif
8817879Sbde#endif /* GUPROF */
8917879Sbde
9055205Speter#else /* !_KERNEL */
9113157Sbde
9222639Sbde#define	FUNCTION_ALIGNMENT	4
9322639Sbde
94129408Speter#define	_MCOUNT_DECL \
95132846Skanstatic void _mcount(uintfptr_t frompc, uintfptr_t selfpc) __used; \
96129408Speterstatic void _mcount
9713157Sbde
9895195Smarkm#ifdef	__GNUC__
99129445Sbde#define	MCOUNT __asm("			\n\
100129408Speter	.globl	.mcount			\n\
101129408Speter	.type	.mcount @function	\n\
102129408Speter.mcount:				\n\
103129408Speter	pushq	%rbp			\n\
104129445Sbde	movq	%rsp,%rbp		\n\
105129408Speter	pushq	%rdi			\n\
106129408Speter	pushq	%rsi			\n\
107129408Speter	pushq	%rdx			\n\
108129408Speter	pushq	%rcx			\n\
109129408Speter	pushq	%r8			\n\
110129408Speter	pushq	%r9			\n\
111130321Speter	pushq	%rax			\n\
112129408Speter	movq	8(%rbp),%rsi		\n\
113129408Speter	movq	(%rbp),%rdi		\n\
114129408Speter	movq	8(%rdi),%rdi		\n\
115129408Speter	call	_mcount			\n\
116130321Speter	popq	%rax			\n\
117129408Speter	popq	%r9			\n\
118129408Speter	popq	%r8			\n\
119129408Speter	popq	%rcx			\n\
120129408Speter	popq	%rdx			\n\
121129408Speter	popq	%rsi			\n\
122129408Speter	popq	%rdi			\n\
123129408Speter	leave				\n\
124129408Speter	ret				\n\
125129408Speter	.size	.mcount, . - .mcount");
126129408Speter#if 0
127129408Speter/*
128129408Speter * We could use this, except it doesn't preserve the registers that were
129129408Speter * being passed with arguments to the function that we were inserted
130129408Speter * into.  I've left it here as documentation of what the code above is
131129408Speter * supposed to do.
132129408Speter */
13395195Smarkm#define	MCOUNT								\
13495195Smarkmvoid									\
13595195Smarkmmcount()								\
13695195Smarkm{									\
13795195Smarkm	uintfptr_t selfpc, frompc;					\
13895195Smarkm	/*								\
13995195Smarkm	 * Find the return address for mcount,				\
14095195Smarkm	 * and the return address for mcount's caller.			\
14195195Smarkm	 *								\
14295195Smarkm	 * selfpc = pc pushed by call to mcount				\
14395195Smarkm	 */								\
144115659Sobrien	__asm("movq 8(%%rbp),%0" : "=r" (selfpc));			\
14595195Smarkm	/*								\
14695195Smarkm	 * frompc = pc pushed by call to mcount's caller.		\
147129445Sbde	 * The caller's stack frame has already been built, so %rbp is	\
14895195Smarkm	 * the caller's frame pointer.  The caller's raddr is in the	\
14995195Smarkm	 * caller's frame following the caller's caller's frame pointer.\
15095195Smarkm	 */								\
151129408Speter	__asm("movq (%%rbp),%0" : "=r" (frompc));			\
15295195Smarkm	frompc = ((uintfptr_t *)frompc)[1];				\
15395195Smarkm	_mcount(frompc, selfpc);					\
1541543Srgrimes}
155129408Speter#endif
156129445Sbde#else /* !__GNUC__ */
157129445Sbde#define	MCOUNT								\
158129445Sbdevoid									\
159129445Sbdemcount()								\
160129445Sbde{									\
16195195Smarkm}
162129445Sbde#endif /* __GNUC__ */
16337542Sbde
164129445Sbdetypedef	u_long	uintfptr_t;
16537542Sbde
16655205Speter#endif /* _KERNEL */
1672166Spaul
16813107Sbde/*
16913107Sbde * An unsigned integral type that can hold non-negative difference between
17013107Sbde * function pointers.
17113107Sbde */
172129446Sbdetypedef	u_long	fptrdiff_t;
17313107Sbde
17455205Speter#ifdef _KERNEL
17519000Sbde
17692761Salfredvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
17719000Sbde
17855205Speter#else /* !_KERNEL */
17919000Sbde
18019000Sbde#include <sys/cdefs.h>
18119000Sbde
18219000Sbde__BEGIN_DECLS
18333047Sbde#ifdef __GNUC__
18492761Salfredvoid	mcount(void) __asm(".mcount");
18533047Sbde#endif
18619000Sbde__END_DECLS
18713157Sbde
18855205Speter#endif /* _KERNEL */
18919000Sbde
19013157Sbde#endif /* !_MACHINE_PROFILE_H_ */
191