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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <assert.h> 34 #include <ctype.h> 35 #if defined(sun) 36 #include <alloca.h> 37 #endif 38 39 #include <dt_impl.h> 40 #include <dt_program.h> 41 #include <dt_printf.h> 42 #include <dt_provider.h> 43 44 dtrace_prog_t * 45 dt_program_create(dtrace_hdl_t *dtp) 46 { 47 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); 48 49 if (pgp != NULL) 50 dt_list_append(&dtp->dt_programs, pgp); 51 else 52 (void) dt_set_errno(dtp, EDT_NOMEM); 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 default: 182 err = errno; 183 } 184 185 return (dt_set_errno(dtp, err)); 186 } 187 188 if (pip != NULL) 189 pip->dpi_matches += args.n_matched; 190 191 return (0); 192 } 193 194 static void 195 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) 196 { 197 edp->dted_refcnt++; 198 } 199 200 void 201 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 202 { 203 if (--edp->dted_refcnt > 0) 204 return; 205 206 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); 207 assert(edp->dted_action == NULL); 208 dt_free(dtp, edp); 209 } 210 211 dtrace_ecbdesc_t * 212 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 213 { 214 dtrace_ecbdesc_t *edp; 215 216 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { 217 (void) dt_set_errno(dtp, EDT_NOMEM); 218 return (NULL); 219 } 220 221 edp->dted_probe = *pdp; 222 dt_ecbdesc_hold(edp); 223 return (edp); 224 } 225 226 dtrace_stmtdesc_t * 227 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 228 { 229 dtrace_stmtdesc_t *sdp; 230 231 if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) 232 return (NULL); 233 234 dt_ecbdesc_hold(edp); 235 sdp->dtsd_ecbdesc = edp; 236 sdp->dtsd_descattr = _dtrace_defattr; 237 sdp->dtsd_stmtattr = _dtrace_defattr; 238 239 return (sdp); 240 } 241 242 dtrace_actdesc_t * 243 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 244 { 245 dtrace_actdesc_t *new; 246 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 247 248 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) 249 return (NULL); 250 251 if (sdp->dtsd_action_last != NULL) { 252 assert(sdp->dtsd_action != NULL); 253 assert(sdp->dtsd_action_last->dtad_next == NULL); 254 sdp->dtsd_action_last->dtad_next = new; 255 } else { 256 dtrace_actdesc_t *ap = edp->dted_action; 257 258 assert(sdp->dtsd_action == NULL); 259 sdp->dtsd_action = new; 260 261 while (ap != NULL && ap->dtad_next != NULL) 262 ap = ap->dtad_next; 263 264 if (ap == NULL) 265 edp->dted_action = new; 266 else 267 ap->dtad_next = new; 268 } 269 270 sdp->dtsd_action_last = new; 271 bzero(new, sizeof (dtrace_actdesc_t)); 272 new->dtad_uarg = (uintptr_t)sdp; 273 274 return (new); 275 } 276 277 int 278 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 279 { 280 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); 281 282 if (stp == NULL) 283 return (-1); /* errno is set for us */ 284 285 dt_list_append(&pgp->dp_stmts, stp); 286 stp->ds_desc = sdp; 287 288 return (0); 289 } 290 291 int 292 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 293 dtrace_stmt_f *func, void *data) 294 { 295 dt_stmt_t *stp, *next; 296 int status = 0; 297 298 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 299 next = dt_list_next(stp); 300 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 301 break; 302 } 303 304 return (status); 305 } 306 307 void 308 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 309 { 310 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 311 312 /* 313 * We need to remove any actions that we have on this ECB, and 314 * remove our hold on the ECB itself. 315 */ 316 if (sdp->dtsd_action != NULL) { 317 dtrace_actdesc_t *last = sdp->dtsd_action_last; 318 dtrace_actdesc_t *ap, *next; 319 320 assert(last != NULL); 321 322 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 323 if (ap == sdp->dtsd_action) 324 break; 325 326 if (ap->dtad_next == sdp->dtsd_action) 327 break; 328 } 329 330 assert(ap != NULL); 331 332 if (ap == edp->dted_action) 333 edp->dted_action = last->dtad_next; 334 else 335 ap->dtad_next = last->dtad_next; 336 337 /* 338 * We have now removed our action list from its ECB; we can 339 * safely destroy the list. 340 */ 341 last->dtad_next = NULL; 342 343 for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 344 assert(ap->dtad_uarg == (uintptr_t)sdp); 345 dt_difo_free(dtp, ap->dtad_difo); 346 next = ap->dtad_next; 347 dt_free(dtp, ap); 348 } 349 } 350 351 if (sdp->dtsd_fmtdata != NULL) 352 dt_printf_destroy(sdp->dtsd_fmtdata); 353 354 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); 355 dt_free(dtp, sdp); 356 } 357 358 typedef struct dt_header_info { 359 dtrace_hdl_t *dthi_dtp; /* consumer handle */ 360 FILE *dthi_out; /* output file */ 361 char *dthi_pmname; /* provider macro name */ 362 char *dthi_pfname; /* provider function name */ 363 int dthi_empty; /* should we generate empty macros */ 364 } dt_header_info_t; 365 366 static void 367 dt_header_fmt_macro(char *buf, const char *str) 368 { 369 for (;;) { 370 if (islower(*str)) { 371 *buf++ = *str++ + 'A' - 'a'; 372 } else if (*str == '-') { 373 *buf++ = '_'; 374 str++; 375 } else if (*str == '.') { 376 *buf++ = '_'; 377 str++; 378 } else if ((*buf++ = *str++) == '\0') { 379 break; 380 } 381 } 382 } 383 384 static void 385 dt_header_fmt_func(char *buf, const char *str) 386 { 387 for (;;) { 388 if (*str == '-') { 389 *buf++ = '_'; 390 *buf++ = '_'; 391 str++; 392 } else if ((*buf++ = *str++) == '\0') { 393 break; 394 } 395 } 396 } 397 398 /*ARGSUSED*/ 399 static int 400 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 401 { 402 dt_header_info_t *infop = data; 403 dtrace_hdl_t *dtp = infop->dthi_dtp; 404 dt_probe_t *prp = idp->di_data; 405 dt_node_t *dnp; 406 char buf[DT_TYPE_NAMELEN]; 407 char *fname; 408 const char *p; 409 int i; 410 411 p = prp->pr_name; 412 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 413 p++; 414 415 fname = alloca(strlen(prp->pr_name) + 1 + i); 416 dt_header_fmt_func(fname, prp->pr_name); 417 418 if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", 419 infop->dthi_pfname, fname) < 0) 420 return (dt_set_errno(dtp, errno)); 421 422 for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { 423 if (fprintf(infop->dthi_out, "%s", 424 ctf_type_name(dnp->dn_ctfp, dnp->dn_type, 425 buf, sizeof (buf))) < 0) 426 return (dt_set_errno(dtp, errno)); 427 428 if (i + 1 != prp->pr_nargc && 429 fprintf(infop->dthi_out, ", ") < 0) 430 return (dt_set_errno(dtp, errno)); 431 } 432 433 if (i == 0 && fprintf(infop->dthi_out, "void") < 0) 434 return (dt_set_errno(dtp, errno)); 435 436 if (fprintf(infop->dthi_out, ");\n") < 0) 437 return (dt_set_errno(dtp, errno)); 438 439 if (fprintf(infop->dthi_out, 440 "#ifndef\t__sparc\n" 441 "extern int __dtraceenabled_%s___%s(void);\n" 442 "#else\n" 443 "extern int __dtraceenabled_%s___%s(long);\n" 444 "#endif\n", 445 infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0) 446 return (dt_set_errno(dtp, errno)); 447 448 return (0); 449 } 450 451 /*ARGSUSED*/ 452 static int 453 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 454 { 455 dt_header_info_t *infop = data; 456 dtrace_hdl_t *dtp = infop->dthi_dtp; 457 dt_probe_t *prp = idp->di_data; 458 char *mname, *fname; 459 const char *p; 460 int i; 461 462 p = prp->pr_name; 463 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 464 p++; 465 466 mname = alloca(strlen(prp->pr_name) + 1); 467 dt_header_fmt_macro(mname, prp->pr_name); 468 469 fname = alloca(strlen(prp->pr_name) + 1 + i); 470 dt_header_fmt_func(fname, prp->pr_name); 471 472 if (fprintf(infop->dthi_out, "#define\t%s_%s(", 473 infop->dthi_pmname, mname) < 0) 474 return (dt_set_errno(dtp, errno)); 475 476 for (i = 0; i < prp->pr_nargc; i++) { 477 if (fprintf(infop->dthi_out, "arg%d", i) < 0) 478 return (dt_set_errno(dtp, errno)); 479 480 if (i + 1 != prp->pr_nargc && 481 fprintf(infop->dthi_out, ", ") < 0) 482 return (dt_set_errno(dtp, errno)); 483 } 484 485 if (!infop->dthi_empty) { 486 if (fprintf(infop->dthi_out, ") \\\n\t") < 0) 487 return (dt_set_errno(dtp, errno)); 488 489 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", 490 infop->dthi_pfname, fname) < 0) 491 return (dt_set_errno(dtp, errno)); 492 493 for (i = 0; i < prp->pr_nargc; i++) { 494 if (fprintf(infop->dthi_out, "arg%d", i) < 0) 495 return (dt_set_errno(dtp, errno)); 496 497 if (i + 1 != prp->pr_nargc && 498 fprintf(infop->dthi_out, ", ") < 0) 499 return (dt_set_errno(dtp, errno)); 500 } 501 } 502 503 if (fprintf(infop->dthi_out, ")\n") < 0) 504 return (dt_set_errno(dtp, errno)); 505 506 if (!infop->dthi_empty) { 507 if (fprintf(infop->dthi_out, 508 "#ifndef\t__sparc\n" 509 "#define\t%s_%s_ENABLED() \\\n" 510 "\t__dtraceenabled_%s___%s()\n" 511 "#else\n" 512 "#define\t%s_%s_ENABLED() \\\n" 513 "\t__dtraceenabled_%s___%s(0)\n" 514 "#endif\n", 515 infop->dthi_pmname, mname, 516 infop->dthi_pfname, fname, 517 infop->dthi_pmname, mname, 518 infop->dthi_pfname, fname) < 0) 519 return (dt_set_errno(dtp, errno)); 520 521 } else { 522 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n", 523 infop->dthi_pmname, mname) < 0) 524 return (dt_set_errno(dtp, errno)); 525 } 526 527 return (0); 528 } 529 530 static int 531 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) 532 { 533 dt_header_info_t info; 534 const char *p; 535 int i; 536 537 if (pvp->pv_flags & DT_PROVIDER_IMPL) 538 return (0); 539 540 /* 541 * Count the instances of the '-' character since we'll need to double 542 * those up. 543 */ 544 p = pvp->pv_desc.dtvd_name; 545 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 546 p++; 547 548 info.dthi_dtp = dtp; 549 info.dthi_out = out; 550 info.dthi_empty = 0; 551 552 info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); 553 dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); 554 555 info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); 556 dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); 557 558 if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0) 559 return (dt_set_errno(dtp, errno)); 560 561 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 562 return (-1); /* dt_errno is set for us */ 563 if (fprintf(out, "\n\n") < 0) 564 return (dt_set_errno(dtp, errno)); 565 if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) 566 return (-1); /* dt_errno is set for us */ 567 568 if (fprintf(out, "\n#else\n\n") < 0) 569 return (dt_set_errno(dtp, errno)); 570 571 info.dthi_empty = 1; 572 573 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 574 return (-1); /* dt_errno is set for us */ 575 576 if (fprintf(out, "\n#endif\n\n") < 0) 577 return (dt_set_errno(dtp, errno)); 578 579 return (0); 580 } 581 582 int 583 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) 584 { 585 dt_provider_t *pvp; 586 char *mfname, *p; 587 588 if (fname != NULL) { 589 if ((p = strrchr(fname, '/')) != NULL) 590 fname = p + 1; 591 592 mfname = alloca(strlen(fname) + 1); 593 dt_header_fmt_macro(mfname, fname); 594 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", 595 mfname, mfname) < 0) 596 return (dt_set_errno(dtp, errno)); 597 } 598 599 if (fprintf(out, "#include <unistd.h>\n\n") < 0) 600 return (-1); 601 602 if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) 603 return (-1); 604 605 for (pvp = dt_list_next(&dtp->dt_provlist); 606 pvp != NULL; pvp = dt_list_next(pvp)) { 607 if (dt_header_provider(dtp, pvp, out) != 0) 608 return (-1); /* dt_errno is set for us */ 609 } 610 611 if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) 612 return (dt_set_errno(dtp, errno)); 613 614 if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) 615 return (dt_set_errno(dtp, errno)); 616 617 return (0); 618 } 619