xref: /netbsd-src/external/cddl/osnet/dev/sdt/sdt.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: sdt.c,v 1.8 2011/07/30 10:12:14 uebayasi Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by CoyotePoint Systems, Inc. It was developed under contract to
9  * CoyotePoint by Darran Hunt.
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  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifdef _KERNEL_OPT
35 #include "opt_dtrace.h"
36 #endif
37 
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/conf.h>
42 #include <sys/kernel.h>
43 #include <sys/kmem.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 
47 #include <sys/dtrace.h>
48 
49 #define KDTRACE_HOOKS
50 #include <sys/sdt.h>
51 
52 #undef SDT_DEBUG
53 
54 static dev_type_open(sdt_open);
55 
56 static int	sdt_unload(void);
57 static void	sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
58 static void	sdt_provide(void *, const dtrace_probedesc_t *);
59 static void	sdt_destroy(void *, dtrace_id_t, void *);
60 static int	sdt_enable(void *, dtrace_id_t, void *);
61 static void	sdt_disable(void *, dtrace_id_t, void *);
62 static void	sdt_load(void *);
63 
64 static const struct cdevsw sdt_cdevsw = {
65 	sdt_open, noclose, noread, nowrite, noioctl,
66 	nostop, notty, nopoll, nommap, nokqfilter,
67 	D_OTHER
68 };
69 
70 static dtrace_pops_t sdt_pops = {
71 	sdt_provide,
72 	NULL,
73 	sdt_enable,
74 	sdt_disable,
75 	NULL,
76 	NULL,
77 	sdt_getargdesc,
78 	NULL,
79 	NULL,
80 	sdt_destroy
81 };
82 
83 #ifdef notyet
84 static struct cdev		*sdt_cdev;
85 #endif
86 
87 /*
88  * Provider and probe definitions
89  */
90 
91 /*
92  * proc provider
93  */
94 
95 /* declare all probes belonging to the provider */
96 SDT_PROBE_DECLARE(proc,,,create);
97 SDT_PROBE_DECLARE(proc,,,exec);
98 SDT_PROBE_DECLARE(proc,,,exec_success);
99 SDT_PROBE_DECLARE(proc,,,exec_failure);
100 SDT_PROBE_DECLARE(proc,,,signal_send);
101 SDT_PROBE_DECLARE(proc,,,signal_discard);
102 SDT_PROBE_DECLARE(proc,,,signal_clear);
103 SDT_PROBE_DECLARE(proc,,,signal_handle);
104 SDT_PROBE_DECLARE(proc,,,lwp_create);
105 SDT_PROBE_DECLARE(proc,,,lwp_start);
106 SDT_PROBE_DECLARE(proc,,,lwp_exit);
107 
108 /* define the provider */
109 static sdt_provider_t proc_provider = {
110 	"proc",		/* provider name */
111 	0,		/* registered ID - leave as 0 */
112 	{
113 		{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
114 		{ DTRACE_STABILITY_PRIVATE,  DTRACE_STABILITY_PRIVATE,  DTRACE_CLASS_UNKNOWN },
115 		{ DTRACE_STABILITY_PRIVATE,  DTRACE_STABILITY_PRIVATE,  DTRACE_CLASS_ISA },
116 		{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
117 		{ DTRACE_STABILITY_PRIVATE,  DTRACE_STABILITY_PRIVATE,  DTRACE_CLASS_ISA },
118 	},
119 
120 	/* list all probes belonging to the provider */
121 	{
122 		&SDT_NAME(proc,,,create),
123 		&SDT_NAME(proc,,,exec),
124 		&SDT_NAME(proc,,,exec_success),
125 		&SDT_NAME(proc,,,exec_failure),
126 		&SDT_NAME(proc,,,signal_send),
127 		&SDT_NAME(proc,,,signal_discard),
128 		&SDT_NAME(proc,,,signal_clear),
129 		&SDT_NAME(proc,,,signal_handle),
130 		&SDT_NAME(proc,,,lwp_create),
131 		&SDT_NAME(proc,,,lwp_start),
132 		&SDT_NAME(proc,,,lwp_exit),
133 		NULL				/* NULL terminated list */
134 	}
135 };
136 
137 /* list of local providers to register with DTrace */
138 static sdt_provider_t *sdt_providers[] = {
139 	&proc_provider,
140 	NULL		/* NULL terminated list */
141 };
142 
143 static sdt_provider_t **sdt_list = NULL;	/* registered provider list */
144 static kmutex_t sdt_mutex;
145 static int sdt_count = 0;	/* number of registered providers */
146 
147 static void
148 sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
149 {
150 	sdt_probe_t *sprobe = parg;
151 
152 #ifdef SDT_DEBUG
153 	printf("sdt: %s probe %d\n", __func__, id);
154 	printf("%s: probe %d (%s:%s:%s:%s).%d\n",
155 		__func__, id,
156 		sprobe->provider,
157 		sprobe->module,
158 		sprobe->function,
159 		sprobe->name,
160 		desc->dtargd_ndx);
161 #endif
162 
163 	/* provide up to 5 arguments  */
164 	if ((desc->dtargd_ndx < SDT_MAX_ARGS) &&
165 		(sprobe->argv[desc->dtargd_ndx] != NULL)) {
166 		strncpy(desc->dtargd_native, sprobe->argv[desc->dtargd_ndx],
167 			sizeof(desc->dtargd_native));
168 		desc->dtargd_mapping = desc->dtargd_ndx;
169 		if (sprobe->argx[desc->dtargd_ndx] != NULL) {
170 			strncpy(desc->dtargd_xlate, sprobe->argx[desc->dtargd_ndx],
171 			    sizeof(desc->dtargd_xlate));
172 		}
173 #ifdef SDT_DEBUG
174 		printf("%s: probe %d (%s:%s:%s:%s).%d = %s\n",
175 			__func__, id,
176 			sprobe->provider,
177 			sprobe->module,
178 			sprobe->function,
179 			sprobe->name,
180 			desc->dtargd_ndx,
181 			sprobe->argv[desc->dtargd_ndx]);
182 #endif
183 	} else {
184 #ifdef SDT_DEBUG
185 		printf("%s: probe %d (%s:%s:%s:%s).%d = NULL\n",
186 			__func__, id,
187 			sprobe->provider,
188 			sprobe->module,
189 			sprobe->function,
190 			sprobe->name,
191 			desc->dtargd_ndx);
192 		desc->dtargd_ndx = DTRACE_ARGNONE;
193 #endif
194 	}
195 }
196 
197 static void
198 sdt_provide(void *arg, const dtrace_probedesc_t *desc)
199 {
200 	sdt_provider_t *sprov = arg;
201 	int res;
202 	int ind;
203 	int num_probes = 0;
204 
205 #ifdef SDT_DEBUG
206 	if (desc == NULL) {
207 		printf("sdt: provide null\n");
208 	} else {
209 		printf("sdt: provide %d %02x:%02x:%02x:%02x\n",
210 		    desc->dtpd_id,
211 		    desc->dtpd_provider[0],
212 		    desc->dtpd_mod[0],
213 		    desc->dtpd_func[0],
214 		    desc->dtpd_name[0]);
215 	}
216 #endif
217 
218 	for (ind = 0; sprov->probes[ind] != NULL; ind++) {
219 	    	if (sprov->probes[ind]->created == 0) {
220 			res = dtrace_probe_create(sprov->id,
221 				sprov->probes[ind]->module,
222 				sprov->probes[ind]->function,
223 				sprov->probes[ind]->name,
224 				0, sprov->probes[ind]);
225 			sprov->probes[ind]->id = res;
226 #ifdef SDT_DEBUG
227 			printf("%s: dtrace_probe_create[%d] res=%d\n",
228 				__func__, ind, res);
229 #endif
230 			sprov->probes[ind]->created = 1;
231 			num_probes++;
232 		}
233 	}
234 
235 #ifdef SDT_DEBUG
236 	printf("sdt: %s num_probes %d\n", __func__, ind);
237 #endif
238 
239 }
240 
241 static void
242 sdt_destroy(void *arg, dtrace_id_t id, void *parg)
243 {
244 	sdt_provider_t *sprov = arg;
245 	int ind;
246 
247 #ifdef SDT_DEBUG
248 	printf("sdt: %s\n", __func__);
249 #endif
250 
251 	for (ind = 0; sprov->probes[ind] != NULL; ind++) {
252 	    	if (sprov->probes[ind]->id == id) {
253 #ifdef SDT_DEBUG
254 		    	printf("%s: destroying probe %d (%s:%s:%s:%s)\n",
255 				__func__, id,
256 				sprov->probes[ind]->provider,
257 				sprov->probes[ind]->module,
258 				sprov->probes[ind]->function,
259 				sprov->probes[ind]->name);
260 #endif
261 			sprov->probes[ind]->enabled = 0;
262 			sprov->probes[ind]->created = 0;
263 			sprov->probes[ind]->id = 0;
264 			break;
265 		}
266 	}
267 }
268 
269 static int
270 sdt_enable(void *arg, dtrace_id_t id, void *parg)
271 {
272 	sdt_provider_t *sprov = arg;
273 	int ind;
274 
275 #ifdef SDT_DEBUG
276 	printf("sdt: %s\n", __func__);
277 #endif
278 
279 	for (ind = 0; sprov->probes[ind] != NULL; ind++) {
280 	    	if (sprov->probes[ind]->id == id) {
281 #ifdef SDT_DEBUG
282 		    	printf("%s: enabling probe %d (%s:%s:%s:%s)\n",
283 				__func__, id,
284 				sprov->probes[ind]->provider,
285 				sprov->probes[ind]->module,
286 				sprov->probes[ind]->function,
287 				sprov->probes[ind]->name);
288 #endif
289 			sprov->probes[ind]->enabled = 1;
290 			break;
291 		}
292 	}
293 
294 	return 0;
295 }
296 
297 static void
298 sdt_disable(void *arg, dtrace_id_t id, void *parg)
299 {
300 	sdt_provider_t *sprov = arg;
301 	int ind;
302 
303 #ifdef SDT_DEBUG
304 	printf("sdt: %s\n", __func__);
305 #endif
306 
307 	for (ind = 0; sprov->probes[ind] != NULL; ind++) {
308 	    	if (sprov->probes[ind]->id == id) {
309 #ifdef SDT_DEBUG
310 		    	printf("%s: disabling probe %d (%s:%s:%s:%s)\n",
311 				__func__, id,
312 				sprov->probes[ind]->provider,
313 				sprov->probes[ind]->module,
314 				sprov->probes[ind]->function,
315 				sprov->probes[ind]->name);
316 #endif
317 			sprov->probes[ind]->enabled = 0;
318 			break;
319 		}
320 	}
321 }
322 
323 int
324 sdt_register(sdt_provider_t *prov)
325 {
326 	int ind;
327 	int res;
328 
329 	/* make sure the provider is not already registered */
330 	for (ind = 0; ind < sdt_count; ind++) {
331 		if (strncmp(sdt_list[ind]->name, prov->name,
332 		    SDT_MAX_NAME_SIZE) == 0) {
333 			printf("sdt: provider %s already registered\n", prov->name);
334 			return -1;
335 		}
336 	}
337 
338 	/* register the new provider */
339 	if ((res = dtrace_register(prov->name,
340 			    &prov->attr, DTRACE_PRIV_USER,
341 			    NULL, &sdt_pops, prov,
342 			    &(prov->id))) != 0) {
343 		printf("sdt: failed to register %s res = %d\n",
344 			prov->name, res);
345 		return -1;
346 	}
347 
348 	sdt_list[sdt_count++] = prov;
349 
350 	return 0;
351 }
352 
353 int
354 sdt_unregister(sdt_provider_t *prov)
355 {
356 	int ind;
357 	int res;
358 
359 	/* find the provider reference */
360 	for (ind = 0; ind < sdt_count; ind++) {
361 		if (sdt_list[ind] == prov) {
362 			res = dtrace_unregister(sdt_list[ind]->id);
363 			if (res != 0) {
364 				printf(
365 				    "sdt: failed to unregister provider %s\n",
366 				    sdt_list[ind]->name);
367 			}
368 			/* remove provider from list */
369 			sdt_list[ind] = sdt_list[--sdt_count];
370 			return 0;
371 		}
372 	}
373 
374 	/* provider not found */
375 	printf("sdt: provider %s not found\n", prov->name);
376 
377 	return 0;
378 }
379 
380 static void
381 sdt_load(void *dummy)
382 {
383 	int ind;
384 
385 #ifdef SDT_DEBUG
386 	printf("sdt: %s\n", __func__);
387 #endif
388 
389 	sdt_init(dtrace_probe);
390 
391 	sdt_list = kmem_alloc(sizeof(sdt_provider_t *) * SDT_MAX_PROVIDER,
392 	    KM_SLEEP);
393 
394 	mutex_init(&sdt_mutex, "sdt_mutex", MUTEX_DEFAULT, NULL);
395 
396 	sdt_count = 0;
397 
398 	if (sdt_list == NULL) {
399 		printf("sdt: failed to alloc provider list\n");
400 		return;
401 	}
402 
403 	for (ind = 0; sdt_providers[ind] != NULL; ind++) {
404 	    	if (sdt_count >= SDT_MAX_PROVIDER) {
405 			printf("sdt: too many providers\n");
406 			break;
407 		}
408 		sdt_register(sdt_providers[ind]);
409 
410 #ifdef SDT_DEBUG
411 		printf("sdt: registered %s id = 0x%x\n",
412 			sdt_providers[ind]->name,
413 			sdt_providers[ind]->id);
414 #endif
415 	}
416 }
417 
418 
419 static int
420 sdt_unload(void)
421 {
422 	int error = 0;
423 	int res = 0;
424 	int ind;
425 
426 #ifdef SDT_DEBUG
427 	printf("sdt: %s\n", __func__);
428 #endif
429 
430 	for (ind = 0; ind < sdt_count; ind++) {
431 		if ((res = dtrace_unregister(sdt_list[ind]->id)) != 0) {
432 #ifdef SDT_DEBUG
433 			printf("%s: failed to unregister %s error = %d\n",
434 			    sdt_list[ind]->name, res);
435 #endif
436 			error = res;
437 		} else {
438 #ifdef SDT_DEBUG
439 			printf("sdt: unregistered %s id = %d\n",
440 			    sdt_list[ind]->name,
441 			    sdt_list[ind]->id);
442 #endif
443 		}
444 	}
445 
446 	kmem_free(sdt_list, sizeof(sdt_provider_t *) * SDT_MAX_PROVIDER);
447 	mutex_destroy(&sdt_mutex);
448 	sdt_exit();
449 	return (error);
450 }
451 
452 static int
453 sdt_modcmd(modcmd_t cmd, void *data)
454 {
455 	int bmajor = -1, cmajor = -1;
456 
457 	switch (cmd) {
458 	case MODULE_CMD_INIT:
459 		sdt_load(NULL);
460 		return devsw_attach("sdt", NULL, &bmajor,
461 		    &sdt_cdevsw, &cmajor);
462 	case MODULE_CMD_FINI:
463 		sdt_unload();
464 		return devsw_detach(NULL, &sdt_cdevsw);
465 	default:
466 		return ENOTTY;
467 	}
468 }
469 
470 static int
471 sdt_open(dev_t dev, int flags, int mode, struct lwp *l)
472 {
473 	return (0);
474 }
475 
476 MODULE(MODULE_CLASS_MISC, sdt, "dtrace");
477