1139790Simp/*-
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$
311543Srgrimes */
321543Srgrimes
3313107Sbde#ifndef _MACHINE_PROFILE_H_
3413107Sbde#define	_MACHINE_PROFILE_H_
352166Spaul
36143063Sjoerg#ifndef _SYS_CDEFS_H_
37143063Sjoerg#error this file needs sys/cdefs.h as a prerequisite
38143063Sjoerg#endif
39143063Sjoerg
4055205Speter#ifdef _KERNEL
4137542Sbde
4213157Sbde/*
4322639Sbde * Config generates something to tell the compiler to align functions on 16
4422639Sbde * byte boundaries.  A strict alignment is good for keeping the tables small.
4522639Sbde */
4622639Sbde#define	FUNCTION_ALIGNMENT	16
4722639Sbde
4822639Sbde/*
4913157Sbde * The kernel uses assembler stubs instead of unportable inlines.
5013157Sbde * This is mainly to save a little time when profiling is not enabled,
5113157Sbde * which is the usual case for the kernel.
5213157Sbde */
5313157Sbde#define	_MCOUNT_DECL void mcount
5413157Sbde#define	MCOUNT
551543Srgrimes
5617879Sbde#ifdef GUPROF
5717879Sbde#define	MCOUNT_DECL(s)
5817879Sbde#define	MCOUNT_ENTER(s)
5917879Sbde#define	MCOUNT_EXIT(s)
60143063Sjoerg#ifdef __GNUCLIKE_ASM
61129498Sbde#define	MCOUNT_OVERHEAD(label)						\
62129498Sbde	__asm __volatile("pushl %0; call __mcount; popl %%ecx"		\
63129498Sbde			 :						\
64163729Sbde			 : "i" (label)					\
65129498Sbde			 : "ax", "dx", "cx", "memory")
66129498Sbde#define	MEXITCOUNT_OVERHEAD()						\
67129498Sbde	__asm __volatile("call .mexitcount; 1:"				\
68129498Sbde			 : :						\
69129498Sbde			 : "ax", "dx", "cx", "memory")
70129498Sbde#define	MEXITCOUNT_OVERHEAD_GETLABEL(labelp)				\
71129498Sbde	__asm __volatile("movl $1b,%0" : "=rm" (labelp))
72129498Sbde#elif defined(lint)
73129498Sbde#define	MCOUNT_OVERHEAD(label)
74129498Sbde#define	MEXITCOUNT_OVERHEAD()
75129498Sbde#define	MEXITCOUNT_OVERHEAD_GETLABEL()
7617879Sbde#else
77129498Sbde#error
78143063Sjoerg#endif /* !__GNUCLIKE_ASM */
79129498Sbde#else /* !GUPROF */
80214346Sjhb#define	MCOUNT_DECL(s)	register_t s;
8128921Sfsmp#ifdef SMP
8290024Sbdeextern int	mcount_lock;
83214346Sjhb#define	MCOUNT_ENTER(s)	{ s = intr_disable(); \
8479734Sjhb 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
8578908Sjhb			  	/* nothing */ ; }
8678908Sjhb#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
87214346Sjhb			  intr_restore(s); }
8828921Sfsmp#else
89214346Sjhb#define	MCOUNT_ENTER(s)	{ s = intr_disable(); }
90214346Sjhb#define	MCOUNT_EXIT(s)	(intr_restore(s))
9128921Sfsmp#endif
9217879Sbde#endif /* GUPROF */
9317879Sbde
94134398Smarcelvoid bintr(void);
95134398Smarcelvoid btrap(void);
96134398Smarcelvoid eintr(void);
97134398Smarcelvoid user(void);
98134398Smarcel
99134398Smarcel#define	MCOUNT_FROMPC_USER(pc)					\
100134398Smarcel	((pc < (uintfptr_t)VM_MAXUSER_ADDRESS) ? (uintfptr_t)user : pc)
101134398Smarcel
102134398Smarcel#define	MCOUNT_FROMPC_INTR(pc)					\
103134398Smarcel	((pc >= (uintfptr_t)btrap && pc < (uintfptr_t)eintr) ?	\
104134398Smarcel	    ((pc >= (uintfptr_t)bintr) ? (uintfptr_t)bintr :	\
105134398Smarcel		(uintfptr_t)btrap) : ~0U)
106134398Smarcel
10755205Speter#else /* !_KERNEL */
10813157Sbde
10922639Sbde#define	FUNCTION_ALIGNMENT	4
11022639Sbde
11113157Sbde#define	_MCOUNT_DECL static __inline void _mcount
11213157Sbde
113143063Sjoerg#ifdef __GNUCLIKE_ASM
11495195Smarkm#define	MCOUNT								\
11595195Smarkmvoid									\
11695195Smarkmmcount()								\
11795195Smarkm{									\
118180756Sluoqi	uintfptr_t selfpc, frompc, ecx;					\
11995195Smarkm	/*								\
120180756Sluoqi	 * In gcc 4.2, ecx might be used in the caller as the arg	\
121180756Sluoqi	 * pointer if the stack realignment option is set (-mstackrealign) \
122180756Sluoqi	 * or if the caller has the force_align_arg_pointer attribute	\
123180756Sluoqi	 * (stack realignment is ALWAYS on for main).  Preserve ecx	\
124180756Sluoqi	 * here.							\
125180756Sluoqi	 */								\
126180756Sluoqi	__asm("" : "=c" (ecx));						\
127180756Sluoqi	/*								\
12895195Smarkm	 * Find the return address for mcount,				\
12995195Smarkm	 * and the return address for mcount's caller.			\
13095195Smarkm	 *								\
13195195Smarkm	 * selfpc = pc pushed by call to mcount				\
13295195Smarkm	 */								\
133115659Sobrien	__asm("movl 4(%%ebp),%0" : "=r" (selfpc));			\
13495195Smarkm	/*								\
13595195Smarkm	 * frompc = pc pushed by call to mcount's caller.		\
13695195Smarkm	 * The caller's stack frame has already been built, so %ebp is	\
13795195Smarkm	 * the caller's frame pointer.  The caller's raddr is in the	\
13895195Smarkm	 * caller's frame following the caller's caller's frame pointer.\
13995195Smarkm	 */								\
140129445Sbde	__asm("movl (%%ebp),%0" : "=r" (frompc));			\
14195195Smarkm	frompc = ((uintfptr_t *)frompc)[1];				\
14295195Smarkm	_mcount(frompc, selfpc);					\
143180756Sluoqi	__asm("" : : "c" (ecx));					\
1441543Srgrimes}
145143063Sjoerg#else /* !__GNUCLIKE_ASM */
146163735Sbde#define	MCOUNT
147143063Sjoerg#endif /* __GNUCLIKE_ASM */
14837542Sbde
149129445Sbdetypedef	u_int	uintfptr_t;
15037542Sbde
15155205Speter#endif /* _KERNEL */
1522166Spaul
15313107Sbde/*
15413107Sbde * An unsigned integral type that can hold non-negative difference between
15513107Sbde * function pointers.
15613107Sbde */
15731723Steggetypedef	u_int	fptrdiff_t;
15813107Sbde
15955205Speter#ifdef _KERNEL
16019000Sbde
16192761Salfredvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
16219000Sbde
16355205Speter#else /* !_KERNEL */
16419000Sbde
16519000Sbde#include <sys/cdefs.h>
16619000Sbde
16719000Sbde__BEGIN_DECLS
168143063Sjoerg#ifdef __GNUCLIKE_ASM
16992761Salfredvoid	mcount(void) __asm(".mcount");
17033047Sbde#endif
17119000Sbde__END_DECLS
17213157Sbde
17355205Speter#endif /* _KERNEL */
17419000Sbde
17513157Sbde#endif /* !_MACHINE_PROFILE_H_ */
176