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