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