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