1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
33#ifndef	_SYS_PMCLOG_H_
34#define	_SYS_PMCLOG_H_
35
36#include <sys/pmc.h>
37
38enum pmclog_type {
39	/* V1 ABI */
40	PMCLOG_TYPE_CLOSELOG = 1,
41	PMCLOG_TYPE_DROPNOTIFY = 2,
42	PMCLOG_TYPE_INITIALIZE = 3,
43
44	PMCLOG_TYPE_PMCALLOCATE = 5,
45	PMCLOG_TYPE_PMCATTACH = 6,
46	PMCLOG_TYPE_PMCDETACH = 7,
47	PMCLOG_TYPE_PROCCSW = 8,
48	PMCLOG_TYPE_PROCEXEC = 9,
49	PMCLOG_TYPE_PROCEXIT = 10,
50	PMCLOG_TYPE_PROCFORK = 11,
51	PMCLOG_TYPE_SYSEXIT = 12,
52	PMCLOG_TYPE_USERDATA = 13,
53	/*
54	 * V2 ABI
55	 *
56	 * The MAP_{IN,OUT} event types obsolete the MAPPING_CHANGE
57	 * event type.  The CALLCHAIN event type obsoletes the
58	 * PCSAMPLE event type.
59	 */
60	PMCLOG_TYPE_MAP_IN = 14,
61	PMCLOG_TYPE_MAP_OUT = 15,
62	PMCLOG_TYPE_CALLCHAIN = 16,
63	/*
64	 * V3 ABI
65	 *
66	 * New variant of PMCLOG_TYPE_PMCALLOCATE for dynamic event.
67	 */
68	PMCLOG_TYPE_PMCALLOCATEDYN = 17,
69	/*
70	 * V6 ABI
71	 */
72	PMCLOG_TYPE_THR_CREATE = 18,
73	PMCLOG_TYPE_THR_EXIT = 19,
74	PMCLOG_TYPE_PROC_CREATE = 20
75};
76
77/*
78 * A log entry descriptor comprises of a 32 bit header and a 64 bit
79 * time stamp followed by as many 32 bit words are required to record
80 * the event.
81 *
82 * Header field format:
83 *
84 *  31           24           16                                   0
85 *   +------------+------------+-----------------------------------+
86 *   |    MAGIC   |    TYPE    |               LENGTH              |
87 *   +------------+------------+-----------------------------------+
88 *
89 * MAGIC 	is the constant PMCLOG_HEADER_MAGIC.
90 * TYPE  	contains a value of type enum pmclog_type.
91 * LENGTH	contains the length of the event record, in bytes.
92 */
93
94#define	PMCLOG_ENTRY_HEADER				\
95	uint32_t		pl_header;			\
96	uint32_t		pl_spare;			\
97	uint64_t		pl_tsc;			\
98
99struct pmclog_header {
100	PMCLOG_ENTRY_HEADER;
101};
102
103/*
104 * The following structures are used to describe the size of each kind
105 * of log entry to sizeof().  To keep the compiler from adding
106 * padding, the fields of each structure are aligned to their natural
107 * boundaries, and the structures are marked as 'packed'.
108 *
109 * The actual reading and writing of the log file is always in terms
110 * of 4 byte quantities.
111 */
112
113struct pmclog_callchain {
114	PMCLOG_ENTRY_HEADER
115	uint32_t		pl_pid;
116	uint32_t		pl_tid;
117	uint32_t		pl_pmcid;
118	uint32_t		pl_cpuflags;
119	/* 8 byte aligned */
120	uintptr_t		pl_pc[PMC_CALLCHAIN_DEPTH_MAX];
121} __packed;
122
123#define	PMC_CALLCHAIN_CPUFLAGS_TO_CPU(CF)	(((CF) >> 16) & 0xFFFF)
124#define	PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(CF)	((CF) & PMC_CC_F_USERSPACE)
125#define	PMC_CALLCHAIN_TO_CPUFLAGS(CPU,FLAGS)	\
126	(((CPU) << 16) | ((FLAGS) & 0xFFFF))
127
128struct pmclog_closelog {
129	PMCLOG_ENTRY_HEADER
130};
131
132struct pmclog_dropnotify {
133	PMCLOG_ENTRY_HEADER
134};
135
136struct pmclog_initialize {
137	PMCLOG_ENTRY_HEADER
138	uint32_t		pl_version;	/* driver version */
139	uint32_t		pl_cpu;		/* enum pmc_cputype */
140	uint64_t		pl_tsc_freq;
141	struct timespec	pl_ts;
142	char			pl_cpuid[PMC_CPUID_LEN];
143} __packed;
144
145struct pmclog_map_in {
146	PMCLOG_ENTRY_HEADER
147	uint32_t		pl_pid;
148	uint32_t		pl_pad;
149	uintfptr_t		pl_start;	/* 8 byte aligned */
150	char			pl_pathname[PATH_MAX];
151} __packed;
152
153struct pmclog_map_out {
154	PMCLOG_ENTRY_HEADER
155	uint32_t		pl_pid;
156	uint32_t		pl_pad;
157	uintfptr_t		pl_start;	/* 8 byte aligned */
158	uintfptr_t		pl_end;
159} __packed;
160
161struct pmclog_pmcallocate {
162	PMCLOG_ENTRY_HEADER
163	uint32_t		pl_pmcid;
164	uint32_t		pl_event;
165	uint32_t		pl_flags;
166	uint32_t		pl_pad;
167	uint64_t		pl_rate;
168} __packed;
169
170struct pmclog_pmcattach {
171	PMCLOG_ENTRY_HEADER
172	uint32_t		pl_pmcid;
173	uint32_t		pl_pid;
174	char			pl_pathname[PATH_MAX];
175} __packed;
176
177struct pmclog_pmcdetach {
178	PMCLOG_ENTRY_HEADER
179	uint32_t		pl_pmcid;
180	uint32_t		pl_pid;
181} __packed;
182
183struct pmclog_proccsw {
184	PMCLOG_ENTRY_HEADER
185	uint64_t		pl_value;	/* keep 8 byte aligned */
186	uint32_t		pl_pmcid;
187	uint32_t		pl_pid;
188	uint32_t		pl_tid;
189	uint32_t		pl_pad;
190} __packed;
191
192struct pmclog_proccreate {
193	PMCLOG_ENTRY_HEADER
194	uint32_t		pl_pid;
195	uint32_t		pl_flags;
196	char			pl_pcomm[MAXCOMLEN+1];	/* keep 8 byte aligned */
197} __packed;
198
199struct pmclog_procexec {
200	PMCLOG_ENTRY_HEADER
201	uint32_t		pl_pid;
202	uint32_t		pl_pmcid;
203	/* keep 8 byte aligned */
204	uintptr_t		pl_base;	/* AT_BASE */
205	/* keep 8 byte aligned */
206	uintptr_t		pl_dyn;		/* PIE load base */
207	char			pl_pathname[PATH_MAX];
208} __packed;
209
210struct pmclog_procexit {
211	PMCLOG_ENTRY_HEADER
212	uint32_t		pl_pmcid;
213	uint32_t		pl_pid;
214	uint64_t		pl_value;	/* keep 8 byte aligned */
215} __packed;
216
217struct pmclog_procfork {
218	PMCLOG_ENTRY_HEADER
219	uint32_t		pl_oldpid;
220	uint32_t		pl_newpid;
221} __packed;
222
223struct pmclog_sysexit {
224	PMCLOG_ENTRY_HEADER
225	uint32_t		pl_pid;
226	uint32_t		pl_pad;
227} __packed;
228
229struct pmclog_threadcreate {
230	PMCLOG_ENTRY_HEADER
231	uint32_t		pl_tid;
232	uint32_t		pl_pid;
233	uint32_t		pl_flags;
234	uint32_t		pl_pad;
235	char			pl_tdname[MAXCOMLEN+1];	/* keep 8 byte aligned */
236} __packed;
237
238struct pmclog_threadexit {
239	PMCLOG_ENTRY_HEADER
240	uint32_t		pl_tid;
241	uint32_t		pl_pad;
242} __packed;
243
244struct pmclog_userdata {
245	PMCLOG_ENTRY_HEADER
246	uint32_t		pl_userdata;
247	uint32_t		pl_pad;
248} __packed;
249
250struct pmclog_pmcallocatedyn {
251	PMCLOG_ENTRY_HEADER
252	uint32_t		pl_pmcid;
253	uint32_t		pl_event;
254	uint32_t		pl_flags;
255	uint32_t		pl_pad;
256	char			pl_evname[PMC_NAME_MAX];
257} __packed;
258
259union pmclog_entry {		/* only used to size scratch areas */
260	struct pmclog_callchain		pl_cc;
261	struct pmclog_closelog		pl_cl;
262	struct pmclog_dropnotify	pl_dn;
263	struct pmclog_initialize	pl_i;
264	struct pmclog_map_in		pl_mi;
265	struct pmclog_map_out		pl_mo;
266	struct pmclog_pmcallocate	pl_a;
267	struct pmclog_pmcallocatedyn	pl_ad;
268	struct pmclog_pmcattach		pl_t;
269	struct pmclog_pmcdetach		pl_d;
270	struct pmclog_proccsw		pl_c;
271	struct pmclog_proccreate	pl_pc;
272	struct pmclog_procexec		pl_x;
273	struct pmclog_procexit		pl_e;
274	struct pmclog_procfork		pl_f;
275	struct pmclog_sysexit		pl_se;
276	struct pmclog_threadcreate	pl_tc;
277	struct pmclog_threadexit	pl_te;
278	struct pmclog_userdata		pl_u;
279};
280
281#define	PMCLOG_HEADER_MAGIC					0xEEU
282
283#define	PMCLOG_HEADER_TO_LENGTH(H)				\
284	((H) & 0x0000FFFF)
285#define	PMCLOG_HEADER_TO_TYPE(H)				\
286	(((H) & 0x00FF0000) >> 16)
287#define	PMCLOG_HEADER_TO_MAGIC(H)				\
288	(((H) & 0xFF000000) >> 24)
289#define	PMCLOG_HEADER_CHECK_MAGIC(H)				\
290	(PMCLOG_HEADER_TO_MAGIC(H) == PMCLOG_HEADER_MAGIC)
291
292#ifdef	_KERNEL
293
294/*
295 * Prototypes
296 */
297int	pmclog_configure_log(struct pmc_mdep *_md, struct pmc_owner *_po,
298    int _logfd);
299int	pmclog_deconfigure_log(struct pmc_owner *_po);
300int	pmclog_flush(struct pmc_owner *_po, int force);
301int	pmclog_close(struct pmc_owner *_po);
302void	pmclog_initialize(void);
303int	pmclog_proc_create(struct thread *td, void **handlep);
304void	pmclog_proc_ignite(void *handle, struct pmc_owner *po);
305void	pmclog_process_callchain(struct pmc *_pm, struct pmc_sample *_ps);
306void	pmclog_process_closelog(struct pmc_owner *po);
307void	pmclog_process_dropnotify(struct pmc_owner *po);
308void	pmclog_process_map_in(struct pmc_owner *po, pid_t pid,
309    uintfptr_t start, const char *path);
310void	pmclog_process_map_out(struct pmc_owner *po, pid_t pid,
311    uintfptr_t start, uintfptr_t end);
312void	pmclog_process_pmcallocate(struct pmc *_pm);
313void	pmclog_process_pmcattach(struct pmc *_pm, pid_t _pid, char *_path);
314void	pmclog_process_pmcdetach(struct pmc *_pm, pid_t _pid);
315void	pmclog_process_proccsw(struct pmc *_pm, struct pmc_process *_pp,
316    pmc_value_t _v, struct thread *);
317void	pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid,
318    uintfptr_t _baseaddr, uintptr_t _dynaddr, char *_path);
319void	pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp);
320void	pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid);
321void	pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid);
322void	pmclog_process_threadcreate(struct pmc_owner *_po, struct thread *td, int sync);
323void	pmclog_process_threadexit(struct pmc_owner *_po, struct thread *td);
324void	pmclog_process_proccreate(struct pmc_owner *_po, struct proc *p, int sync);
325int	pmclog_process_userlog(struct pmc_owner *_po,
326    struct pmc_op_writelog *_wl);
327void	pmclog_shutdown(void);
328#endif	/* _KERNEL */
329
330#endif	/* _SYS_PMCLOG_H_ */
331