1*cd35dc3dSkamil /* $NetBSD: systrace.c,v 1.12 2018/06/29 11:33:46 kamil Exp $ */
201c9547eSdarran
3bb8023b5Sdarran /*
4bb8023b5Sdarran * CDDL HEADER START
5bb8023b5Sdarran *
6bb8023b5Sdarran * The contents of this file are subject to the terms of the
7bb8023b5Sdarran * Common Development and Distribution License (the "License").
8bb8023b5Sdarran * You may not use this file except in compliance with the License.
9bb8023b5Sdarran *
10bb8023b5Sdarran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11bb8023b5Sdarran * or http://www.opensolaris.org/os/licensing.
12bb8023b5Sdarran * See the License for the specific language governing permissions
13bb8023b5Sdarran * and limitations under the License.
14bb8023b5Sdarran *
15bb8023b5Sdarran * When distributing Covered Code, include this CDDL HEADER in each
16bb8023b5Sdarran * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17bb8023b5Sdarran * If applicable, add the following below this CDDL HEADER, with the
18bb8023b5Sdarran * fields enclosed by brackets "[]" replaced with your own identifying
19bb8023b5Sdarran * information: Portions Copyright [yyyy] [name of copyright owner]
20bb8023b5Sdarran *
21bb8023b5Sdarran * CDDL HEADER END
22bb8023b5Sdarran *
23bb8023b5Sdarran * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
24bb8023b5Sdarran *
25bb8023b5Sdarran */
26bb8023b5Sdarran
27bb8023b5Sdarran /*
28bb8023b5Sdarran * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29bb8023b5Sdarran * Use is subject to license terms.
30bb8023b5Sdarran */
31bb8023b5Sdarran
32bb8023b5Sdarran #include <sys/cdefs.h>
33ba2539a9Schs /* __FBSDID("$FreeBSD: head/sys/cddl/dev/systrace/systrace.c 306220 2016-09-22 23:22:53Z markj $"); */
34ba2539a9Schs
35ba2539a9Schs #include <sys/proc.h>
36bb8023b5Sdarran #include <sys/param.h>
37bb8023b5Sdarran #include <sys/systm.h>
38bb8023b5Sdarran #include <sys/conf.h>
39bb8023b5Sdarran #include <sys/cpuvar.h>
40bb8023b5Sdarran #include <sys/fcntl.h>
41bb8023b5Sdarran #include <sys/filio.h>
42bb8023b5Sdarran #include <sys/kernel.h>
43bb8023b5Sdarran #include <sys/kmem.h>
44bb8023b5Sdarran #include <sys/kthread.h>
4567442b90Schristos #include <sys/syslimits.h>
46bb8023b5Sdarran #include <sys/linker.h>
47bb8023b5Sdarran #include <sys/lock.h>
48bb8023b5Sdarran #include <sys/malloc.h>
49bb8023b5Sdarran #include <sys/module.h>
50bb8023b5Sdarran #include <sys/mutex.h>
51bb8023b5Sdarran #include <sys/poll.h>
52bb8023b5Sdarran #include <sys/proc.h>
53bb8023b5Sdarran #include <sys/selinfo.h>
5411beb836Sriz #include <sys/syscallargs.h>
55bb8023b5Sdarran #include <sys/uio.h>
56bb8023b5Sdarran #include <sys/unistd.h>
57bb8023b5Sdarran
58bb8023b5Sdarran #include <sys/dtrace.h>
59ba2539a9Schs #include "dtrace_cddl.h"
60bb8023b5Sdarran
61c0342a4eSchristos #include "emultrace.h"
62c0342a4eSchristos
63c0342a4eSchristos #define CONCAT(x,y) __CONCAT(x,y)
64c0342a4eSchristos #define STRING(s) __STRING(s)
65c0342a4eSchristos
66ba2539a9Schs #ifdef __FreeBSD__
67ba2539a9Schs #ifdef LINUX_SYSTRACE
68ba2539a9Schs #if defined(__amd64__)
69ba2539a9Schs #include <amd64/linux/linux.h>
70ba2539a9Schs #include <amd64/linux/linux_proto.h>
71ba2539a9Schs #include <amd64/linux/linux_syscalls.c>
72ba2539a9Schs #include <amd64/linux/linux_systrace_args.c>
73ba2539a9Schs #elif defined(__i386__)
74ba2539a9Schs #include <i386/linux/linux.h>
75ba2539a9Schs #include <i386/linux/linux_proto.h>
76ba2539a9Schs #include <i386/linux/linux_syscalls.c>
77ba2539a9Schs #include <i386/linux/linux_systrace_args.c>
78ba2539a9Schs #else
79ba2539a9Schs #error Only i386 and amd64 are supported.
80ba2539a9Schs #endif
81ba2539a9Schs #define MODNAME "linux"
82ba2539a9Schs extern struct sysent linux_sysent[];
83ba2539a9Schs #define MAXSYSCALL LINUX_SYS_MAXSYSCALL
84ba2539a9Schs #define SYSCALLNAMES linux_syscallnames
85ba2539a9Schs #define SYSENT linux_sysent
86ba2539a9Schs #elif defined(LINUX32_SYSTRACE)
87ba2539a9Schs #if defined(__amd64__)
88ba2539a9Schs #include <amd64/linux32/linux.h>
89ba2539a9Schs #include <amd64/linux32/linux32_proto.h>
90ba2539a9Schs #include <amd64/linux32/linux32_syscalls.c>
91ba2539a9Schs #include <amd64/linux32/linux32_systrace_args.c>
92ba2539a9Schs #else
93ba2539a9Schs #error Only amd64 is supported.
94ba2539a9Schs #endif
95ba2539a9Schs #define MODNAME "linux32"
96ba2539a9Schs extern struct sysent linux32_sysent[];
97ba2539a9Schs #define MAXSYSCALL LINUX32_SYS_MAXSYSCALL
98ba2539a9Schs #define SYSCALLNAMES linux32_syscallnames
99ba2539a9Schs #define SYSENT linux32_sysent
100ba2539a9Schs #elif defined(FREEBSD32_SYSTRACE)
101ba2539a9Schs /*
102ba2539a9Schs * The syscall arguments are processed into a DTrace argument array
103ba2539a9Schs * using a generated function. See sys/kern/makesyscalls.sh.
104ba2539a9Schs */
105ba2539a9Schs #include <compat/freebsd32/freebsd32_proto.h>
106ba2539a9Schs #include <compat/freebsd32/freebsd32_util.h>
107ba2539a9Schs #include <compat/freebsd32/freebsd32_syscall.h>
108ba2539a9Schs #include <compat/freebsd32/freebsd32_systrace_args.c>
109ba2539a9Schs extern const char *freebsd32_syscallnames[];
110ba2539a9Schs #define MODNAME "freebsd32"
111ba2539a9Schs #define MAXSYSCALL FREEBSD32_SYS_MAXSYSCALL
112ba2539a9Schs #define SYSCALLNAMES freebsd32_syscallnames
113ba2539a9Schs #define SYSENT freebsd32_sysent
114ba2539a9Schs #else
115ba2539a9Schs /*
116ba2539a9Schs * The syscall arguments are processed into a DTrace argument array
117ba2539a9Schs * using a generated function. See sys/kern/makesyscalls.sh.
118ba2539a9Schs */
119ba2539a9Schs #include <sys/syscall.h>
120ba2539a9Schs #include <kern/systrace_args.c>
121ba2539a9Schs #define MODNAME "freebsd"
122ba2539a9Schs #define MAXSYSCALL SYS_MAXSYSCALL
123ba2539a9Schs #define SYSCALLNAMES syscallnames
124ba2539a9Schs #define SYSENT sysent
125ba2539a9Schs #define NATIVE_ABI
126ba2539a9Schs #endif
127ba2539a9Schs
128ba2539a9Schs #define PROVNAME "syscall"
129ba2539a9Schs #define DEVNAME "dtrace/systrace/" MODNAME
130ba2539a9Schs #endif /* __FreeBSD__ */
131ba2539a9Schs
132ba2539a9Schs #ifdef __NetBSD__
133ba2539a9Schs #include <sys/syscallargs.h>
134ba2539a9Schs
135c0342a4eSchristos #ifndef NATIVE
136c0342a4eSchristos extern const char * const CONCAT(emulname,_syscallnames)[];
1375377c710Schristos extern const char * const CONCAT(alt,CONCAT(emulname,_syscallnames))[];
138c0342a4eSchristos extern struct sysent CONCAT(emulname,_sysent)[];
139c0342a4eSchristos #define MODNAME CONCAT(dtrace_syscall_,emulname)
140c0342a4eSchristos #define MODDEP "dtrace_syscall,compat_" STRING(emulname)
141c0342a4eSchristos #define MAXSYSCALL CONCAT(EMULNAME,_SYS_MAXSYSCALL)
142c0342a4eSchristos #define SYSCALLNAMES CONCAT(emulname,_syscallnames)
1435377c710Schristos #define ALTSYSCALLNAMES CONCAT(alt,CONCAT(emulname,_syscallnames))
144c0342a4eSchristos #define SYSENT CONCAT(emulname,_sysent)
145c0342a4eSchristos #define PROVNAME STRING(emulname) "_syscall"
146bb8023b5Sdarran #else
14711beb836Sriz extern const char * const syscallnames[];
1485377c710Schristos extern const char * const altsyscallnames[];
149c0342a4eSchristos #define MODNAME dtrace_syscall
150c0342a4eSchristos #define MODDEP "dtrace"
151bb8023b5Sdarran #define MAXSYSCALL SYS_MAXSYSCALL
152bb8023b5Sdarran #define SYSCALLNAMES syscallnames
1535377c710Schristos #define ALTSYSCALLNAMES altsyscallnames
154bb8023b5Sdarran #define SYSENT sysent
155c0342a4eSchristos #define PROVNAME "syscall"
156bb8023b5Sdarran #endif
157bb8023b5Sdarran
158c0342a4eSchristos #define MODCMD CONCAT(MODNAME,_modcmd)
159c0342a4eSchristos #define EMUL CONCAT(emul_,emulname)
160c0342a4eSchristos extern struct emul EMUL;
161ba2539a9Schs #define curthread curlwp
162ba2539a9Schs #endif /* __NetBSD__ */
163c0342a4eSchristos
164bb8023b5Sdarran #define SYSTRACE_ARTIFICIAL_FRAMES 1
165bb8023b5Sdarran
166bb8023b5Sdarran #define SYSTRACE_SHIFT 16
167bb8023b5Sdarran #define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)
168bb8023b5Sdarran #define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))
169bb8023b5Sdarran #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))
170bb8023b5Sdarran #define SYSTRACE_RETURN(id) (id)
171bb8023b5Sdarran
172bb8023b5Sdarran #if ((1 << SYSTRACE_SHIFT) <= MAXSYSCALL)
173bb8023b5Sdarran #error 1 << SYSTRACE_SHIFT must exceed number of system calls
174bb8023b5Sdarran #endif
175bb8023b5Sdarran
176bb8023b5Sdarran static int systrace_unload(void);
177bb8023b5Sdarran static void systrace_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
178ba2539a9Schs static uint64_t systrace_getargval(void *, dtrace_id_t, void *, int, int);
179ba2539a9Schs static void systrace_provide(void *, dtrace_probedesc_t *);
180bb8023b5Sdarran static void systrace_destroy(void *, dtrace_id_t, void *);
18111beb836Sriz static int systrace_enable(void *, dtrace_id_t, void *);
182bb8023b5Sdarran static void systrace_disable(void *, dtrace_id_t, void *);
183bb8023b5Sdarran static void systrace_load(void *);
184bb8023b5Sdarran
185ba2539a9Schs #ifdef __FreeBSD__
186ba2539a9Schs static union {
187ba2539a9Schs const char **p_constnames;
188ba2539a9Schs char **pp_syscallnames;
189ba2539a9Schs } uglyhack = { SYSCALLNAMES };
190ba2539a9Schs #endif
191ba2539a9Schs
192bb8023b5Sdarran static dtrace_pattr_t systrace_attr = {
193bb8023b5Sdarran { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
194bb8023b5Sdarran { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
195bb8023b5Sdarran { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
196bb8023b5Sdarran { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
197bb8023b5Sdarran { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
198bb8023b5Sdarran };
199bb8023b5Sdarran
200bb8023b5Sdarran static dtrace_pops_t systrace_pops = {
201bb8023b5Sdarran systrace_provide,
202bb8023b5Sdarran NULL,
203bb8023b5Sdarran systrace_enable,
204bb8023b5Sdarran systrace_disable,
205bb8023b5Sdarran NULL,
206bb8023b5Sdarran NULL,
207bb8023b5Sdarran systrace_getargdesc,
208ba2539a9Schs systrace_getargval,
209bb8023b5Sdarran NULL,
210bb8023b5Sdarran systrace_destroy
211bb8023b5Sdarran };
212bb8023b5Sdarran
213bb8023b5Sdarran static dtrace_provider_id_t systrace_id;
214bb8023b5Sdarran
215bb8023b5Sdarran /*
216bb8023b5Sdarran * Probe callback function.
217bb8023b5Sdarran *
218bb8023b5Sdarran * Note: This function is called for _all_ syscalls, regardless of which sysent
219bb8023b5Sdarran * array the syscall comes from. It could be a standard syscall or a
220bb8023b5Sdarran * compat syscall from something like Linux.
221bb8023b5Sdarran */
222ba2539a9Schs #ifdef __FreeBSD__
223ba2539a9Schs #ifdef NATIVE_ABI
224ba2539a9Schs static void
systrace_probe(struct syscall_args * sa,enum systrace_probe_t type,int retval)225ba2539a9Schs systrace_probe(struct syscall_args *sa, enum systrace_probe_t type, int retval)
226ba2539a9Schs {
227ba2539a9Schs uint64_t uargs[nitems(sa->args)];
228ba2539a9Schs dtrace_id_t id;
229ba2539a9Schs int n_args, sysnum;
230ba2539a9Schs
231ba2539a9Schs sysnum = sa->code;
232ba2539a9Schs memset(uargs, 0, sizeof(uargs));
233ba2539a9Schs
234ba2539a9Schs if (type == SYSTRACE_ENTRY) {
235ba2539a9Schs if ((id = sa->callp->sy_entry) == DTRACE_IDNONE)
236ba2539a9Schs return;
237ba2539a9Schs
238ba2539a9Schs if (sa->callp->sy_systrace_args_func != NULL)
239ba2539a9Schs /*
240ba2539a9Schs * Convert the syscall parameters using the registered
241ba2539a9Schs * function.
242ba2539a9Schs */
243ba2539a9Schs (*sa->callp->sy_systrace_args_func)(sysnum, sa->args,
244ba2539a9Schs uargs, &n_args);
245ba2539a9Schs else
246ba2539a9Schs /*
247ba2539a9Schs * Use the built-in system call argument conversion
248ba2539a9Schs * function to translate the syscall structure fields
249ba2539a9Schs * into the array of 64-bit values that DTrace expects.
250ba2539a9Schs */
251ba2539a9Schs systrace_args(sysnum, sa->args, uargs, &n_args);
252ba2539a9Schs /*
253ba2539a9Schs * Save probe arguments now so that we can retrieve them if
254ba2539a9Schs * the getargval method is called from further down the stack.
255ba2539a9Schs */
256ba2539a9Schs curthread->t_dtrace_systrace_args = uargs;
257ba2539a9Schs } else {
258ba2539a9Schs if ((id = sa->callp->sy_return) == DTRACE_IDNONE)
259ba2539a9Schs return;
260ba2539a9Schs
261ba2539a9Schs curthread->t_dtrace_systrace_args = NULL;
262ba2539a9Schs /* Set arg0 and arg1 as the return value of this syscall. */
263ba2539a9Schs uargs[0] = uargs[1] = retval;
264ba2539a9Schs }
265ba2539a9Schs
266ba2539a9Schs /* Process the probe using the converted argments. */
267ba2539a9Schs dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]);
268ba2539a9Schs }
269ba2539a9Schs #endif /* NATIVE_ABI */
270ba2539a9Schs #endif /* __FreeBSD__ */
271ba2539a9Schs
272ba2539a9Schs #ifdef __NetBSD__
273bb8023b5Sdarran static void
systrace_probe(uint32_t id,register_t sysnum,const struct sysent * se,const void * params,const register_t * ret,int error)274c0342a4eSchristos systrace_probe(uint32_t id, register_t sysnum, const struct sysent *se,
275c0342a4eSchristos const void *params, const register_t *ret, int error)
276bb8023b5Sdarran {
277c0342a4eSchristos size_t n_args = 0;
278aadbd125Schristos uintptr_t uargs[SYS_MAXSYSARGS + 3];
279bb8023b5Sdarran
280c0342a4eSchristos memset(uargs, 0, sizeof(uargs));
28171da105aSchristos if (ret == NULL) {
282c0342a4eSchristos /* entry syscall, convert params */
283bb8023b5Sdarran systrace_args(sysnum, params, uargs, &n_args);
284c0342a4eSchristos } else {
285aadbd125Schristos /* return syscall, set values and params: */
286c0342a4eSchristos uargs[0] = ret[0];
287c0342a4eSchristos uargs[1] = ret[1];
288c0342a4eSchristos uargs[2] = error;
289aadbd125Schristos systrace_args(sysnum, params, uargs + 3, &n_args);
290bb8023b5Sdarran }
291c0342a4eSchristos /* Process the probe using the converted argments. */
292c0342a4eSchristos /* XXX: fix for more arguments! */
293c0342a4eSchristos dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]);
294c0342a4eSchristos }
295ba2539a9Schs #endif
296bb8023b5Sdarran
297bb8023b5Sdarran static void
systrace_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)298bb8023b5Sdarran systrace_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
299bb8023b5Sdarran {
300bb8023b5Sdarran int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
301ba2539a9Schs
302c0342a4eSchristos if (SYSTRACE_ISENTRY((uintptr_t)parg))
303c0342a4eSchristos systrace_entry_setargdesc(sysnum, desc->dtargd_ndx,
304c0342a4eSchristos desc->dtargd_native, sizeof(desc->dtargd_native));
305c0342a4eSchristos else
306c0342a4eSchristos systrace_return_setargdesc(sysnum, desc->dtargd_ndx,
307c0342a4eSchristos desc->dtargd_native, sizeof(desc->dtargd_native));
308bb8023b5Sdarran
309bb8023b5Sdarran if (desc->dtargd_native[0] == '\0')
310bb8023b5Sdarran desc->dtargd_ndx = DTRACE_ARGNONE;
311bb8023b5Sdarran }
312bb8023b5Sdarran
313ba2539a9Schs static uint64_t
systrace_getargval(void * arg,dtrace_id_t id,void * parg,int argno,int aframes)314ba2539a9Schs systrace_getargval(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
315ba2539a9Schs {
316ba2539a9Schs uint64_t *uargs;
317ba2539a9Schs
318ba2539a9Schs uargs = curthread->t_dtrace_systrace_args;
319ba2539a9Schs if (uargs == NULL)
320ba2539a9Schs /* This is a return probe. */
321ba2539a9Schs return (0);
322ba2539a9Schs #ifdef __FreeBSD__
323ba2539a9Schs if (argno >= nitems(((struct syscall_args *)NULL)->args))
324ba2539a9Schs return (0);
325ba2539a9Schs #endif
326ba2539a9Schs #ifdef __NetBSD__
327ba2539a9Schs if (argno >= SYS_MAXSYSARGS)
328ba2539a9Schs return (0);
329ba2539a9Schs #endif
330ba2539a9Schs
331ba2539a9Schs return (uargs[argno]);
332ba2539a9Schs }
333ba2539a9Schs
334bb8023b5Sdarran static void
systrace_provide(void * arg,dtrace_probedesc_t * desc)335ba2539a9Schs systrace_provide(void *arg, dtrace_probedesc_t *desc)
336bb8023b5Sdarran {
337bb8023b5Sdarran int i;
338bb8023b5Sdarran
339bb8023b5Sdarran if (desc != NULL)
340bb8023b5Sdarran return;
341bb8023b5Sdarran
342bb8023b5Sdarran for (i = 0; i < MAXSYSCALL; i++) {
343ba2539a9Schs #ifdef __FreeBSD__
344ba2539a9Schs if (dtrace_probe_lookup(systrace_id, MODNAME,
345ba2539a9Schs uglyhack.pp_syscallnames[i], "entry") != 0)
346ba2539a9Schs continue;
347ba2539a9Schs
348ba2539a9Schs (void)dtrace_probe_create(systrace_id, MODNAME,
349ba2539a9Schs uglyhack.pp_syscallnames[i], "entry",
350ba2539a9Schs SYSTRACE_ARTIFICIAL_FRAMES,
351ba2539a9Schs (void *)((uintptr_t)SYSTRACE_ENTRY(i)));
352ba2539a9Schs (void)dtrace_probe_create(systrace_id, MODNAME,
353ba2539a9Schs uglyhack.pp_syscallnames[i], "return",
354ba2539a9Schs SYSTRACE_ARTIFICIAL_FRAMES,
355ba2539a9Schs (void *)((uintptr_t)SYSTRACE_RETURN(i)));
356ba2539a9Schs #else
3575377c710Schristos const char *name = ALTSYSCALLNAMES[i] ? ALTSYSCALLNAMES[i] :
3585377c710Schristos SYSCALLNAMES[i];
359*cd35dc3dSkamil if (dtrace_probe_lookup(systrace_id, NULL, name, "entry") != 0)
360bb8023b5Sdarran continue;
361bb8023b5Sdarran
362c0342a4eSchristos (void) dtrace_probe_create(systrace_id, NULL,
3635377c710Schristos name, "entry", SYSTRACE_ARTIFICIAL_FRAMES,
364c0342a4eSchristos (void *)(intptr_t)SYSTRACE_ENTRY(i));
365c0342a4eSchristos (void) dtrace_probe_create(systrace_id, NULL,
3665377c710Schristos name, "return", SYSTRACE_ARTIFICIAL_FRAMES,
367c0342a4eSchristos (void *)(intptr_t)SYSTRACE_RETURN(i));
368ba2539a9Schs #endif
369bb8023b5Sdarran }
370bb8023b5Sdarran }
371bb8023b5Sdarran
372bb8023b5Sdarran static void
systrace_destroy(void * arg,dtrace_id_t id,void * parg)373bb8023b5Sdarran systrace_destroy(void *arg, dtrace_id_t id, void *parg)
374bb8023b5Sdarran {
375bb8023b5Sdarran #ifdef DEBUG
376bb8023b5Sdarran int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
377bb8023b5Sdarran
378bb8023b5Sdarran /*
379bb8023b5Sdarran * There's nothing to do here but assert that we have actually been
380bb8023b5Sdarran * disabled.
381bb8023b5Sdarran */
382bb8023b5Sdarran if (SYSTRACE_ISENTRY((uintptr_t)parg)) {
383bb8023b5Sdarran ASSERT(sysent[sysnum].sy_entry == 0);
384bb8023b5Sdarran } else {
385bb8023b5Sdarran ASSERT(sysent[sysnum].sy_return == 0);
386bb8023b5Sdarran }
387bb8023b5Sdarran #endif
388bb8023b5Sdarran }
389bb8023b5Sdarran
39011beb836Sriz static int
systrace_enable(void * arg,dtrace_id_t id,void * parg)391bb8023b5Sdarran systrace_enable(void *arg, dtrace_id_t id, void *parg)
392bb8023b5Sdarran {
393bb8023b5Sdarran int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
394bb8023b5Sdarran
395ba2539a9Schs #ifdef __FreeBSD__
396ba2539a9Schs if (SYSENT[sysnum].sy_systrace_args_func == NULL)
397ba2539a9Schs SYSENT[sysnum].sy_systrace_args_func = systrace_args;
398ba2539a9Schs #endif
399ba2539a9Schs
400bb8023b5Sdarran if (SYSTRACE_ISENTRY((uintptr_t)parg))
401bb8023b5Sdarran SYSENT[sysnum].sy_entry = id;
402bb8023b5Sdarran else
403bb8023b5Sdarran SYSENT[sysnum].sy_return = id;
404ba2539a9Schs
40511beb836Sriz return 0;
406bb8023b5Sdarran }
407bb8023b5Sdarran
408bb8023b5Sdarran static void
systrace_disable(void * arg,dtrace_id_t id,void * parg)409bb8023b5Sdarran systrace_disable(void *arg, dtrace_id_t id, void *parg)
410bb8023b5Sdarran {
411bb8023b5Sdarran int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
412bb8023b5Sdarran
413bb8023b5Sdarran SYSENT[sysnum].sy_entry = 0;
414bb8023b5Sdarran SYSENT[sysnum].sy_return = 0;
415bb8023b5Sdarran }
416bb8023b5Sdarran
417bb8023b5Sdarran static void
systrace_load(void * dummy)418bb8023b5Sdarran systrace_load(void *dummy)
419bb8023b5Sdarran {
420ba2539a9Schs if (dtrace_register(PROVNAME, &systrace_attr, DTRACE_PRIV_USER, NULL,
421ba2539a9Schs &systrace_pops, NULL, &systrace_id) != 0)
422bb8023b5Sdarran return;
423bb8023b5Sdarran
424ba2539a9Schs #ifdef NATIVE_ABI
425ba2539a9Schs systrace_probe_func = systrace_probe;
426ba2539a9Schs #endif
427ba2539a9Schs #ifdef __NetBSD__
428c0342a4eSchristos EMUL.e_dtrace_syscall = systrace_probe;
429ba2539a9Schs #endif
430bb8023b5Sdarran }
431bb8023b5Sdarran
432bb8023b5Sdarran
433bb8023b5Sdarran static int
systrace_unload()434bb8023b5Sdarran systrace_unload()
435bb8023b5Sdarran {
436c0342a4eSchristos int error;
437bb8023b5Sdarran
438ba2539a9Schs #ifdef NATIVE_ABI
439ba2539a9Schs systrace_probe_func = NULL;
440ba2539a9Schs #endif
441ba2539a9Schs #ifdef __NetBSD__
442ba2539a9Schs EMUL.e_dtrace_syscall = NULL;
443ba2539a9Schs #endif
444ba2539a9Schs
445bb8023b5Sdarran if ((error = dtrace_unregister(systrace_id)) != 0)
446bb8023b5Sdarran return (error);
447bb8023b5Sdarran
448c0342a4eSchristos return error;
449bb8023b5Sdarran }
450bb8023b5Sdarran
451ba2539a9Schs #ifdef __FreeBSD__
452ba2539a9Schs static int
systrace_modevent(module_t mod __unused,int type,void * data __unused)453ba2539a9Schs systrace_modevent(module_t mod __unused, int type, void *data __unused)
454ba2539a9Schs {
455ba2539a9Schs int error;
456ba2539a9Schs
457ba2539a9Schs error = 0;
458ba2539a9Schs switch (type) {
459ba2539a9Schs case MOD_LOAD:
460ba2539a9Schs break;
461ba2539a9Schs
462ba2539a9Schs case MOD_UNLOAD:
463ba2539a9Schs break;
464ba2539a9Schs
465ba2539a9Schs case MOD_SHUTDOWN:
466ba2539a9Schs break;
467ba2539a9Schs
468ba2539a9Schs default:
469ba2539a9Schs error = EOPNOTSUPP;
470ba2539a9Schs break;
471ba2539a9Schs
472ba2539a9Schs }
473ba2539a9Schs return (error);
474ba2539a9Schs }
475ba2539a9Schs
476ba2539a9Schs SYSINIT(systrace_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
477ba2539a9Schs systrace_load, NULL);
478ba2539a9Schs SYSUNINIT(systrace_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
479ba2539a9Schs systrace_unload, NULL);
480ba2539a9Schs
481ba2539a9Schs #ifdef LINUX_SYSTRACE
482ba2539a9Schs DEV_MODULE(systrace_linux, systrace_modevent, NULL);
483ba2539a9Schs MODULE_VERSION(systrace_linux, 1);
484ba2539a9Schs #ifdef __amd64__
485ba2539a9Schs MODULE_DEPEND(systrace_linux, linux64, 1, 1, 1);
486ba2539a9Schs #else
487ba2539a9Schs MODULE_DEPEND(systrace_linux, linux, 1, 1, 1);
488ba2539a9Schs #endif
489ba2539a9Schs MODULE_DEPEND(systrace_linux, dtrace, 1, 1, 1);
490ba2539a9Schs MODULE_DEPEND(systrace_linux, opensolaris, 1, 1, 1);
491ba2539a9Schs #elif defined(LINUX32_SYSTRACE)
492ba2539a9Schs DEV_MODULE(systrace_linux32, systrace_modevent, NULL);
493ba2539a9Schs MODULE_VERSION(systrace_linux32, 1);
494ba2539a9Schs MODULE_DEPEND(systrace_linux32, linux, 1, 1, 1);
495ba2539a9Schs MODULE_DEPEND(systrace_linux32, dtrace, 1, 1, 1);
496ba2539a9Schs MODULE_DEPEND(systrace_linux32, opensolaris, 1, 1, 1);
497ba2539a9Schs #elif defined(FREEBSD32_SYSTRACE)
498ba2539a9Schs DEV_MODULE(systrace_freebsd32, systrace_modevent, NULL);
499ba2539a9Schs MODULE_VERSION(systrace_freebsd32, 1);
500ba2539a9Schs MODULE_DEPEND(systrace_freebsd32, dtrace, 1, 1, 1);
501ba2539a9Schs MODULE_DEPEND(systrace_freebsd32, opensolaris, 1, 1, 1);
502ba2539a9Schs #else
503ba2539a9Schs DEV_MODULE(systrace, systrace_modevent, NULL);
504ba2539a9Schs MODULE_VERSION(systrace, 1);
505ba2539a9Schs MODULE_DEPEND(systrace, dtrace, 1, 1, 1);
506ba2539a9Schs MODULE_DEPEND(systrace, opensolaris, 1, 1, 1);
507ba2539a9Schs #endif
508ba2539a9Schs #endif /* __FreeBSD__ */
509ba2539a9Schs
510ba2539a9Schs #ifdef __NetBSD__
511ba2539a9Schs
512bb8023b5Sdarran static int
MODCMD(modcmd_t cmd,void * data)513c0342a4eSchristos MODCMD(modcmd_t cmd, void *data)
51411beb836Sriz {
51511beb836Sriz switch (cmd) {
51611beb836Sriz case MODULE_CMD_INIT:
51711beb836Sriz systrace_load(NULL);
51811beb836Sriz return 0;
51911beb836Sriz
52011beb836Sriz case MODULE_CMD_FINI:
521c0342a4eSchristos return systrace_unload();
522c0342a4eSchristos
523c0342a4eSchristos case MODULE_CMD_AUTOUNLOAD:
524c0342a4eSchristos return EBUSY;
52511beb836Sriz
52611beb836Sriz default:
52711beb836Sriz return ENOTTY;
52811beb836Sriz }
52911beb836Sriz }
53011beb836Sriz
531c0342a4eSchristos MODULE(MODULE_CLASS_MISC, MODNAME, MODDEP)
532ba2539a9Schs
533ba2539a9Schs #endif /* __NetBSD__ */
534