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 /* 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2011 by Delphix. All rights reserved. 25 * Copyright (c) 2011, Joyent, Inc. All rights reserved. 26 */ 27 28 #include <unistd.h> 29 #include <strings.h> 30 #include <stdlib.h> 31 #include <errno.h> 32 #include <assert.h> 33 #include <ctype.h> 34 #include <alloca.h> 35 36 #include <dt_impl.h> 37 #include <dt_program.h> 38 #include <dt_printf.h> 39 #include <dt_provider.h> 40 41 dtrace_prog_t * 42 dt_program_create(dtrace_hdl_t *dtp) 43 { 44 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); 45 46 if (pgp != NULL) { 47 dt_list_append(&dtp->dt_programs, pgp); 48 } else { 49 (void) dt_set_errno(dtp, EDT_NOMEM); 50 return (NULL); 51 } 52 53 /* 54 * By default, programs start with DOF version 1 so that output files 55 * containing DOF are backward compatible. If a program requires new 56 * DOF features, the version is increased as needed. 57 */ 58 pgp->dp_dofversion = DOF_VERSION_1; 59 60 return (pgp); 61 } 62 63 void 64 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) 65 { 66 dt_stmt_t *stp, *next; 67 uint_t i; 68 69 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 70 next = dt_list_next(stp); 71 dtrace_stmt_destroy(dtp, stp->ds_desc); 72 dt_free(dtp, stp); 73 } 74 75 for (i = 0; i < pgp->dp_xrefslen; i++) 76 dt_free(dtp, pgp->dp_xrefs[i]); 77 78 dt_free(dtp, pgp->dp_xrefs); 79 dt_list_delete(&dtp->dt_programs, pgp); 80 dt_free(dtp, pgp); 81 } 82 83 /*ARGSUSED*/ 84 void 85 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 86 dtrace_proginfo_t *pip) 87 { 88 dt_stmt_t *stp; 89 dtrace_actdesc_t *ap; 90 dtrace_ecbdesc_t *last = NULL; 91 92 if (pip == NULL) 93 return; 94 95 bzero(pip, sizeof (dtrace_proginfo_t)); 96 97 if (dt_list_next(&pgp->dp_stmts) != NULL) { 98 pip->dpi_descattr = _dtrace_maxattr; 99 pip->dpi_stmtattr = _dtrace_maxattr; 100 } else { 101 pip->dpi_descattr = _dtrace_defattr; 102 pip->dpi_stmtattr = _dtrace_defattr; 103 } 104 105 for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { 106 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; 107 108 if (edp == last) 109 continue; 110 last = edp; 111 112 pip->dpi_descattr = 113 dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); 114 115 pip->dpi_stmtattr = 116 dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); 117 118 /* 119 * If there aren't any actions, account for the fact that 120 * recording the epid will generate a record. 121 */ 122 if (edp->dted_action == NULL) 123 pip->dpi_recgens++; 124 125 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 126 if (ap->dtad_kind == DTRACEACT_SPECULATE) { 127 pip->dpi_speculations++; 128 continue; 129 } 130 131 if (DTRACEACT_ISAGG(ap->dtad_kind)) { 132 pip->dpi_recgens -= ap->dtad_arg; 133 pip->dpi_aggregates++; 134 continue; 135 } 136 137 if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) 138 continue; 139 140 if (ap->dtad_kind == DTRACEACT_DIFEXPR && 141 ap->dtad_difo->dtdo_rtype.dtdt_kind == 142 DIF_TYPE_CTF && 143 ap->dtad_difo->dtdo_rtype.dtdt_size == 0) 144 continue; 145 146 pip->dpi_recgens++; 147 } 148 } 149 } 150 151 int 152 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 153 dtrace_proginfo_t *pip) 154 { 155 void *dof; 156 int n, err; 157 158 if (!dtp->dt_optset) { 159 /* 160 * If we have not yet ioctl'd down our options DOF, we'll 161 * do that before enabling any probes (some options will 162 * affect which probes we match). 163 */ 164 if ((dof = dtrace_getopt_dof(dtp)) == NULL) 165 return (-1); /* dt_errno has been set for us */ 166 167 err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 168 dtrace_dof_destroy(dtp, dof); 169 170 if (err == -1) 171 return (-1); 172 173 dtp->dt_optset = B_TRUE; 174 } 175 176 dtrace_program_info(dtp, pgp, pip); 177 178 if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) 179 return (-1); 180 181 n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 182 dtrace_dof_destroy(dtp, dof); 183 184 if (n == -1) { 185 switch (errno) { 186 case EINVAL: 187 err = EDT_DIFINVAL; 188 break; 189 case EFAULT: 190 err = EDT_DIFFAULT; 191 break; 192 case E2BIG: 193 err = EDT_DIFSIZE; 194 break; 195 case EBUSY: 196 err = EDT_ENABLING_ERR; 197 break; 198 default: 199 err = errno; 200 } 201 202 return (dt_set_errno(dtp, err)); 203 } 204 205 if (pip != NULL) 206 pip->dpi_matches += n; 207 208 return (0); 209 } 210 211 static void 212 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) 213 { 214 edp->dted_refcnt++; 215 } 216 217 void 218 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 219 { 220 if (--edp->dted_refcnt > 0) 221 return; 222 223 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); 224 assert(edp->dted_action == NULL); 225 dt_free(dtp, edp); 226 } 227 228 dtrace_ecbdesc_t * 229 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 230 { 231 dtrace_ecbdesc_t *edp; 232 233 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { 234 (void) dt_set_errno(dtp, EDT_NOMEM); 235 return (NULL); 236 } 237 238 edp->dted_probe = *pdp; 239 dt_ecbdesc_hold(edp); 240 return (edp); 241 } 242 243 dtrace_stmtdesc_t * 244 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 245 { 246 dtrace_stmtdesc_t *sdp; 247 248 if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) 249 return (NULL); 250 251 dt_ecbdesc_hold(edp); 252 sdp->dtsd_ecbdesc = edp; 253 sdp->dtsd_descattr = _dtrace_defattr; 254 sdp->dtsd_stmtattr = _dtrace_defattr; 255 256 return (sdp); 257 } 258 259 dtrace_actdesc_t * 260 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 261 { 262 dtrace_actdesc_t *new; 263 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 264 265 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) 266 return (NULL); 267 268 if (sdp->dtsd_action_last != NULL) { 269 assert(sdp->dtsd_action != NULL); 270 assert(sdp->dtsd_action_last->dtad_next == NULL); 271 sdp->dtsd_action_last->dtad_next = new; 272 } else { 273 dtrace_actdesc_t *ap = edp->dted_action; 274 275 assert(sdp->dtsd_action == NULL); 276 sdp->dtsd_action = new; 277 278 while (ap != NULL && ap->dtad_next != NULL) 279 ap = ap->dtad_next; 280 281 if (ap == NULL) 282 edp->dted_action = new; 283 else 284 ap->dtad_next = new; 285 } 286 287 sdp->dtsd_action_last = new; 288 bzero(new, sizeof (dtrace_actdesc_t)); 289 new->dtad_uarg = (uintptr_t)sdp; 290 291 return (new); 292 } 293 294 int 295 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 296 { 297 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); 298 299 if (stp == NULL) 300 return (-1); /* errno is set for us */ 301 302 dt_list_append(&pgp->dp_stmts, stp); 303 stp->ds_desc = sdp; 304 305 return (0); 306 } 307 308 int 309 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 310 dtrace_stmt_f *func, void *data) 311 { 312 dt_stmt_t *stp, *next; 313 int status = 0; 314 315 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 316 next = dt_list_next(stp); 317 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 318 break; 319 } 320 321 return (status); 322 } 323 324 void 325 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 326 { 327 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 328 329 /* 330 * We need to remove any actions that we have on this ECB, and 331 * remove our hold on the ECB itself. 332 */ 333 if (sdp->dtsd_action != NULL) { 334 dtrace_actdesc_t *last = sdp->dtsd_action_last; 335 dtrace_actdesc_t *ap, *next; 336 337 assert(last != NULL); 338 339 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 340 if (ap == sdp->dtsd_action) 341 break; 342 343 if (ap->dtad_next == sdp->dtsd_action) 344 break; 345 } 346 347 assert(ap != NULL); 348 349 if (ap == edp->dted_action) 350 edp->dted_action = last->dtad_next; 351 else 352 ap->dtad_next = last->dtad_next; 353 354 /* 355 * We have now removed our action list from its ECB; we can 356 * safely destroy the list. 357 */ 358 last->dtad_next = NULL; 359 360 for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 361 assert(ap->dtad_uarg == (uintptr_t)sdp); 362 dt_difo_free(dtp, ap->dtad_difo); 363 next = ap->dtad_next; 364 dt_free(dtp, ap); 365 } 366 } 367 368 if (sdp->dtsd_fmtdata != NULL) 369 dt_printf_destroy(sdp->dtsd_fmtdata); 370 dt_free(dtp, sdp->dtsd_strdata); 371 372 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); 373 dt_free(dtp, sdp); 374 } 375 376 typedef struct dt_header_info { 377 dtrace_hdl_t *dthi_dtp; /* consumer handle */ 378 FILE *dthi_out; /* output file */ 379 char *dthi_pmname; /* provider macro name */ 380 char *dthi_pfname; /* provider function name */ 381 int dthi_empty; /* should we generate empty macros */ 382 } dt_header_info_t; 383 384 static void 385 dt_header_fmt_macro(char *buf, const char *str) 386 { 387 for (;;) { 388 if (islower(*str)) { 389 *buf++ = *str++ + 'A' - 'a'; 390 } else if (*str == '-') { 391 *buf++ = '_'; 392 str++; 393 } else if (*str == '.') { 394 *buf++ = '_'; 395 str++; 396 } else if ((*buf++ = *str++) == '\0') { 397 break; 398 } 399 } 400 } 401 402 static void 403 dt_header_fmt_func(char *buf, const char *str) 404 { 405 for (;;) { 406 if (*str == '-') { 407 *buf++ = '_'; 408 *buf++ = '_'; 409 str++; 410 } else if ((*buf++ = *str++) == '\0') { 411 break; 412 } 413 } 414 } 415 416 /*ARGSUSED*/ 417 static int 418 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 419 { 420 dt_header_info_t *infop = data; 421 dtrace_hdl_t *dtp = infop->dthi_dtp; 422 dt_probe_t *prp = idp->di_data; 423 dt_node_t *dnp; 424 char buf[DT_TYPE_NAMELEN]; 425 char *fname; 426 const char *p; 427 int i; 428 429 p = prp->pr_name; 430 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 431 p++; 432 433 fname = alloca(strlen(prp->pr_name) + 1 + i); 434 dt_header_fmt_func(fname, prp->pr_name); 435 436 if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", 437 infop->dthi_pfname, fname) < 0) 438 return (dt_set_errno(dtp, errno)); 439 440 for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { 441 if (fprintf(infop->dthi_out, "%s", 442 ctf_type_name(dnp->dn_ctfp, dnp->dn_type, 443 buf, sizeof (buf))) < 0) 444 return (dt_set_errno(dtp, errno)); 445 446 if (i + 1 != prp->pr_nargc && 447 fprintf(infop->dthi_out, ", ") < 0) 448 return (dt_set_errno(dtp, errno)); 449 } 450 451 if (i == 0 && fprintf(infop->dthi_out, "void") < 0) 452 return (dt_set_errno(dtp, errno)); 453 454 if (fprintf(infop->dthi_out, ");\n") < 0) 455 return (dt_set_errno(dtp, errno)); 456 457 if (fprintf(infop->dthi_out, 458 "#ifndef\t__sparc\n" 459 "extern int __dtraceenabled_%s___%s(void);\n" 460 "#else\n" 461 "extern int __dtraceenabled_%s___%s(long);\n" 462 "#endif\n", 463 infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0) 464 return (dt_set_errno(dtp, errno)); 465 466 return (0); 467 } 468 469 /*ARGSUSED*/ 470 static int 471 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 472 { 473 dt_header_info_t *infop = data; 474 dtrace_hdl_t *dtp = infop->dthi_dtp; 475 dt_probe_t *prp = idp->di_data; 476 char *mname, *fname; 477 const char *p; 478 int i; 479 480 p = prp->pr_name; 481 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 482 p++; 483 484 mname = alloca(strlen(prp->pr_name) + 1); 485 dt_header_fmt_macro(mname, prp->pr_name); 486 487 fname = alloca(strlen(prp->pr_name) + 1 + i); 488 dt_header_fmt_func(fname, prp->pr_name); 489 490 if (fprintf(infop->dthi_out, "#define\t%s_%s(", 491 infop->dthi_pmname, mname) < 0) 492 return (dt_set_errno(dtp, errno)); 493 494 for (i = 0; i < prp->pr_nargc; i++) { 495 if (fprintf(infop->dthi_out, "arg%d", i) < 0) 496 return (dt_set_errno(dtp, errno)); 497 498 if (i + 1 != prp->pr_nargc && 499 fprintf(infop->dthi_out, ", ") < 0) 500 return (dt_set_errno(dtp, errno)); 501 } 502 503 if (!infop->dthi_empty) { 504 if (fprintf(infop->dthi_out, ") \\\n\t") < 0) 505 return (dt_set_errno(dtp, errno)); 506 507 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", 508 infop->dthi_pfname, fname) < 0) 509 return (dt_set_errno(dtp, errno)); 510 511 for (i = 0; i < prp->pr_nargc; i++) { 512 if (fprintf(infop->dthi_out, "arg%d", i) < 0) 513 return (dt_set_errno(dtp, errno)); 514 515 if (i + 1 != prp->pr_nargc && 516 fprintf(infop->dthi_out, ", ") < 0) 517 return (dt_set_errno(dtp, errno)); 518 } 519 } 520 521 if (fprintf(infop->dthi_out, ")\n") < 0) 522 return (dt_set_errno(dtp, errno)); 523 524 if (!infop->dthi_empty) { 525 if (fprintf(infop->dthi_out, 526 "#ifndef\t__sparc\n" 527 "#define\t%s_%s_ENABLED() \\\n" 528 "\t__dtraceenabled_%s___%s()\n" 529 "#else\n" 530 "#define\t%s_%s_ENABLED() \\\n" 531 "\t__dtraceenabled_%s___%s(0)\n" 532 "#endif\n", 533 infop->dthi_pmname, mname, 534 infop->dthi_pfname, fname, 535 infop->dthi_pmname, mname, 536 infop->dthi_pfname, fname) < 0) 537 return (dt_set_errno(dtp, errno)); 538 539 } else { 540 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n", 541 infop->dthi_pmname, mname) < 0) 542 return (dt_set_errno(dtp, errno)); 543 } 544 545 return (0); 546 } 547 548 static int 549 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) 550 { 551 dt_header_info_t info; 552 const char *p; 553 int i; 554 555 if (pvp->pv_flags & DT_PROVIDER_IMPL) 556 return (0); 557 558 /* 559 * Count the instances of the '-' character since we'll need to double 560 * those up. 561 */ 562 p = pvp->pv_desc.dtvd_name; 563 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 564 p++; 565 566 info.dthi_dtp = dtp; 567 info.dthi_out = out; 568 info.dthi_empty = 0; 569 570 info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); 571 dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); 572 573 info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); 574 dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); 575 576 if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0) 577 return (dt_set_errno(dtp, errno)); 578 579 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 580 return (-1); /* dt_errno is set for us */ 581 if (fprintf(out, "\n\n") < 0) 582 return (dt_set_errno(dtp, errno)); 583 if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) 584 return (-1); /* dt_errno is set for us */ 585 586 if (fprintf(out, "\n#else\n\n") < 0) 587 return (dt_set_errno(dtp, errno)); 588 589 info.dthi_empty = 1; 590 591 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 592 return (-1); /* dt_errno is set for us */ 593 594 if (fprintf(out, "\n#endif\n\n") < 0) 595 return (dt_set_errno(dtp, errno)); 596 597 return (0); 598 } 599 600 int 601 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) 602 { 603 dt_provider_t *pvp; 604 char *mfname, *p; 605 606 if (fname != NULL) { 607 if ((p = strrchr(fname, '/')) != NULL) 608 fname = p + 1; 609 610 mfname = alloca(strlen(fname) + 1); 611 dt_header_fmt_macro(mfname, fname); 612 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", 613 mfname, mfname) < 0) 614 return (dt_set_errno(dtp, errno)); 615 } 616 617 if (fprintf(out, "#include <unistd.h>\n\n") < 0) 618 return (-1); 619 620 if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) 621 return (-1); 622 623 for (pvp = dt_list_next(&dtp->dt_provlist); 624 pvp != NULL; pvp = dt_list_next(pvp)) { 625 if (dt_header_provider(dtp, pvp, out) != 0) 626 return (-1); /* dt_errno is set for us */ 627 } 628 629 if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) 630 return (dt_set_errno(dtp, errno)); 631 632 if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) 633 return (dt_set_errno(dtp, errno)); 634 635 return (0); 636 }