xref: /freebsd/sys/sys/pmclog.h (revision 5506ceb8)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005-2007, Joseph Koshy
5  * Copyright (c) 2007 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * Portions of this software were developed by A. Joseph Koshy under
9  * sponsorship from the FreeBSD Foundation and Google, Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 
35 #ifndef	_SYS_PMCLOG_H_
36 #define	_SYS_PMCLOG_H_
37 
38 #include <sys/pmc.h>
39 
40 enum pmclog_type {
41 	/* V1 ABI */
42 	PMCLOG_TYPE_CLOSELOG,
43 	PMCLOG_TYPE_DROPNOTIFY,
44 	PMCLOG_TYPE_INITIALIZE,
45 	PMCLOG_TYPE_MAPPINGCHANGE, /* unused in v1 */
46 	PMCLOG_TYPE_PCSAMPLE,
47 	PMCLOG_TYPE_PMCALLOCATE,
48 	PMCLOG_TYPE_PMCATTACH,
49 	PMCLOG_TYPE_PMCDETACH,
50 	PMCLOG_TYPE_PROCCSW,
51 	PMCLOG_TYPE_PROCEXEC,
52 	PMCLOG_TYPE_PROCEXIT,
53 	PMCLOG_TYPE_PROCFORK,
54 	PMCLOG_TYPE_SYSEXIT,
55 	PMCLOG_TYPE_USERDATA,
56 	/*
57 	 * V2 ABI
58 	 *
59 	 * The MAP_{IN,OUT} event types obsolete the MAPPING_CHANGE
60 	 * event type.  The CALLCHAIN event type obsoletes the
61 	 * PCSAMPLE event type.
62 	 */
63 	PMCLOG_TYPE_MAP_IN,
64 	PMCLOG_TYPE_MAP_OUT,
65 	PMCLOG_TYPE_CALLCHAIN,
66 	/*
67 	 * V3 ABI
68 	 *
69 	 * New variant of PMCLOG_TYPE_PMCALLOCATE for dynamic event.
70 	 */
71 	PMCLOG_TYPE_PMCALLOCATEDYN
72 };
73 
74 /*
75  * A log entry descriptor comprises of a 32 bit header and a 64 bit
76  * time stamp followed by as many 32 bit words are required to record
77  * the event.
78  *
79  * Header field format:
80  *
81  *  31           24           16                                   0
82  *   +------------+------------+-----------------------------------+
83  *   |    MAGIC   |    TYPE    |               LENGTH              |
84  *   +------------+------------+-----------------------------------+
85  *
86  * MAGIC 	is the constant PMCLOG_HEADER_MAGIC.
87  * TYPE  	contains a value of type enum pmclog_type.
88  * LENGTH	contains the length of the event record, in bytes.
89  */
90 
91 #define	PMCLOG_ENTRY_HEADER				\
92 	uint32_t		pl_header;		\
93 	uint32_t		pl_ts_sec;		\
94 	uint32_t		pl_ts_nsec;
95 
96 
97 /*
98  * The following structures are used to describe the size of each kind
99  * of log entry to sizeof().  To keep the compiler from adding
100  * padding, the fields of each structure are aligned to their natural
101  * boundaries, and the structures are marked as 'packed'.
102  *
103  * The actual reading and writing of the log file is always in terms
104  * of 4 byte quantities.
105  */
106 
107 struct pmclog_callchain {
108 	PMCLOG_ENTRY_HEADER
109 	uint32_t		pl_pid;
110 	uint32_t		pl_tid;
111 	uint32_t		pl_pmcid;
112 	uint32_t		pl_cpuflags;
113 	uint32_t		pl_cpuflags2;
114 	/* 8 byte aligned */
115 	uintptr_t		pl_pc[PMC_CALLCHAIN_DEPTH_MAX];
116 } __packed;
117 
118 #define	PMC_CALLCHAIN_CPUFLAGS_TO_CPU(CF)	(((CF) >> 16) & 0xFFFF)
119 #define	PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(CF)	((CF) & PMC_CC_F_USERSPACE)
120 #define	PMC_CALLCHAIN_TO_CPUFLAGS(CPU,FLAGS)	\
121 	(((CPU) << 16) | ((FLAGS) & 0xFFFF))
122 
123 struct pmclog_closelog {
124 	PMCLOG_ENTRY_HEADER
125 };
126 
127 struct pmclog_dropnotify {
128 	PMCLOG_ENTRY_HEADER
129 };
130 
131 struct pmclog_initialize {
132 	PMCLOG_ENTRY_HEADER
133 	uint32_t		pl_version;	/* driver version */
134 	uint32_t		pl_cpu;		/* enum pmc_cputype */
135 } __packed;
136 
137 struct pmclog_map_in {
138 	PMCLOG_ENTRY_HEADER
139 	uint32_t		pl_pid;
140 	uintfptr_t		pl_start;	/* 8 byte aligned */
141 	char			pl_pathname[PATH_MAX];
142 } __packed;
143 
144 struct pmclog_map_out {
145 	PMCLOG_ENTRY_HEADER
146 	uint32_t		pl_pid;
147 	uintfptr_t		pl_start;	/* 8 byte aligned */
148 	uintfptr_t		pl_end;
149 } __packed;
150 
151 struct pmclog_pcsample {
152 	PMCLOG_ENTRY_HEADER
153 	uint32_t		pl_pid;
154 	uintfptr_t		pl_pc;		/* 8 byte aligned */
155 	uint32_t		pl_pmcid;
156 	uint32_t		pl_usermode;
157 	uint32_t		pl_tid;
158 	uint32_t		pl_pad;
159 } __packed;
160 
161 struct pmclog_pmcallocate {
162 	PMCLOG_ENTRY_HEADER
163 	uint32_t		pl_pmcid;
164 	uint32_t		pl_event;
165 	uint32_t		pl_flags;
166 } __packed;
167 
168 struct pmclog_pmcattach {
169 	PMCLOG_ENTRY_HEADER
170 	uint32_t		pl_pmcid;
171 	uint32_t		pl_pid;
172 	char			pl_pathname[PATH_MAX];
173 } __packed;
174 
175 struct pmclog_pmcdetach {
176 	PMCLOG_ENTRY_HEADER
177 	uint32_t		pl_pmcid;
178 	uint32_t		pl_pid;
179 } __packed;
180 
181 struct pmclog_proccsw {
182 	PMCLOG_ENTRY_HEADER
183 	uint32_t		pl_pmcid;
184 	uint64_t		pl_value;	/* keep 8 byte aligned */
185 	uint32_t		pl_pid;
186 	uint32_t		pl_tid;
187 } __packed;
188 
189 struct pmclog_procexec {
190 	PMCLOG_ENTRY_HEADER
191 	uint32_t		pl_pid;
192 	uintfptr_t		pl_start;	/* keep 8 byte aligned */
193 	uint32_t		pl_pmcid;
194 	char			pl_pathname[PATH_MAX];
195 } __packed;
196 
197 struct pmclog_procexit {
198 	PMCLOG_ENTRY_HEADER
199 	uint32_t		pl_pmcid;
200 	uint64_t		pl_value;	/* keep 8 byte aligned */
201 	uint32_t		pl_pid;
202 } __packed;
203 
204 struct pmclog_procfork {
205 	PMCLOG_ENTRY_HEADER
206 	uint32_t		pl_oldpid;
207 	uint32_t		pl_newpid;
208 } __packed;
209 
210 struct pmclog_sysexit {
211 	PMCLOG_ENTRY_HEADER
212 	uint32_t		pl_pid;
213 } __packed;
214 
215 struct pmclog_userdata {
216 	PMCLOG_ENTRY_HEADER
217 	uint32_t		pl_userdata;
218 } __packed;
219 
220 struct pmclog_pmcallocatedyn {
221 	PMCLOG_ENTRY_HEADER
222 	uint32_t		pl_pmcid;
223 	uint32_t		pl_event;
224 	uint32_t		pl_flags;
225 	char			pl_evname[PMC_NAME_MAX];
226 } __packed;
227 
228 union pmclog_entry {		/* only used to size scratch areas */
229 	struct pmclog_callchain		pl_cc;
230 	struct pmclog_closelog		pl_cl;
231 	struct pmclog_dropnotify	pl_dn;
232 	struct pmclog_initialize	pl_i;
233 	struct pmclog_map_in		pl_mi;
234 	struct pmclog_map_out		pl_mo;
235 	struct pmclog_pcsample		pl_s;
236 	struct pmclog_pmcallocate	pl_a;
237 	struct pmclog_pmcallocatedyn	pl_ad;
238 	struct pmclog_pmcattach		pl_t;
239 	struct pmclog_pmcdetach		pl_d;
240 	struct pmclog_proccsw		pl_c;
241 	struct pmclog_procexec		pl_x;
242 	struct pmclog_procexit		pl_e;
243 	struct pmclog_procfork		pl_f;
244 	struct pmclog_sysexit		pl_se;
245 	struct pmclog_userdata		pl_u;
246 };
247 
248 #define	PMCLOG_HEADER_MAGIC					0xEEU
249 
250 #define	PMCLOG_HEADER_TO_LENGTH(H)				\
251 	((H) & 0x0000FFFF)
252 #define	PMCLOG_HEADER_TO_TYPE(H)				\
253 	(((H) & 0x00FF0000) >> 16)
254 #define	PMCLOG_HEADER_TO_MAGIC(H)				\
255 	(((H) & 0xFF000000) >> 24)
256 #define	PMCLOG_HEADER_CHECK_MAGIC(H)				\
257 	(PMCLOG_HEADER_TO_MAGIC(H) == PMCLOG_HEADER_MAGIC)
258 
259 #ifdef	_KERNEL
260 
261 /*
262  * Prototypes
263  */
264 int	pmclog_configure_log(struct pmc_mdep *_md, struct pmc_owner *_po,
265     int _logfd);
266 int	pmclog_deconfigure_log(struct pmc_owner *_po);
267 int	pmclog_flush(struct pmc_owner *_po);
268 int	pmclog_close(struct pmc_owner *_po);
269 void	pmclog_initialize(void);
270 int	pmclog_proc_create(struct thread *td, void **handlep);
271 void	pmclog_proc_ignite(void *handle, struct pmc_owner *po);
272 void	pmclog_process_callchain(struct pmc *_pm, struct pmc_sample *_ps);
273 void	pmclog_process_closelog(struct pmc_owner *po);
274 void	pmclog_process_dropnotify(struct pmc_owner *po);
275 void	pmclog_process_map_in(struct pmc_owner *po, pid_t pid,
276     uintfptr_t start, const char *path);
277 void	pmclog_process_map_out(struct pmc_owner *po, pid_t pid,
278     uintfptr_t start, uintfptr_t end);
279 void	pmclog_process_pmcallocate(struct pmc *_pm);
280 void	pmclog_process_pmcattach(struct pmc *_pm, pid_t _pid, char *_path);
281 void	pmclog_process_pmcdetach(struct pmc *_pm, pid_t _pid);
282 void	pmclog_process_proccsw(struct pmc *_pm, struct pmc_process *_pp,
283     pmc_value_t _v, struct thread *);
284 void	pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid,
285     uintfptr_t _startaddr, char *_path);
286 void	pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp);
287 void	pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid);
288 void	pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid);
289 int	pmclog_process_userlog(struct pmc_owner *_po,
290     struct pmc_op_writelog *_wl);
291 void	pmclog_shutdown(void);
292 #endif	/* _KERNEL */
293 
294 #endif	/* _SYS_PMCLOG_H_ */
295