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