1179237Sjb/*
2179237Sjb * CDDL HEADER START
3179237Sjb *
4179237Sjb * The contents of this file are subject to the terms of the
5179237Sjb * Common Development and Distribution License (the "License").
6179237Sjb * You may not use this file except in compliance with the License.
7179237Sjb *
8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9179237Sjb * or http://www.opensolaris.org/os/licensing.
10179237Sjb * See the License for the specific language governing permissions
11179237Sjb * and limitations under the License.
12179237Sjb *
13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each
14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15179237Sjb * If applicable, add the following below this CDDL HEADER, with the
16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18179237Sjb *
19179237Sjb * CDDL HEADER END
20179237Sjb *
21179237Sjb * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
22179237Sjb *
23179237Sjb * $FreeBSD$
24179237Sjb *
25179237Sjb */
26179237Sjb
27262041Savg/*
28262041Savg * This file contains a reimplementation of the statically-defined tracing (SDT)
29262041Savg * framework for DTrace. Probes and SDT providers are defined using the macros
30262041Savg * in sys/sdt.h, which append all the needed structures to linker sets. When
31262041Savg * this module is loaded, it iterates over all of the loaded modules and
32262041Savg * registers probes and providers with the DTrace framework based on the
33262041Savg * contents of these linker sets.
34262041Savg *
35262041Savg * A list of SDT providers is maintained here since a provider may span multiple
36262041Savg * modules. When a kernel module is unloaded, a provider defined in that module
37262041Savg * is unregistered only if no other modules refer to it. The DTrace framework is
38262041Savg * responsible for destroying individual probes when a kernel module is
39262041Savg * unloaded; in particular, probes may not span multiple kernel modules.
40262041Savg */
41262041Savg
42255763Smarkj#include "opt_kdtrace.h"
43179237Sjb
44179237Sjb#include <sys/cdefs.h>
45179237Sjb#include <sys/param.h>
46179237Sjb#include <sys/systm.h>
47255763Smarkj
48179237Sjb#include <sys/conf.h>
49255763Smarkj#include <sys/eventhandler.h>
50179237Sjb#include <sys/kernel.h>
51179237Sjb#include <sys/limits.h>
52255763Smarkj#include <sys/linker.h>
53255763Smarkj#include <sys/linker_set.h>
54179237Sjb#include <sys/lock.h>
55255763Smarkj#include <sys/malloc.h>
56179237Sjb#include <sys/module.h>
57179237Sjb#include <sys/mutex.h>
58255763Smarkj#include <sys/queue.h>
59255763Smarkj#include <sys/sdt.h>
60179237Sjb
61179237Sjb#include <sys/dtrace.h>
62255763Smarkj#include <sys/dtrace_bsd.h>
63179237Sjb
64255763Smarkj/* DTrace methods. */
65179237Sjbstatic void	sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
66179237Sjbstatic void	sdt_provide_probes(void *, dtrace_probedesc_t *);
67179237Sjbstatic void	sdt_destroy(void *, dtrace_id_t, void *);
68179237Sjbstatic void	sdt_enable(void *, dtrace_id_t, void *);
69179237Sjbstatic void	sdt_disable(void *, dtrace_id_t, void *);
70255763Smarkj
71262041Savgstatic void	sdt_load(void);
72262041Savgstatic int	sdt_unload(void);
73255763Smarkjstatic void	sdt_create_provider(struct sdt_provider *);
74255763Smarkjstatic void	sdt_create_probe(struct sdt_probe *);
75255763Smarkjstatic void	sdt_kld_load(void *, struct linker_file *);
76262038Savgstatic void	sdt_kld_unload_try(void *, struct linker_file *, int *);
77179237Sjb
78255763Smarkjstatic MALLOC_DEFINE(M_SDT, "SDT", "DTrace SDT providers");
79255763Smarkj
80179237Sjbstatic dtrace_pattr_t sdt_attr = {
81179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
82179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
83179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
84179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
85179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
86179237Sjb};
87179237Sjb
88179237Sjbstatic dtrace_pops_t sdt_pops = {
89179237Sjb	sdt_provide_probes,
90179237Sjb	NULL,
91179237Sjb	sdt_enable,
92179237Sjb	sdt_disable,
93179237Sjb	NULL,
94179237Sjb	NULL,
95179237Sjb	sdt_getargdesc,
96179237Sjb	NULL,
97179237Sjb	NULL,
98255763Smarkj	sdt_destroy,
99179237Sjb};
100179237Sjb
101255763Smarkjstatic TAILQ_HEAD(, sdt_provider) sdt_prov_list;
102255763Smarkj
103255763Smarkjeventhandler_tag	sdt_kld_load_tag;
104262038Savgeventhandler_tag	sdt_kld_unload_try_tag;
105255763Smarkj
106255763Smarkjstatic void
107255763Smarkjsdt_create_provider(struct sdt_provider *prov)
108179237Sjb{
109255763Smarkj	struct sdt_provider *curr, *newprov;
110179237Sjb
111255763Smarkj	TAILQ_FOREACH(curr, &sdt_prov_list, prov_entry)
112255763Smarkj		if (strcmp(prov->name, curr->name) == 0) {
113255763Smarkj			/* The provider has already been defined. */
114255763Smarkj			curr->sdt_refs++;
115255763Smarkj			return;
116255763Smarkj		}
117179237Sjb
118255763Smarkj	/*
119255763Smarkj	 * Make a copy of prov so that we don't lose fields if its module is
120255763Smarkj	 * unloaded but the provider isn't destroyed. This could happen with
121255763Smarkj	 * a provider that spans multiple modules.
122255763Smarkj	 */
123255763Smarkj	newprov = malloc(sizeof(*newprov), M_SDT, M_WAITOK | M_ZERO);
124255763Smarkj	newprov->name = strdup(prov->name, M_SDT);
125255763Smarkj	prov->sdt_refs = newprov->sdt_refs = 1;
126255763Smarkj
127255763Smarkj	TAILQ_INSERT_TAIL(&sdt_prov_list, newprov, prov_entry);
128255763Smarkj
129255763Smarkj	(void)dtrace_register(newprov->name, &sdt_attr, DTRACE_PRIV_USER, NULL,
130255763Smarkj	    &sdt_pops, NULL, (dtrace_provider_id_t *)&newprov->id);
131255763Smarkj	prov->id = newprov->id;
132179237Sjb}
133179237Sjb
134179237Sjbstatic void
135255763Smarkjsdt_create_probe(struct sdt_probe *probe)
136179237Sjb{
137255763Smarkj	struct sdt_provider *prov;
138255763Smarkj	char mod[DTRACE_MODNAMELEN];
139255763Smarkj	char func[DTRACE_FUNCNAMELEN];
140255763Smarkj	char name[DTRACE_NAMELEN];
141262057Savg	const char *from;
142262057Savg	char *to;
143255763Smarkj	size_t len;
144179237Sjb
145255763Smarkj	TAILQ_FOREACH(prov, &sdt_prov_list, prov_entry)
146255763Smarkj		if (strcmp(prov->name, probe->prov->name) == 0)
147255763Smarkj			break;
148179237Sjb
149255763Smarkj	KASSERT(prov != NULL, ("probe defined without a provider"));
150179237Sjb
151255763Smarkj	/* If no module name was specified, use the module filename. */
152255763Smarkj	if (*probe->mod == 0) {
153255763Smarkj		len = strlcpy(mod, probe->sdtp_lf->filename, sizeof(mod));
154255763Smarkj		if (len > 3 && strcmp(mod + len - 3, ".ko") == 0)
155255763Smarkj			mod[len - 3] = '\0';
156255763Smarkj	} else
157255763Smarkj		strlcpy(mod, probe->mod, sizeof(mod));
158179237Sjb
159179237Sjb	/*
160179237Sjb	 * Unfortunately this is necessary because the Solaris DTrace
161179237Sjb	 * code mixes consts and non-consts with casts to override
162179237Sjb	 * the incompatibilies. On FreeBSD, we use strict warnings
163255763Smarkj	 * in the C compiler, so we have to respect const vs non-const.
164179237Sjb	 */
165179237Sjb	strlcpy(func, probe->func, sizeof(func));
166179237Sjb
167262057Savg	from = probe->name;
168262057Savg	to = name;
169262057Savg	for (len = 0; len < (sizeof(name) - 1) && *from != '\0';
170262057Savg	    len++, from++, to++) {
171262057Savg		if (from[0] == '_' && from[1] == '_') {
172262057Savg			*to = '-';
173262057Savg			from++;
174262057Savg		} else
175262057Savg			*to = *from;
176262057Savg	}
177262057Savg	*to = '\0';
178262057Savg
179255763Smarkj	if (dtrace_probe_lookup(prov->id, mod, func, name) != DTRACE_IDNONE)
180255763Smarkj		return;
181179237Sjb
182255763Smarkj	(void)dtrace_probe_create(prov->id, mod, func, name, 1, probe);
183179237Sjb}
184179237Sjb
185262041Savg/*
186262041Savg * Probes are created through the SDT module load/unload hook, so this function
187262041Savg * has nothing to do. It only exists because the DTrace provider framework
188262041Savg * requires one of provide_probes and provide_module to be defined.
189262041Savg */
190255763Smarkjstatic void
191255763Smarkjsdt_provide_probes(void *arg, dtrace_probedesc_t *desc)
192179237Sjb{
193179237Sjb}
194179237Sjb
195179237Sjbstatic void
196255763Smarkjsdt_enable(void *arg __unused, dtrace_id_t id, void *parg)
197179237Sjb{
198255763Smarkj	struct sdt_probe *probe = parg;
199179237Sjb
200255763Smarkj	probe->id = id;
201255763Smarkj	probe->sdtp_lf->nenabled++;
202179237Sjb}
203179237Sjb
204179237Sjbstatic void
205255763Smarkjsdt_disable(void *arg __unused, dtrace_id_t id, void *parg)
206179237Sjb{
207255763Smarkj	struct sdt_probe *probe = parg;
208255763Smarkj
209255763Smarkj	KASSERT(probe->sdtp_lf->nenabled > 0, ("no probes enabled"));
210255763Smarkj
211255763Smarkj	probe->id = 0;
212255763Smarkj	probe->sdtp_lf->nenabled--;
213179237Sjb}
214179237Sjb
215179237Sjbstatic void
216255763Smarkjsdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
217179237Sjb{
218255763Smarkj	struct sdt_argtype *argtype;
219179237Sjb	struct sdt_probe *probe = parg;
220179237Sjb
221262041Savg	if (desc->dtargd_ndx >= probe->n_args) {
222262041Savg		desc->dtargd_ndx = DTRACE_ARGNONE;
223262041Savg		return;
224262041Savg	}
225262041Savg
226262041Savg	TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
227262041Savg		if (desc->dtargd_ndx == argtype->ndx) {
228262041Savg			desc->dtargd_mapping = desc->dtargd_ndx;
229262041Savg			if (argtype->type == NULL) {
230262041Savg				desc->dtargd_native[0] = '\0';
231262041Savg				desc->dtargd_xlate[0] = '\0';
232262041Savg				continue;
233255763Smarkj			}
234262041Savg			strlcpy(desc->dtargd_native, argtype->type,
235262041Savg			    sizeof(desc->dtargd_native));
236262041Savg			if (argtype->xtype != NULL)
237262041Savg				strlcpy(desc->dtargd_xlate, argtype->xtype,
238262041Savg				    sizeof(desc->dtargd_xlate));
239255763Smarkj		}
240262041Savg	}
241179237Sjb}
242179237Sjb
243179237Sjbstatic void
244255763Smarkjsdt_destroy(void *arg, dtrace_id_t id, void *parg)
245179237Sjb{
246179237Sjb}
247179237Sjb
248255763Smarkj/*
249255763Smarkj * Called from the kernel linker when a module is loaded, before
250255763Smarkj * dtrace_module_loaded() is called. This is done so that it's possible to
251262041Savg * register new providers when modules are loaded. The DTrace framework
252262041Savg * explicitly disallows calling into the framework from the provide_module
253262041Savg * provider method, so we cannot do this there.
254255763Smarkj */
255255763Smarkjstatic void
256255763Smarkjsdt_kld_load(void *arg __unused, struct linker_file *lf)
257255763Smarkj{
258255763Smarkj	struct sdt_provider **prov, **begin, **end;
259255763Smarkj	struct sdt_probe **probe, **p_begin, **p_end;
260255763Smarkj	struct sdt_argtype **argtype, **a_begin, **a_end;
261255763Smarkj
262255763Smarkj	if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end, NULL))
263255763Smarkj		return;
264255763Smarkj	for (prov = begin; prov < end; prov++)
265255763Smarkj		sdt_create_provider(*prov);
266255763Smarkj
267255763Smarkj	if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
268255763Smarkj	    NULL))
269255763Smarkj		return;
270255763Smarkj	for (probe = p_begin; probe < p_end; probe++) {
271255763Smarkj		(*probe)->sdtp_lf = lf;
272255763Smarkj		sdt_create_probe(*probe);
273255763Smarkj		TAILQ_INIT(&(*probe)->argtype_list);
274255763Smarkj	}
275255763Smarkj
276255763Smarkj	if (linker_file_lookup_set(lf, "sdt_argtypes_set", &a_begin, &a_end,
277255763Smarkj	    NULL))
278255763Smarkj		return;
279255763Smarkj	for (argtype = a_begin; argtype < a_end; argtype++) {
280255763Smarkj		(*argtype)->probe->n_args++;
281255763Smarkj		TAILQ_INSERT_TAIL(&(*argtype)->probe->argtype_list, *argtype,
282255763Smarkj		    argtype_entry);
283255763Smarkj	}
284255763Smarkj}
285255763Smarkj
286255763Smarkjstatic void
287262041Savgsdt_kld_unload_try(void *arg __unused, struct linker_file *lf, int *error)
288255763Smarkj{
289255763Smarkj	struct sdt_provider *prov, **curr, **begin, **end, *tmp;
290255763Smarkj
291255763Smarkj	if (*error != 0)
292255763Smarkj		/* We already have an error, so don't do anything. */
293255763Smarkj		return;
294262041Savg	else if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end,
295262041Savg	    NULL))
296255763Smarkj		/* No DTrace providers are declared in this file. */
297255763Smarkj		return;
298255763Smarkj
299255763Smarkj	/*
300255763Smarkj	 * Go through all the providers declared in this linker file and
301255763Smarkj	 * unregister any that aren't declared in another loaded file.
302255763Smarkj	 */
303255763Smarkj	for (curr = begin; curr < end; curr++) {
304255763Smarkj		TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
305262041Savg			if (strcmp(prov->name, (*curr)->name) != 0)
306262041Savg				continue;
307262041Savg
308262041Savg			if (prov->sdt_refs == 1) {
309262041Savg				if (dtrace_unregister(prov->id) != 0) {
310262041Savg					*error = 1;
311262041Savg					return;
312262041Savg				}
313262041Savg				TAILQ_REMOVE(&sdt_prov_list, prov, prov_entry);
314262041Savg				free(prov->name, M_SDT);
315262041Savg				free(prov, M_SDT);
316262041Savg			} else
317262041Savg				prov->sdt_refs--;
318262041Savg			break;
319255763Smarkj		}
320255763Smarkj	}
321255763Smarkj}
322255763Smarkj
323179237Sjbstatic int
324255763Smarkjsdt_linker_file_cb(linker_file_t lf, void *arg __unused)
325179237Sjb{
326255763Smarkj
327255763Smarkj	sdt_kld_load(NULL, lf);
328255763Smarkj
329255763Smarkj	return (0);
330179237Sjb}
331179237Sjb
332179237Sjbstatic void
333262041Savgsdt_load()
334179237Sjb{
335255763Smarkj
336255763Smarkj	TAILQ_INIT(&sdt_prov_list);
337255763Smarkj
338179237Sjb	sdt_probe_func = dtrace_probe;
339179237Sjb
340255763Smarkj	sdt_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, sdt_kld_load, NULL,
341255763Smarkj	    EVENTHANDLER_PRI_ANY);
342262038Savg	sdt_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
343262038Savg	    sdt_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
344179237Sjb
345255763Smarkj	/* Pick up probes from the kernel and already-loaded linker files. */
346255763Smarkj	linker_file_foreach(sdt_linker_file_cb, NULL);
347179237Sjb}
348179237Sjb
349179237Sjbstatic int
350262041Savgsdt_unload()
351179237Sjb{
352255763Smarkj	struct sdt_provider *prov, *tmp;
353262041Savg	int ret;
354179237Sjb
355255763Smarkj	EVENTHANDLER_DEREGISTER(kld_load, sdt_kld_load_tag);
356262038Savg	EVENTHANDLER_DEREGISTER(kld_unload_try, sdt_kld_unload_try_tag);
357255763Smarkj
358179237Sjb	sdt_probe_func = sdt_probe_stub;
359179237Sjb
360255763Smarkj	TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
361262041Savg		ret = dtrace_unregister(prov->id);
362262041Savg		if (ret != 0)
363262041Savg			return (ret);
364255763Smarkj		TAILQ_REMOVE(&sdt_prov_list, prov, prov_entry);
365255763Smarkj		free(prov->name, M_SDT);
366255763Smarkj		free(prov, M_SDT);
367255763Smarkj	}
368255763Smarkj
369255763Smarkj	return (0);
370179237Sjb}
371179237Sjb
372179237Sjbstatic int
373179237Sjbsdt_modevent(module_t mod __unused, int type, void *data __unused)
374179237Sjb{
375179237Sjb	int error = 0;
376179237Sjb
377179237Sjb	switch (type) {
378179237Sjb	case MOD_LOAD:
379262041Savg		sdt_load();
380179237Sjb		break;
381179237Sjb
382179237Sjb	case MOD_UNLOAD:
383262041Savg		error = sdt_unload();
384179237Sjb		break;
385179237Sjb
386179237Sjb	case MOD_SHUTDOWN:
387179237Sjb		break;
388179237Sjb
389179237Sjb	default:
390179237Sjb		error = EOPNOTSUPP;
391179237Sjb		break;
392179237Sjb	}
393179237Sjb
394179237Sjb	return (error);
395179237Sjb}
396179237Sjb
397179237SjbDEV_MODULE(sdt, sdt_modevent, NULL);
398179237SjbMODULE_VERSION(sdt, 1);
399179237SjbMODULE_DEPEND(sdt, dtrace, 1, 1, 1);
400179237SjbMODULE_DEPEND(sdt, opensolaris, 1, 1, 1);
401