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