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