xref: /freebsd/sys/kern/kern_sdt.c (revision 5572901b331d35a779ce756ba4b25a41cc082d0c)
15572901bSJohn Birrell /*-
25572901bSJohn Birrell  * Copyright 2006-2008 John Birrell <jb@FreeBSD.org>
35572901bSJohn Birrell  *
45572901bSJohn Birrell  * Redistribution and use in source and binary forms, with or without
55572901bSJohn Birrell  * modification, are permitted provided that the following conditions
65572901bSJohn Birrell  * are met:
75572901bSJohn Birrell  * 1. Redistributions of source code must retain the above copyright
85572901bSJohn Birrell  *    notice, this list of conditions and the following disclaimer.
95572901bSJohn Birrell  * 2. Redistributions in binary form must reproduce the above copyright
105572901bSJohn Birrell  *    notice, this list of conditions and the following disclaimer in the
115572901bSJohn Birrell  *    documentation and/or other materials provided with the distribution.
125572901bSJohn Birrell  *
135572901bSJohn Birrell  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
145572901bSJohn Birrell  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
155572901bSJohn Birrell  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
165572901bSJohn Birrell  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
175572901bSJohn Birrell  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
185572901bSJohn Birrell  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
195572901bSJohn Birrell  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
205572901bSJohn Birrell  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
215572901bSJohn Birrell  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
225572901bSJohn Birrell  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
235572901bSJohn Birrell  * SUCH DAMAGE.
245572901bSJohn Birrell  *
255572901bSJohn Birrell  * $FreeBSD$
265572901bSJohn Birrell  *
275572901bSJohn Birrell  * Backend for the Statically Defined Tracing (SDT) kernel support. This is
285572901bSJohn Birrell  * required to allow a module to load even though DTrace kernel support may
295572901bSJohn Birrell  * not be present. A module may be built with SDT probes in it which are
305572901bSJohn Birrell  * registered and deregistered via SYSINIT/SYSUNINIT.
315572901bSJohn Birrell  *
325572901bSJohn Birrell  */
335572901bSJohn Birrell 
345572901bSJohn Birrell #include "opt_kdtrace.h"
355572901bSJohn Birrell 
365572901bSJohn Birrell #include <sys/cdefs.h>
375572901bSJohn Birrell #include <sys/param.h>
385572901bSJohn Birrell #include <sys/systm.h>
395572901bSJohn Birrell #include <sys/kernel.h>
405572901bSJohn Birrell #include <sys/linker.h>
415572901bSJohn Birrell #include <sys/lock.h>
425572901bSJohn Birrell #include <sys/proc.h>
435572901bSJohn Birrell #include <sys/sx.h>
445572901bSJohn Birrell #include <sys/sdt.h>
455572901bSJohn Birrell 
465572901bSJohn Birrell /*
475572901bSJohn Birrell  * This is the list of statically defined tracing providers.
485572901bSJohn Birrell  */
495572901bSJohn Birrell static TAILQ_HEAD(sdt_provider_list_head, sdt_provider) sdt_provider_list;
505572901bSJohn Birrell 
515572901bSJohn Birrell /*
525572901bSJohn Birrell  * Mutex to serialise access to the SDT provider list.
535572901bSJohn Birrell  */
545572901bSJohn Birrell static struct sx sdt_sx;
555572901bSJohn Birrell 
565572901bSJohn Birrell /*
575572901bSJohn Birrell  * Hook for the DTrace probe function. The 'sdt' provider will set this
585572901bSJohn Birrell  * to dtrace_probe when it loads.
595572901bSJohn Birrell  */
605572901bSJohn Birrell sdt_probe_func_t sdt_probe_func = sdt_probe_stub;
615572901bSJohn Birrell 
625572901bSJohn Birrell /*
635572901bSJohn Birrell  * This is a stub for probe calls in case kernel DTrace support isn't
645572901bSJohn Birrell  * compiled in. It should never get called because there is no DTrace
655572901bSJohn Birrell  * support to enable it.
665572901bSJohn Birrell  */
675572901bSJohn Birrell void
685572901bSJohn Birrell sdt_probe_stub(u_int32_t id, uintptr_t arg0, uintptr_t arg1,
695572901bSJohn Birrell     uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
705572901bSJohn Birrell {
715572901bSJohn Birrell 	printf("sdt_probe_stub: Why did this get called?\n");
725572901bSJohn Birrell }
735572901bSJohn Birrell 
745572901bSJohn Birrell /*
755572901bSJohn Birrell  * Called from SYSINIT to register a provider.
765572901bSJohn Birrell  */
775572901bSJohn Birrell void
785572901bSJohn Birrell sdt_provider_register(void *arg)
795572901bSJohn Birrell {
805572901bSJohn Birrell 	struct sdt_provider *prov = arg;
815572901bSJohn Birrell 
825572901bSJohn Birrell 	sx_xlock(&sdt_sx);
835572901bSJohn Birrell 
845572901bSJohn Birrell 	TAILQ_INSERT_TAIL(&sdt_provider_list, prov, prov_entry);
855572901bSJohn Birrell 
865572901bSJohn Birrell 	TAILQ_INIT(&prov->probe_list);
875572901bSJohn Birrell 
885572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
895572901bSJohn Birrell }
905572901bSJohn Birrell 
915572901bSJohn Birrell /*
925572901bSJohn Birrell  * Called from SYSUNINIT to de-register a provider.
935572901bSJohn Birrell  */
945572901bSJohn Birrell void
955572901bSJohn Birrell sdt_provider_deregister(void *arg)
965572901bSJohn Birrell {
975572901bSJohn Birrell 	struct sdt_provider *prov = arg;
985572901bSJohn Birrell 
995572901bSJohn Birrell 	sx_xlock(&sdt_sx);
1005572901bSJohn Birrell 
1015572901bSJohn Birrell 	TAILQ_REMOVE(&sdt_provider_list, prov, prov_entry);
1025572901bSJohn Birrell 
1035572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
1045572901bSJohn Birrell }
1055572901bSJohn Birrell 
1065572901bSJohn Birrell /*
1075572901bSJohn Birrell  * Called from SYSINIT to register a statically defined trace probe.
1085572901bSJohn Birrell  */
1095572901bSJohn Birrell void
1105572901bSJohn Birrell sdt_probe_register(void *arg)
1115572901bSJohn Birrell {
1125572901bSJohn Birrell 	struct sdt_probe *probe = arg;
1135572901bSJohn Birrell 
1145572901bSJohn Birrell 	/*
1155572901bSJohn Birrell 	 * Check the reference structure version. Only version 1 is
1165572901bSJohn Birrell 	 * supported at the moment.
1175572901bSJohn Birrell 	 */
1185572901bSJohn Birrell 	if (probe->version != sizeof(struct sdt_probe)) {
1195572901bSJohn Birrell 		printf("%s:%s:%s has version %d when %d required\n", probe->mod, probe->func, probe->name, probe->version, (int) sizeof(struct sdt_probe));
1205572901bSJohn Birrell 		return;
1215572901bSJohn Birrell 	}
1225572901bSJohn Birrell 
1235572901bSJohn Birrell 	sx_xlock(&sdt_sx);
1245572901bSJohn Birrell 
1255572901bSJohn Birrell 	TAILQ_INSERT_TAIL(&probe->prov->probe_list, probe, probe_entry);
1265572901bSJohn Birrell 
1275572901bSJohn Birrell 	TAILQ_INIT(&probe->argtype_list);
1285572901bSJohn Birrell 
1295572901bSJohn Birrell 	probe->state = SDT_INIT;
1305572901bSJohn Birrell 
1315572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
1325572901bSJohn Birrell }
1335572901bSJohn Birrell 
1345572901bSJohn Birrell /*
1355572901bSJohn Birrell  * Called from SYSUNINIT to de-register a statically defined trace probe.
1365572901bSJohn Birrell  */
1375572901bSJohn Birrell void
1385572901bSJohn Birrell sdt_probe_deregister(void *arg)
1395572901bSJohn Birrell {
1405572901bSJohn Birrell 	struct sdt_probe *probe = arg;
1415572901bSJohn Birrell 
1425572901bSJohn Birrell 	sx_xlock(&sdt_sx);
1435572901bSJohn Birrell 
1445572901bSJohn Birrell 	if (probe->state == SDT_INIT) {
1455572901bSJohn Birrell 		TAILQ_REMOVE(&probe->prov->probe_list, probe, probe_entry);
1465572901bSJohn Birrell 		probe->state = SDT_UNINIT;
1475572901bSJohn Birrell 	}
1485572901bSJohn Birrell 
1495572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
1505572901bSJohn Birrell }
1515572901bSJohn Birrell 
1525572901bSJohn Birrell /*
1535572901bSJohn Birrell  * Called from SYSINIT to register a statically defined trace probe argument.
1545572901bSJohn Birrell  */
1555572901bSJohn Birrell void
1565572901bSJohn Birrell sdt_argtype_register(void *arg)
1575572901bSJohn Birrell {
1585572901bSJohn Birrell 	struct sdt_argtype *argtype = arg;
1595572901bSJohn Birrell 
1605572901bSJohn Birrell 	sx_xlock(&sdt_sx);
1615572901bSJohn Birrell 
1625572901bSJohn Birrell 	TAILQ_INSERT_TAIL(&argtype->probe->argtype_list, argtype, argtype_entry);
1635572901bSJohn Birrell 
1645572901bSJohn Birrell 	argtype->probe->n_args++;
1655572901bSJohn Birrell 
1665572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
1675572901bSJohn Birrell }
1685572901bSJohn Birrell 
1695572901bSJohn Birrell /*
1705572901bSJohn Birrell  * Called from SYSUNINIT to de-register a statically defined trace probe argument.
1715572901bSJohn Birrell  */
1725572901bSJohn Birrell void
1735572901bSJohn Birrell sdt_argtype_deregister(void *arg)
1745572901bSJohn Birrell {
1755572901bSJohn Birrell 	struct sdt_argtype *argtype = arg;
1765572901bSJohn Birrell 
1775572901bSJohn Birrell 	sx_xlock(&sdt_sx);
1785572901bSJohn Birrell 
1795572901bSJohn Birrell 	TAILQ_REMOVE(&argtype->probe->argtype_list, argtype, argtype_entry);
1805572901bSJohn Birrell 
1815572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
1825572901bSJohn Birrell }
1835572901bSJohn Birrell 
1845572901bSJohn Birrell static void
1855572901bSJohn Birrell sdt_init(void *arg)
1865572901bSJohn Birrell {
1875572901bSJohn Birrell 	sx_init_flags(&sdt_sx, "Statically Defined Tracing", SX_NOWITNESS);
1885572901bSJohn Birrell 
1895572901bSJohn Birrell 	TAILQ_INIT(&sdt_provider_list);
1905572901bSJohn Birrell }
1915572901bSJohn Birrell 
1925572901bSJohn Birrell SYSINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_init, NULL);
1935572901bSJohn Birrell 
1945572901bSJohn Birrell static void
1955572901bSJohn Birrell sdt_uninit(void *arg)
1965572901bSJohn Birrell {
1975572901bSJohn Birrell 	sx_destroy(&sdt_sx);
1985572901bSJohn Birrell }
1995572901bSJohn Birrell 
2005572901bSJohn Birrell SYSUNINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_uninit, NULL);
2015572901bSJohn Birrell 
2025572901bSJohn Birrell /*
2035572901bSJohn Birrell  * List statically defined tracing providers.
2045572901bSJohn Birrell  */
2055572901bSJohn Birrell int
2065572901bSJohn Birrell sdt_provider_listall(sdt_provider_listall_func_t callback_func,void *arg)
2075572901bSJohn Birrell {
2085572901bSJohn Birrell 	int error = 0;
2095572901bSJohn Birrell 	struct sdt_provider *prov;
2105572901bSJohn Birrell 
2115572901bSJohn Birrell 	sx_xlock(&sdt_sx);
2125572901bSJohn Birrell 
2135572901bSJohn Birrell 	TAILQ_FOREACH(prov, &sdt_provider_list, prov_entry) {
2145572901bSJohn Birrell 		if ((error = callback_func(prov, arg)) != 0)
2155572901bSJohn Birrell 			break;
2165572901bSJohn Birrell 	}
2175572901bSJohn Birrell 
2185572901bSJohn Birrell 	sx_xunlock(&sdt_sx);
2195572901bSJohn Birrell 
2205572901bSJohn Birrell 	return (error);
2215572901bSJohn Birrell }
2225572901bSJohn Birrell 
2235572901bSJohn Birrell /*
2245572901bSJohn Birrell  * List statically defined tracing probes.
2255572901bSJohn Birrell  */
2265572901bSJohn Birrell int
2275572901bSJohn Birrell sdt_probe_listall(struct sdt_provider *prov,
2285572901bSJohn Birrell     sdt_probe_listall_func_t callback_func,void *arg)
2295572901bSJohn Birrell {
2305572901bSJohn Birrell 	int error = 0;
2315572901bSJohn Birrell 	int locked;
2325572901bSJohn Birrell 	struct sdt_probe *probe;
2335572901bSJohn Birrell 
2345572901bSJohn Birrell 	locked = sx_xlocked(&sdt_sx);
2355572901bSJohn Birrell 	if (!locked)
2365572901bSJohn Birrell 		sx_xlock(&sdt_sx);
2375572901bSJohn Birrell 
2385572901bSJohn Birrell 	TAILQ_FOREACH(probe, &prov->probe_list, probe_entry) {
2395572901bSJohn Birrell 		if ((error = callback_func(probe, arg)) != 0)
2405572901bSJohn Birrell 			break;
2415572901bSJohn Birrell 	}
2425572901bSJohn Birrell 
2435572901bSJohn Birrell 	if (!locked)
2445572901bSJohn Birrell 		sx_xunlock(&sdt_sx);
2455572901bSJohn Birrell 
2465572901bSJohn Birrell 	return (error);
2475572901bSJohn Birrell }
2485572901bSJohn Birrell 
2495572901bSJohn Birrell /*
2505572901bSJohn Birrell  * List statically defined tracing probe arguments.
2515572901bSJohn Birrell  */
2525572901bSJohn Birrell int
2535572901bSJohn Birrell sdt_argtype_listall(struct sdt_probe *probe,
2545572901bSJohn Birrell     sdt_argtype_listall_func_t callback_func,void *arg)
2555572901bSJohn Birrell {
2565572901bSJohn Birrell 	int error = 0;
2575572901bSJohn Birrell 	int locked;
2585572901bSJohn Birrell 	struct sdt_argtype *argtype;
2595572901bSJohn Birrell 
2605572901bSJohn Birrell 	locked = sx_xlocked(&sdt_sx);
2615572901bSJohn Birrell 	if (!locked)
2625572901bSJohn Birrell 		sx_xlock(&sdt_sx);
2635572901bSJohn Birrell 
2645572901bSJohn Birrell 	TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
2655572901bSJohn Birrell 		if ((error = callback_func(argtype, arg)) != 0)
2665572901bSJohn Birrell 			break;
2675572901bSJohn Birrell 	}
2685572901bSJohn Birrell 
2695572901bSJohn Birrell 	if (!locked)
2705572901bSJohn Birrell 		sx_xunlock(&sdt_sx);
2715572901bSJohn Birrell 
2725572901bSJohn Birrell 	return (error);
2735572901bSJohn Birrell }
274