profile.h revision 134398
1116742Ssam/*
2116904Ssam * Copyright (c) 1992, 1993
3186904Ssam *	The Regents of the University of California.  All rights reserved.
4116742Ssam *
5116742Ssam * Redistribution and use in source and binary forms, with or without
6116742Ssam * modification, are permitted provided that the following conditions
7116742Ssam * are met:
8116742Ssam * 1. Redistributions of source code must retain the above copyright
9116742Ssam *    notice, this list of conditions and the following disclaimer.
10116742Ssam * 2. Redistributions in binary form must reproduce the above copyright
11116742Ssam *    notice, this list of conditions and the following disclaimer in the
12116742Ssam *    documentation and/or other materials provided with the distribution.
13116742Ssam * 4. Neither the name of the University nor the names of its contributors
14116742Ssam *    may be used to endorse or promote products derived from this software
15116904Ssam *    without specific prior written permission.
16116904Ssam *
17116904Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18116904Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19116904Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20116904Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21116904Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22116904Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23116904Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24116904Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25116904Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26116742Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27116742Ssam * SUCH DAMAGE.
28116742Ssam *
29116742Ssam *	@(#)profile.h	8.1 (Berkeley) 6/11/93
30116742Ssam * $FreeBSD: head/sys/amd64/include/profile.h 134398 2004-08-27 19:42:35Z marcel $
31116742Ssam */
32116742Ssam
33116742Ssam#ifndef _MACHINE_PROFILE_H_
34138568Ssam#define	_MACHINE_PROFILE_H_
35201793Strasz
36138568Ssam#ifdef _KERNEL
37201793Strasz
38138568Ssam/*
39201793Strasz * Config generates something to tell the compiler to align functions on 16
40138568Ssam * byte boundaries.  A strict alignment is good for keeping the tables small.
41138568Ssam */
42138568Ssam#define	FUNCTION_ALIGNMENT	16
43138568Ssam
44138568Ssam/*
45138568Ssam * The kernel uses assembler stubs instead of unportable inlines.
46116742Ssam * This is mainly to save a little time when profiling is not enabled,
47195379Ssam * which is the usual case for the kernel.
48116742Ssam */
49178354Ssam#define	_MCOUNT_DECL void mcount
50121180Ssam#define	MCOUNT
51190532Ssam
52184288Ssam#ifdef GUPROF
53116742Ssam#define	MCOUNT_DECL(s)
54116742Ssam#define	MCOUNT_ENTER(s)
55192468Ssam#define	MCOUNT_EXIT(s)
56170530Ssam#ifdef __GNUC__
57116742Ssam#define	MCOUNT_OVERHEAD(label)						\
58251766Seadler	__asm __volatile("pushq %0; call __mcount; popq %%rcx"		\
59138568Ssam			 :						\
60116742Ssam			 : "i" (profil)					\
61138568Ssam			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
62140754Ssam#define	MEXITCOUNT_OVERHEAD()						\
63116742Ssam	__asm __volatile("call .mexitcount; 1:"				\
64153349Ssam			 : :						\
65155688Ssam			 : "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
66153349Ssam#define	MEXITCOUNT_OVERHEAD_GETLABEL(labelp)				\
67170530Ssam	__asm __volatile("movq $1b,%0" : "=rm" (labelp))
68170530Ssam#elif defined(lint)
69170530Ssam#define	MCOUNT_OVERHEAD(label)
70170530Ssam#define	MEXITCOUNT_OVERHEAD()
71170530Ssam#define	MEXITCOUNT_OVERHEAD_GETLABEL()
72170530Ssam#else
73170530Ssam#error
74170530Ssam#endif /* __GNUC */
75170530Ssam#else /* !GUPROF */
76138568Ssam#define	MCOUNT_DECL(s)	u_long s;
77138568Ssam#ifdef SMP
78116742Ssamextern int	mcount_lock;
79178354Ssam#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); \
80178354Ssam 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
81148290Ssam			  	/* nothing */ ; }
82148291Ssam#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
83148291Ssam			  write_rflags(s); }
84148291Ssam#else
85167242Ssam#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); }
86167242Ssam#define	MCOUNT_EXIT(s)	(write_rflags(s))
87167242Ssam#endif
88140754Ssam#endif /* GUPROF */
89178354Ssam
90178354Ssamvoid bintr(void);
91178354Ssamvoid btrap(void);
92178354Ssamvoid eintr(void);
93178354Ssamvoid user(void);
94178354Ssam
95178354Ssam#define	MCOUNT_FROMPC_USER(pc)					\
96178354Ssam	((pc < (uintfptr_t)VM_MAXUSER_ADDRESS) ? (uintfptr_t)user : pc)
97116742Ssam
98178354Ssam#define	MCOUNT_FROMPC_INTR(pc)					\
99178354Ssam	((pc >= (uintfptr_t)btrap && pc < (uintfptr_t)eintr) ?	\
100178354Ssam	    ((pc >= (uintfptr_t)bintr) ? (uintfptr_t)bintr :	\
101178354Ssam		(uintfptr_t)btrap) : ~0UL)
102178354Ssam
103178354Ssam#else /* !_KERNEL */
104178354Ssam
105178354Ssam#define	FUNCTION_ALIGNMENT	4
106178354Ssam
107178354Ssam#define	_MCOUNT_DECL \
108178354Ssamstatic void _mcount(uintfptr_t frompc, uintfptr_t selfpc) __used; \
109178354Ssamstatic void _mcount
110178354Ssam
111186904Ssam#ifdef	__GNUC__
112190579Ssam#define	MCOUNT __asm("			\n\
113191554Ssam	.globl	.mcount			\n\
114191554Ssam	.type	.mcount @function	\n\
115191753Ssam.mcount:				\n\
116195377Ssam	pushq	%rbp			\n\
117186904Ssam	movq	%rsp,%rbp		\n\
118138568Ssam	pushq	%rdi			\n\
119283531Sglebius	pushq	%rsi			\n\
120283527Sglebius	pushq	%rdx			\n\
121170530Ssam	pushq	%rcx			\n\
122248069Sadrian	pushq	%r8			\n\
123286410Sglebius	pushq	%r9			\n\
124178354Ssam	pushq	%rax			\n\
125170530Ssam	movq	8(%rbp),%rsi		\n\
126170530Ssam	movq	(%rbp),%rdi		\n\
127170530Ssam	movq	8(%rdi),%rdi		\n\
128178354Ssam	call	_mcount			\n\
129191746Sthompsa	popq	%rax			\n\
130178354Ssam	popq	%r9			\n\
131191746Sthompsa	popq	%r8			\n\
132191746Sthompsa	popq	%rcx			\n\
133191746Sthompsa	popq	%rdx			\n\
134191746Sthompsa	popq	%rsi			\n\
135233452Sadrian	popq	%rdi			\n\
136127648Ssam	leave				\n\
137283567Sglebius	ret				\n\
138283567Sglebius	.size	.mcount, . - .mcount");
139283567Sglebius#if 0
140170530Ssam/*
141170530Ssam * We could use this, except it doesn't preserve the registers that were
142193655Ssam * being passed with arguments to the function that we were inserted
143173273Ssam * into.  I've left it here as documentation of what the code above is
144170530Ssam * supposed to do.
145173273Ssam */
146205513Srpaulo#define	MCOUNT								\
147178354Ssamvoid									\
148170530Ssammcount()								\
149178354Ssam{									\
150178354Ssam	uintfptr_t selfpc, frompc;					\
151178354Ssam	/*								\
152178354Ssam	 * Find the return address for mcount,				\
153286410Sglebius	 * and the return address for mcount's caller.			\
154170530Ssam	 *								\
155170530Ssam	 * selfpc = pc pushed by call to mcount				\
156170530Ssam	 */								\
157170530Ssam	__asm("movq 8(%%rbp),%0" : "=r" (selfpc));			\
158178354Ssam	/*								\
159170530Ssam	 * frompc = pc pushed by call to mcount's caller.		\
160170530Ssam	 * The caller's stack frame has already been built, so %rbp is	\
161170530Ssam	 * the caller's frame pointer.  The caller's raddr is in the	\
162170530Ssam	 * caller's frame following the caller's caller's frame pointer.\
163170530Ssam	 */								\
164170530Ssam	__asm("movq (%%rbp),%0" : "=r" (frompc));			\
165170530Ssam	frompc = ((uintfptr_t *)frompc)[1];				\
166170530Ssam	_mcount(frompc, selfpc);					\
167170530Ssam}
168170530Ssam#endif
169170530Ssam#else /* !__GNUC__ */
170170530Ssam#define	MCOUNT								\
171170530Ssamvoid									\
172170530Ssammcount()								\
173170530Ssam{									\
174170530Ssam}
175170530Ssam#endif /* __GNUC__ */
176170530Ssam
177170530Ssamtypedef	u_long	uintfptr_t;
178170530Ssam
179170530Ssam#endif /* _KERNEL */
180170530Ssam
181186107Ssam/*
182170530Ssam * An unsigned integral type that can hold non-negative difference between
183170530Ssam * function pointers.
184170530Ssam */
185170530Ssamtypedef	u_long	fptrdiff_t;
186190532Ssam
187170530Ssam#ifdef _KERNEL
188170530Ssam
189178354Ssamvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
190178354Ssam
191178354Ssam#else /* !_KERNEL */
192170530Ssam
193178354Ssam#include <sys/cdefs.h>
194178354Ssam
195193439Ssam__BEGIN_DECLS
196193439Ssam#ifdef __GNUC__
197178354Ssamvoid	mcount(void) __asm(".mcount");
198178354Ssam#endif
199170530Ssam__END_DECLS
200284143Sadrian
201170530Ssam#endif /* _KERNEL */
202170530Ssam
203170530Ssam#endif /* !_MACHINE_PROFILE_H_ */
204178354Ssam