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