1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/modctl.h> 29 #include <sys/sunddi.h> 30 #include <sys/dtrace.h> 31 #include <sys/kobj.h> 32 #include <sys/stat.h> 33 #include <sys/conf.h> 34 #include <vm/seg_kmem.h> 35 #include <sys/stack.h> 36 #include <sys/sdt_impl.h> 37 38 #define SDT_PATCHVAL 0xf0 39 #define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) 40 #define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ 41 42 static dev_info_t *sdt_devi; 43 static int sdt_verbose = 0; 44 static sdt_probe_t **sdt_probetab; 45 static int sdt_probetab_size; 46 static int sdt_probetab_mask; 47 48 /*ARGSUSED*/ 49 static int 50 sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 51 { 52 uintptr_t stack0, stack1, stack2, stack3, stack4; 53 int i = 0; 54 sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; 55 56 #ifdef __amd64 57 /* 58 * On amd64, stack[0] contains the dereferenced stack pointer, 59 * stack[1] contains savfp, stack[2] contains savpc. We want 60 * to step over these entries. 61 */ 62 i += 3; 63 #endif 64 65 for (; sdt != NULL; sdt = sdt->sdp_hashnext) { 66 if ((uintptr_t)sdt->sdp_patchpoint == addr) { 67 /* 68 * When accessing the arguments on the stack, we must 69 * protect against accessing beyond the stack. We can 70 * safely set NOFAULT here -- we know that interrupts 71 * are already disabled. 72 */ 73 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 74 stack0 = stack[i++]; 75 stack1 = stack[i++]; 76 stack2 = stack[i++]; 77 stack3 = stack[i++]; 78 stack4 = stack[i++]; 79 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | 80 CPU_DTRACE_BADADDR); 81 82 dtrace_probe(sdt->sdp_id, stack0, stack1, 83 stack2, stack3, stack4); 84 85 return (DTRACE_INVOP_NOP); 86 } 87 } 88 89 return (0); 90 } 91 92 /*ARGSUSED*/ 93 static void 94 sdt_provide_module(void *arg, struct modctl *ctl) 95 { 96 struct module *mp = ctl->mod_mp; 97 char *modname = ctl->mod_modname; 98 sdt_probedesc_t *sdpd; 99 sdt_probe_t *sdp, *old; 100 sdt_provider_t *prov; 101 int len; 102 103 /* 104 * One for all, and all for one: if we haven't yet registered all of 105 * our providers, we'll refuse to provide anything. 106 */ 107 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { 108 if (prov->sdtp_id == DTRACE_PROVNONE) 109 return; 110 } 111 112 if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) 113 return; 114 115 for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { 116 char *name = sdpd->sdpd_name, *func, *nname; 117 int i, j; 118 sdt_provider_t *prov; 119 ulong_t offs; 120 dtrace_id_t id; 121 122 for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { 123 char *prefix = prov->sdtp_prefix; 124 125 if (strncmp(name, prefix, strlen(prefix)) == 0) { 126 name += strlen(prefix); 127 break; 128 } 129 } 130 131 nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); 132 133 for (i = 0, j = 0; name[j] != '\0'; i++) { 134 if (name[j] == '_' && name[j + 1] == '_') { 135 nname[i] = '-'; 136 j += 2; 137 } else { 138 nname[i] = name[j++]; 139 } 140 } 141 142 nname[i] = '\0'; 143 144 sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); 145 sdp->sdp_loadcnt = ctl->mod_loadcnt; 146 sdp->sdp_ctl = ctl; 147 sdp->sdp_name = nname; 148 sdp->sdp_namelen = len; 149 sdp->sdp_provider = prov; 150 151 func = kobj_searchsym(mp, sdpd->sdpd_offset, &offs); 152 153 if (func == NULL) 154 func = "<unknown>"; 155 156 /* 157 * We have our provider. Now create the probe. 158 */ 159 if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, 160 func, nname)) != DTRACE_IDNONE) { 161 old = dtrace_probe_arg(prov->sdtp_id, id); 162 ASSERT(old != NULL); 163 164 sdp->sdp_next = old->sdp_next; 165 sdp->sdp_id = id; 166 old->sdp_next = sdp; 167 } else { 168 sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, 169 modname, func, nname, 3, sdp); 170 171 mp->sdt_nprobes++; 172 } 173 174 sdp->sdp_hashnext = 175 sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; 176 sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; 177 178 sdp->sdp_patchval = SDT_PATCHVAL; 179 sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; 180 sdp->sdp_savedval = *sdp->sdp_patchpoint; 181 } 182 } 183 184 /*ARGSUSED*/ 185 static void 186 sdt_destroy(void *arg, dtrace_id_t id, void *parg) 187 { 188 sdt_probe_t *sdp = parg, *old, *last, *hash; 189 struct modctl *ctl = sdp->sdp_ctl; 190 int ndx; 191 192 if (ctl != NULL && ctl->mod_loadcnt == sdp->sdp_loadcnt) { 193 if ((ctl->mod_loadcnt == sdp->sdp_loadcnt && 194 ctl->mod_loaded)) { 195 ((struct module *)(ctl->mod_mp))->sdt_nprobes--; 196 } 197 } 198 199 while (sdp != NULL) { 200 old = sdp; 201 202 /* 203 * Now we need to remove this probe from the sdt_probetab. 204 */ 205 ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); 206 last = NULL; 207 hash = sdt_probetab[ndx]; 208 209 while (hash != sdp) { 210 ASSERT(hash != NULL); 211 last = hash; 212 hash = hash->sdp_hashnext; 213 } 214 215 if (last != NULL) { 216 last->sdp_hashnext = sdp->sdp_hashnext; 217 } else { 218 sdt_probetab[ndx] = sdp->sdp_hashnext; 219 } 220 221 kmem_free(sdp->sdp_name, sdp->sdp_namelen); 222 sdp = sdp->sdp_next; 223 kmem_free(old, sizeof (sdt_probe_t)); 224 } 225 } 226 227 /*ARGSUSED*/ 228 static void 229 sdt_enable(void *arg, dtrace_id_t id, void *parg) 230 { 231 sdt_probe_t *sdp = parg; 232 struct modctl *ctl = sdp->sdp_ctl; 233 234 ctl->mod_nenabled++; 235 236 /* 237 * If this module has disappeared since we discovered its probes, 238 * refuse to enable it. 239 */ 240 if (!ctl->mod_loaded) { 241 if (sdt_verbose) { 242 cmn_err(CE_NOTE, "sdt is failing for probe %s " 243 "(module %s unloaded)", 244 sdp->sdp_name, ctl->mod_modname); 245 } 246 goto err; 247 } 248 249 /* 250 * Now check that our modctl has the expected load count. If it 251 * doesn't, this module must have been unloaded and reloaded -- and 252 * we're not going to touch it. 253 */ 254 if (ctl->mod_loadcnt != sdp->sdp_loadcnt) { 255 if (sdt_verbose) { 256 cmn_err(CE_NOTE, "sdt is failing for probe %s " 257 "(module %s reloaded)", 258 sdp->sdp_name, ctl->mod_modname); 259 } 260 goto err; 261 } 262 263 while (sdp != NULL) { 264 *sdp->sdp_patchpoint = sdp->sdp_patchval; 265 sdp = sdp->sdp_next; 266 } 267 err: 268 ; 269 } 270 271 /*ARGSUSED*/ 272 static void 273 sdt_disable(void *arg, dtrace_id_t id, void *parg) 274 { 275 sdt_probe_t *sdp = parg; 276 struct modctl *ctl = sdp->sdp_ctl; 277 278 ctl->mod_nenabled--; 279 280 if (!ctl->mod_loaded || ctl->mod_loadcnt != sdp->sdp_loadcnt) 281 goto err; 282 283 while (sdp != NULL) { 284 *sdp->sdp_patchpoint = sdp->sdp_savedval; 285 sdp = sdp->sdp_next; 286 } 287 288 err: 289 ; 290 } 291 292 static dtrace_pops_t sdt_pops = { 293 NULL, 294 sdt_provide_module, 295 sdt_enable, 296 sdt_disable, 297 NULL, 298 NULL, 299 sdt_getargdesc, 300 NULL, 301 NULL, 302 sdt_destroy 303 }; 304 305 /*ARGSUSED*/ 306 static int 307 sdt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 308 { 309 sdt_provider_t *prov; 310 311 if (ddi_create_minor_node(devi, "sdt", S_IFCHR, 312 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 313 cmn_err(CE_NOTE, "/dev/sdt couldn't create minor node"); 314 ddi_remove_minor_node(devi, NULL); 315 return (DDI_FAILURE); 316 } 317 318 ddi_report_dev(devi); 319 sdt_devi = devi; 320 321 if (sdt_probetab_size == 0) 322 sdt_probetab_size = SDT_PROBETAB_SIZE; 323 324 sdt_probetab_mask = sdt_probetab_size - 1; 325 sdt_probetab = 326 kmem_zalloc(sdt_probetab_size * sizeof (sdt_probe_t *), KM_SLEEP); 327 dtrace_invop_add(sdt_invop); 328 329 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { 330 if (dtrace_register(prov->sdtp_name, prov->sdtp_attr, 331 DTRACE_PRIV_KERNEL, NULL, 332 &sdt_pops, prov, &prov->sdtp_id) != 0) { 333 cmn_err(CE_WARN, "failed to register sdt provider %s", 334 prov->sdtp_name); 335 } 336 } 337 338 return (DDI_SUCCESS); 339 } 340 341 /*ARGSUSED*/ 342 static int 343 sdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 344 { 345 sdt_provider_t *prov; 346 347 switch (cmd) { 348 case DDI_DETACH: 349 break; 350 351 case DDI_SUSPEND: 352 return (DDI_SUCCESS); 353 354 default: 355 return (DDI_FAILURE); 356 } 357 358 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { 359 if (prov->sdtp_id != DTRACE_PROVNONE) { 360 if (dtrace_unregister(prov->sdtp_id) != 0) 361 return (DDI_FAILURE); 362 363 prov->sdtp_id = DTRACE_PROVNONE; 364 } 365 } 366 367 dtrace_invop_remove(sdt_invop); 368 kmem_free(sdt_probetab, sdt_probetab_size * sizeof (sdt_probe_t *)); 369 370 return (DDI_SUCCESS); 371 } 372 373 /*ARGSUSED*/ 374 static int 375 sdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 376 { 377 int error; 378 379 switch (infocmd) { 380 case DDI_INFO_DEVT2DEVINFO: 381 *result = (void *)sdt_devi; 382 error = DDI_SUCCESS; 383 break; 384 case DDI_INFO_DEVT2INSTANCE: 385 *result = (void *)0; 386 error = DDI_SUCCESS; 387 break; 388 default: 389 error = DDI_FAILURE; 390 } 391 return (error); 392 } 393 394 /*ARGSUSED*/ 395 static int 396 sdt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 397 { 398 return (0); 399 } 400 401 static struct cb_ops sdt_cb_ops = { 402 sdt_open, /* open */ 403 nodev, /* close */ 404 nulldev, /* strategy */ 405 nulldev, /* print */ 406 nodev, /* dump */ 407 nodev, /* read */ 408 nodev, /* write */ 409 nodev, /* ioctl */ 410 nodev, /* devmap */ 411 nodev, /* mmap */ 412 nodev, /* segmap */ 413 nochpoll, /* poll */ 414 ddi_prop_op, /* cb_prop_op */ 415 0, /* streamtab */ 416 D_NEW | D_MP /* Driver compatibility flag */ 417 }; 418 419 static struct dev_ops sdt_ops = { 420 DEVO_REV, /* devo_rev, */ 421 0, /* refcnt */ 422 sdt_info, /* get_dev_info */ 423 nulldev, /* identify */ 424 nulldev, /* probe */ 425 sdt_attach, /* attach */ 426 sdt_detach, /* detach */ 427 nodev, /* reset */ 428 &sdt_cb_ops, /* driver operations */ 429 NULL, /* bus operations */ 430 nodev /* dev power */ 431 }; 432 433 /* 434 * Module linkage information for the kernel. 435 */ 436 static struct modldrv modldrv = { 437 &mod_driverops, /* module type (this is a pseudo driver) */ 438 "Statically Defined Tracing", /* name of module */ 439 &sdt_ops, /* driver ops */ 440 }; 441 442 static struct modlinkage modlinkage = { 443 MODREV_1, 444 (void *)&modldrv, 445 NULL 446 }; 447 448 int 449 _init(void) 450 { 451 return (mod_install(&modlinkage)); 452 } 453 454 int 455 _info(struct modinfo *modinfop) 456 { 457 return (mod_info(&modlinkage, modinfop)); 458 } 459 460 int 461 _fini(void) 462 { 463 return (mod_remove(&modlinkage)); 464 } 465