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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <unistd.h> 31 #include <strings.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <assert.h> 35 #include <ctype.h> 36 #include <alloca.h> 37 38 #include <dt_impl.h> 39 #include <dt_program.h> 40 #include <dt_printf.h> 41 #include <dt_provider.h> 42 43 dtrace_prog_t * 44 dt_program_create(dtrace_hdl_t *dtp) 45 { 46 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); 47 48 if (pgp != NULL) 49 dt_list_append(&dtp->dt_programs, pgp); 50 else 51 (void) dt_set_errno(dtp, EDT_NOMEM); 52 53 return (pgp); 54 } 55 56 void 57 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) 58 { 59 dt_stmt_t *stp, *next; 60 uint_t i; 61 62 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 63 next = dt_list_next(stp); 64 dtrace_stmt_destroy(dtp, stp->ds_desc); 65 dt_free(dtp, stp); 66 } 67 68 for (i = 0; i < pgp->dp_xrefslen; i++) 69 dt_free(dtp, pgp->dp_xrefs[i]); 70 71 dt_free(dtp, pgp->dp_xrefs); 72 dt_list_delete(&dtp->dt_programs, pgp); 73 dt_free(dtp, pgp); 74 } 75 76 /*ARGSUSED*/ 77 void 78 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 79 dtrace_proginfo_t *pip) 80 { 81 dt_stmt_t *stp; 82 dtrace_actdesc_t *ap; 83 dtrace_ecbdesc_t *last = NULL; 84 85 if (pip == NULL) 86 return; 87 88 bzero(pip, sizeof (dtrace_proginfo_t)); 89 90 if (dt_list_next(&pgp->dp_stmts) != NULL) { 91 pip->dpi_descattr = _dtrace_maxattr; 92 pip->dpi_stmtattr = _dtrace_maxattr; 93 } else { 94 pip->dpi_descattr = _dtrace_defattr; 95 pip->dpi_stmtattr = _dtrace_defattr; 96 } 97 98 for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { 99 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; 100 101 if (edp == last) 102 continue; 103 last = edp; 104 105 pip->dpi_descattr = 106 dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); 107 108 pip->dpi_stmtattr = 109 dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); 110 111 /* 112 * If there aren't any actions, account for the fact that 113 * recording the epid will generate a record. 114 */ 115 if (edp->dted_action == NULL) 116 pip->dpi_recgens++; 117 118 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 119 if (ap->dtad_kind == DTRACEACT_SPECULATE) { 120 pip->dpi_speculations++; 121 continue; 122 } 123 124 if (DTRACEACT_ISAGG(ap->dtad_kind)) { 125 pip->dpi_recgens -= ap->dtad_arg; 126 pip->dpi_aggregates++; 127 continue; 128 } 129 130 if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) 131 continue; 132 133 if (ap->dtad_kind == DTRACEACT_DIFEXPR && 134 ap->dtad_difo->dtdo_rtype.dtdt_kind == 135 DIF_TYPE_CTF && 136 ap->dtad_difo->dtdo_rtype.dtdt_size == 0) 137 continue; 138 139 pip->dpi_recgens++; 140 } 141 } 142 } 143 144 int 145 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 146 dtrace_proginfo_t *pip) 147 { 148 void *dof; 149 int n, err; 150 151 dtrace_program_info(dtp, pgp, pip); 152 153 if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) 154 return (-1); 155 156 n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 157 dtrace_dof_destroy(dtp, dof); 158 159 if (n == -1) { 160 switch (errno) { 161 case EINVAL: 162 err = EDT_DIFINVAL; 163 break; 164 case EFAULT: 165 err = EDT_DIFFAULT; 166 break; 167 case E2BIG: 168 err = EDT_DIFSIZE; 169 break; 170 default: 171 err = errno; 172 } 173 174 return (dt_set_errno(dtp, err)); 175 } 176 177 if (pip != NULL) 178 pip->dpi_matches += n; 179 180 return (0); 181 } 182 183 static void 184 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) 185 { 186 edp->dted_refcnt++; 187 } 188 189 void 190 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 191 { 192 if (--edp->dted_refcnt > 0) 193 return; 194 195 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); 196 assert(edp->dted_action == NULL); 197 dt_free(dtp, edp); 198 } 199 200 dtrace_ecbdesc_t * 201 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 202 { 203 dtrace_ecbdesc_t *edp; 204 205 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { 206 (void) dt_set_errno(dtp, EDT_NOMEM); 207 return (NULL); 208 } 209 210 edp->dted_probe = *pdp; 211 dt_ecbdesc_hold(edp); 212 return (edp); 213 } 214 215 dtrace_stmtdesc_t * 216 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 217 { 218 dtrace_stmtdesc_t *sdp; 219 220 if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) 221 return (NULL); 222 223 dt_ecbdesc_hold(edp); 224 sdp->dtsd_ecbdesc = edp; 225 sdp->dtsd_descattr = _dtrace_defattr; 226 sdp->dtsd_stmtattr = _dtrace_defattr; 227 228 return (sdp); 229 } 230 231 dtrace_actdesc_t * 232 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 233 { 234 dtrace_actdesc_t *new; 235 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 236 237 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) 238 return (NULL); 239 240 if (sdp->dtsd_action_last != NULL) { 241 assert(sdp->dtsd_action != NULL); 242 assert(sdp->dtsd_action_last->dtad_next == NULL); 243 sdp->dtsd_action_last->dtad_next = new; 244 } else { 245 dtrace_actdesc_t *ap = edp->dted_action; 246 247 assert(sdp->dtsd_action == NULL); 248 sdp->dtsd_action = new; 249 250 while (ap != NULL && ap->dtad_next != NULL) 251 ap = ap->dtad_next; 252 253 if (ap == NULL) 254 edp->dted_action = new; 255 else 256 ap->dtad_next = new; 257 } 258 259 sdp->dtsd_action_last = new; 260 bzero(new, sizeof (dtrace_actdesc_t)); 261 new->dtad_uarg = (uintptr_t)sdp; 262 263 return (new); 264 } 265 266 int 267 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 268 { 269 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); 270 271 if (stp == NULL) 272 return (-1); /* errno is set for us */ 273 274 dt_list_append(&pgp->dp_stmts, stp); 275 stp->ds_desc = sdp; 276 277 return (0); 278 } 279 280 int 281 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 282 dtrace_stmt_f *func, void *data) 283 { 284 dt_stmt_t *stp, *next; 285 int status = 0; 286 287 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 288 next = dt_list_next(stp); 289 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 290 break; 291 } 292 293 return (status); 294 } 295 296 void 297 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 298 { 299 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 300 301 /* 302 * We need to remove any actions that we have on this ECB, and 303 * remove our hold on the ECB itself. 304 */ 305 if (sdp->dtsd_action != NULL) { 306 dtrace_actdesc_t *last = sdp->dtsd_action_last; 307 dtrace_actdesc_t *ap, *next; 308 309 assert(last != NULL); 310 311 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 312 if (ap == sdp->dtsd_action) 313 break; 314 315 if (ap->dtad_next == sdp->dtsd_action) 316 break; 317 } 318 319 assert(ap != NULL); 320 321 if (ap == edp->dted_action) 322 edp->dted_action = last->dtad_next; 323 else 324 ap->dtad_next = last->dtad_next; 325 326 /* 327 * We have now removed our action list from its ECB; we can 328 * safely destroy the list. 329 */ 330 last->dtad_next = NULL; 331 332 for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 333 assert(ap->dtad_uarg == (uintptr_t)sdp); 334 dt_difo_free(dtp, ap->dtad_difo); 335 next = ap->dtad_next; 336 dt_free(dtp, ap); 337 } 338 } 339 340 if (sdp->dtsd_fmtdata != NULL) 341 dt_printf_destroy(sdp->dtsd_fmtdata); 342 343 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); 344 dt_free(dtp, sdp); 345 } 346 347 typedef struct dt_header_info { 348 dtrace_hdl_t *dthi_dtp; /* consumer handle */ 349 FILE *dthi_out; /* output file */ 350 char *dthi_pmname; /* provider macro name */ 351 char *dthi_pfname; /* provider function name */ 352 } dt_header_info_t; 353 354 355 static void 356 dt_header_fmt_macro(char *buf, const char *str) 357 { 358 for (;;) { 359 if (islower(*str)) { 360 *buf++ = *str++ + 'A' - 'a'; 361 } else if (*str == '-') { 362 *buf++ = '_'; 363 str++; 364 } else if (*str == '.') { 365 *buf++ = '_'; 366 str++; 367 } else if ((*buf++ = *str++) == '\0') { 368 break; 369 } 370 } 371 } 372 373 static void 374 dt_header_fmt_func(char *buf, const char *str) 375 { 376 for (;;) { 377 if (*str == '-') { 378 *buf++ = '_'; 379 *buf++ = '_'; 380 str++; 381 } else if ((*buf++ = *str++) == '\0') { 382 break; 383 } 384 } 385 } 386 387 /*ARGSUSED*/ 388 static int 389 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 390 { 391 dt_header_info_t *infop = data; 392 dtrace_hdl_t *dtp = infop->dthi_dtp; 393 dt_probe_t *prp = idp->di_data; 394 dt_node_t *dnp; 395 char buf[DT_TYPE_NAMELEN]; 396 char *fname; 397 const char *p; 398 int i; 399 400 p = prp->pr_name; 401 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 402 p++; 403 404 fname = alloca(strlen(prp->pr_name) + 1 + i); 405 dt_header_fmt_func(fname, prp->pr_name); 406 407 if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", 408 infop->dthi_pfname, fname) < 0) 409 return (dt_set_errno(dtp, errno)); 410 411 for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { 412 if (fprintf(infop->dthi_out, "%s", 413 ctf_type_name(dnp->dn_ctfp, dnp->dn_type, 414 buf, sizeof (buf))) < 0) 415 return (dt_set_errno(dtp, errno)); 416 417 if (i + 1 != prp->pr_nargc && 418 fprintf(infop->dthi_out, ", ") < 0) 419 return (dt_set_errno(dtp, errno)); 420 } 421 422 if (i == 0 && fprintf(infop->dthi_out, "void") < 0) 423 return (dt_set_errno(dtp, errno)); 424 425 if (fprintf(infop->dthi_out, ");\n") < 0) 426 return (dt_set_errno(dtp, errno)); 427 428 return (0); 429 } 430 431 /*ARGSUSED*/ 432 static int 433 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 434 { 435 dt_header_info_t *infop = data; 436 dtrace_hdl_t *dtp = infop->dthi_dtp; 437 dt_probe_t *prp = idp->di_data; 438 char *mname, *fname; 439 const char *p; 440 int i; 441 442 p = prp->pr_name; 443 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 444 p++; 445 446 mname = alloca(strlen(prp->pr_name) + 1); 447 dt_header_fmt_macro(mname, prp->pr_name); 448 449 fname = alloca(strlen(prp->pr_name) + 1 + i); 450 dt_header_fmt_func(fname, prp->pr_name); 451 452 if (fprintf(infop->dthi_out, "#define\t%s_%s(", 453 infop->dthi_pmname, mname) < 0) 454 return (dt_set_errno(dtp, errno)); 455 456 for (i = 0; i < prp->pr_nargc; i++) { 457 if (fprintf(infop->dthi_out, "arg%d", i) < 0) 458 return (dt_set_errno(dtp, errno)); 459 460 if (i + 1 != prp->pr_nargc && 461 fprintf(infop->dthi_out, ", ") < 0) 462 return (dt_set_errno(dtp, errno)); 463 } 464 465 if (fprintf(infop->dthi_out, ") \\\n\t") < 0) 466 return (dt_set_errno(dtp, errno)); 467 468 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", 469 infop->dthi_pfname, fname) < 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 (fprintf(infop->dthi_out, ")\n") < 0) 482 return (dt_set_errno(dtp, errno)); 483 484 return (0); 485 } 486 487 static int 488 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) 489 { 490 dt_header_info_t info; 491 const char *p; 492 int i; 493 494 if (pvp->pv_flags & DT_PROVIDER_IMPL) 495 return (0); 496 497 p = pvp->pv_desc.dtvd_name; 498 for (i = 0; (p = strchr(p, '-')) != NULL; i++) 499 p++; 500 501 info.dthi_dtp = dtp; 502 info.dthi_out = out; 503 504 info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); 505 dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); 506 507 info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); 508 dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); 509 510 511 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 512 return (-1); /* dt_errno is set for us */ 513 if (fprintf(out, "\n\n") < 0) 514 return (dt_set_errno(dtp, errno)); 515 if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) 516 return (-1); /* dt_errno is set for us */ 517 518 return (0); 519 } 520 521 int 522 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) 523 { 524 dt_provider_t *pvp; 525 char *mfname, *p; 526 527 if (fname != NULL) { 528 if ((p = strrchr(fname, '/')) != NULL) 529 fname = p + 1; 530 531 mfname = alloca(strlen(fname) + 1); 532 dt_header_fmt_macro(mfname, fname); 533 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", 534 mfname, mfname) < 0) 535 return (dt_set_errno(dtp, errno)); 536 } 537 538 if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) 539 return (-1); 540 541 for (pvp = dt_list_next(&dtp->dt_provlist); 542 pvp != NULL; pvp = dt_list_next(pvp)) { 543 if (dt_header_provider(dtp, pvp, out) != 0) 544 return (-1); /* dt_errno is set for us */ 545 } 546 547 if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) 548 return (dt_set_errno(dtp, errno)); 549 550 if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) 551 return (dt_set_errno(dtp, errno)); 552 553 return (0); 554 } 555