profile.h revision 163735
1168404Spjd/*-
2168404Spjd * Copyright (c) 1992, 1993
3168404Spjd *	The Regents of the University of California.  All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd * 4. Neither the name of the University nor the names of its contributors
14168404Spjd *    may be used to endorse or promote products derived from this software
15168404Spjd *    without specific prior written permission.
16168404Spjd *
17168404Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27168404Spjd * SUCH DAMAGE.
28168404Spjd *
29168404Spjd *	@(#)profile.h	8.1 (Berkeley) 6/11/93
30169303Spjd * $FreeBSD: head/sys/amd64/include/profile.h 163735 2006-10-28 11:03:03Z bde $
31168404Spjd */
32168404Spjd
33168404Spjd#ifndef _MACHINE_PROFILE_H_
34168404Spjd#define	_MACHINE_PROFILE_H_
35168404Spjd
36169303Spjd#ifndef _SYS_CDEFS_H_
37168404Spjd#error this file needs sys/cdefs.h as a prerequisite
38168404Spjd#endif
39168404Spjd
40168404Spjd#ifdef _KERNEL
41168404Spjd
42168404Spjd/*
43168404Spjd * Config generates something to tell the compiler to align functions on 16
44168404Spjd * byte boundaries.  A strict alignment is good for keeping the tables small.
45168404Spjd */
46168404Spjd#define	FUNCTION_ALIGNMENT	16
47168404Spjd
48168404Spjd/*
49168404Spjd * The kernel uses assembler stubs instead of unportable inlines.
50168404Spjd * This is mainly to save a little time when profiling is not enabled,
51168404Spjd * which is the usual case for the kernel.
52168404Spjd */
53168404Spjd#define	_MCOUNT_DECL void mcount
54168404Spjd#define	MCOUNT
55168404Spjd
56168404Spjd#ifdef GUPROF
57168404Spjd#define	MCOUNT_DECL(s)
58168404Spjd#define	MCOUNT_ENTER(s)
59168404Spjd#define	MCOUNT_EXIT(s)
60168404Spjd#ifdef __GNUCLIKE_ASM
61168404Spjd#define	MCOUNT_OVERHEAD(label)						\
62168404Spjd	__asm __volatile("pushq %0; call __mcount; popq %%rcx"		\
63168404Spjd			 :						\
64168404Spjd			 : "i" (label)					\
65168404Spjd			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
66168404Spjd#define	MEXITCOUNT_OVERHEAD()						\
67168404Spjd	__asm __volatile("call .mexitcount; 1:"				\
68168404Spjd			 : :						\
69168404Spjd			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
70168404Spjd#define	MEXITCOUNT_OVERHEAD_GETLABEL(labelp)				\
71168404Spjd	__asm __volatile("movq $1b,%0" : "=rm" (labelp))
72168404Spjd#elif defined(lint)
73168404Spjd#define	MCOUNT_OVERHEAD(label)
74168404Spjd#define	MEXITCOUNT_OVERHEAD()
75168404Spjd#define	MEXITCOUNT_OVERHEAD_GETLABEL()
76168404Spjd#else
77168404Spjd#error this file needs to be ported to your compiler
78168404Spjd#endif /* !__GNUCLIKE_ASM */
79168404Spjd#else /* !GUPROF */
80168404Spjd#define	MCOUNT_DECL(s)	u_long s;
81168404Spjd#ifdef SMP
82168404Spjdextern int	mcount_lock;
83168404Spjd#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); \
84168404Spjd 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
85168404Spjd			  	/* nothing */ ; }
86168404Spjd#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
87168404Spjd			  write_rflags(s); }
88169303Spjd#else
89169303Spjd#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); }
90169087Spjd#define	MCOUNT_EXIT(s)	(write_rflags(s))
91168404Spjd#endif
92168404Spjd#endif /* GUPROF */
93168404Spjd
94168404Spjdvoid bintr(void);
95168404Spjdvoid btrap(void);
96169087Spjdvoid eintr(void);
97168404Spjdvoid user(void);
98168404Spjd
99185029Spjd#define	MCOUNT_FROMPC_USER(pc)					\
100185029Spjd	((pc < (uintfptr_t)VM_MAXUSER_ADDRESS) ? (uintfptr_t)user : pc)
101185029Spjd
102168404Spjd#define	MCOUNT_FROMPC_INTR(pc)					\
103168404Spjd	((pc >= (uintfptr_t)btrap && pc < (uintfptr_t)eintr) ?	\
104168404Spjd	    ((pc >= (uintfptr_t)bintr) ? (uintfptr_t)bintr :	\
105168404Spjd		(uintfptr_t)btrap) : ~0UL)
106168404Spjd
107168404Spjd#else /* !_KERNEL */
108168404Spjd
109168404Spjd#define	FUNCTION_ALIGNMENT	4
110168404Spjd
111168404Spjd#define	_MCOUNT_DECL \
112168404Spjdstatic void _mcount(uintfptr_t frompc, uintfptr_t selfpc) __used; \
113168404Spjdstatic void _mcount
114168404Spjd
115169303Spjd#ifdef __GNUCLIKE_ASM
116169303Spjd#define	MCOUNT __asm("			\n\
117169303Spjd	.globl	.mcount			\n\
118169303Spjd	.type	.mcount @function	\n\
119169303Spjd.mcount:				\n\
120168404Spjd	pushq	%rbp			\n\
121168404Spjd	movq	%rsp,%rbp		\n\
122168404Spjd	pushq	%rdi			\n\
123168404Spjd	pushq	%rsi			\n\
124168404Spjd	pushq	%rdx			\n\
125168404Spjd	pushq	%rcx			\n\
126168404Spjd	pushq	%r8			\n\
127168404Spjd	pushq	%r9			\n\
128168404Spjd	pushq	%rax			\n\
129168404Spjd	movq	8(%rbp),%rsi		\n\
130168404Spjd	movq	(%rbp),%rdi		\n\
131168404Spjd	movq	8(%rdi),%rdi		\n\
132168404Spjd	call	_mcount			\n\
133168404Spjd	popq	%rax			\n\
134168404Spjd	popq	%r9			\n\
135168404Spjd	popq	%r8			\n\
136168404Spjd	popq	%rcx			\n\
137168404Spjd	popq	%rdx			\n\
138168404Spjd	popq	%rsi			\n\
139168404Spjd	popq	%rdi			\n\
140168404Spjd	leave				\n\
141168404Spjd	ret				\n\
142168404Spjd	.size	.mcount, . - .mcount");
143168404Spjd#if 0
144168404Spjd/*
145168404Spjd * We could use this, except it doesn't preserve the registers that were
146168404Spjd * being passed with arguments to the function that we were inserted
147168404Spjd * into.  I've left it here as documentation of what the code above is
148168404Spjd * supposed to do.
149168404Spjd */
150168404Spjd#define	MCOUNT								\
151168404Spjdvoid									\
152168404Spjdmcount()								\
153168404Spjd{									\
154168404Spjd	uintfptr_t selfpc, frompc;					\
155168404Spjd	/*								\
156168404Spjd	 * Find the return address for mcount,				\
157168404Spjd	 * and the return address for mcount's caller.			\
158168404Spjd	 *								\
159168404Spjd	 * selfpc = pc pushed by call to mcount				\
160168404Spjd	 */								\
161168404Spjd	__asm("movq 8(%%rbp),%0" : "=r" (selfpc));			\
162168404Spjd	/*								\
163168404Spjd	 * frompc = pc pushed by call to mcount's caller.		\
164168404Spjd	 * The caller's stack frame has already been built, so %rbp is	\
165168404Spjd	 * the caller's frame pointer.  The caller's raddr is in the	\
166168404Spjd	 * caller's frame following the caller's caller's frame pointer.\
167168404Spjd	 */								\
168168404Spjd	__asm("movq (%%rbp),%0" : "=r" (frompc));			\
169168404Spjd	frompc = ((uintfptr_t *)frompc)[1];				\
170168404Spjd	_mcount(frompc, selfpc);					\
171168404Spjd}
172168404Spjd#endif
173168404Spjd#else /* !__GNUCLIKE_ASM */
174168404Spjd#define	MCOUNT
175168404Spjd#endif /* __GNUCLIKE_ASM */
176168404Spjd
177168404Spjdtypedef	u_long	uintfptr_t;
178168404Spjd
179168404Spjd#endif /* _KERNEL */
180168404Spjd
181168404Spjd/*
182168404Spjd * An unsigned integral type that can hold non-negative difference between
183168404Spjd * function pointers.
184168404Spjd */
185168404Spjdtypedef	u_long	fptrdiff_t;
186168404Spjd
187168404Spjd#ifdef _KERNEL
188168404Spjd
189168404Spjdvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
190168404Spjd
191168404Spjd#else /* !_KERNEL */
192168404Spjd
193168404Spjd#include <sys/cdefs.h>
194168404Spjd
195168404Spjd__BEGIN_DECLS
196168404Spjd#ifdef __GNUCLIKE_ASM
197168404Spjdvoid	mcount(void) __asm(".mcount");
198168404Spjd#endif
199168404Spjd__END_DECLS
200168404Spjd
201168404Spjd#endif /* _KERNEL */
202168404Spjd
203168404Spjd#endif /* !_MACHINE_PROFILE_H_ */
204168404Spjd