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.
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.
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]
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011 by Delphix. All rights reserved.
38 #include <dt_program.h>
39 #include <dt_printf.h>
40 #include <dt_provider.h>
43 dt_program_create(dtrace_hdl_t *dtp)
45 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
48 dt_list_append(&dtp->dt_programs, pgp);
50 (void) dt_set_errno(dtp, EDT_NOMEM);
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.
59 pgp->dp_dofversion = DOF_VERSION_1;
65 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
67 dt_stmt_t *stp, *next;
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);
76 for (i = 0; i < pgp->dp_xrefslen; i++)
77 dt_free(dtp, pgp->dp_xrefs[i]);
79 dt_free(dtp, pgp->dp_xrefs);
80 dt_list_delete(&dtp->dt_programs, pgp);
86 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
87 dtrace_proginfo_t *pip)
91 dtrace_ecbdesc_t *last = NULL;
96 bzero(pip, sizeof (dtrace_proginfo_t));
98 if (dt_list_next(&pgp->dp_stmts) != NULL) {
99 pip->dpi_descattr = _dtrace_maxattr;
100 pip->dpi_stmtattr = _dtrace_maxattr;
102 pip->dpi_descattr = _dtrace_defattr;
103 pip->dpi_stmtattr = _dtrace_defattr;
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;
114 dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
117 dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
120 * If there aren't any actions, account for the fact that
121 * recording the epid will generate a record.
123 if (edp->dted_action == NULL)
126 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
127 if (ap->dtad_kind == DTRACEACT_SPECULATE) {
128 pip->dpi_speculations++;
132 if (DTRACEACT_ISAGG(ap->dtad_kind)) {
133 pip->dpi_recgens -= ap->dtad_arg;
134 pip->dpi_aggregates++;
138 if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
141 if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
142 ap->dtad_difo->dtdo_rtype.dtdt_kind ==
144 ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
153 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
154 dtrace_proginfo_t *pip)
156 dtrace_enable_io_t args;
160 dtrace_program_info(dtp, pgp, pip);
162 if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
167 n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
168 dtrace_dof_destroy(dtp, dof);
182 err = EDT_ENABLING_ERR;
188 return (dt_set_errno(dtp, err));
192 pip->dpi_matches += args.n_matched;
198 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
204 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
206 if (--edp->dted_refcnt > 0)
209 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
210 assert(edp->dted_action == NULL);
215 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
217 dtrace_ecbdesc_t *edp;
219 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
220 (void) dt_set_errno(dtp, EDT_NOMEM);
224 edp->dted_probe = *pdp;
225 dt_ecbdesc_hold(edp);
230 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
232 dtrace_stmtdesc_t *sdp;
234 if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
237 dt_ecbdesc_hold(edp);
238 sdp->dtsd_ecbdesc = edp;
239 sdp->dtsd_descattr = _dtrace_defattr;
240 sdp->dtsd_stmtattr = _dtrace_defattr;
246 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
248 dtrace_actdesc_t *new;
249 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
251 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
254 if (sdp->dtsd_action_last != NULL) {
255 assert(sdp->dtsd_action != NULL);
256 assert(sdp->dtsd_action_last->dtad_next == NULL);
257 sdp->dtsd_action_last->dtad_next = new;
259 dtrace_actdesc_t *ap = edp->dted_action;
261 assert(sdp->dtsd_action == NULL);
262 sdp->dtsd_action = new;
264 while (ap != NULL && ap->dtad_next != NULL)
268 edp->dted_action = new;
273 sdp->dtsd_action_last = new;
274 bzero(new, sizeof (dtrace_actdesc_t));
275 new->dtad_uarg = (uintptr_t)sdp;
281 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
283 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
286 return (-1); /* errno is set for us */
288 dt_list_append(&pgp->dp_stmts, stp);
295 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
296 dtrace_stmt_f *func, void *data)
298 dt_stmt_t *stp, *next;
301 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
302 next = dt_list_next(stp);
303 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
311 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
313 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
316 * We need to remove any actions that we have on this ECB, and
317 * remove our hold on the ECB itself.
319 if (sdp->dtsd_action != NULL) {
320 dtrace_actdesc_t *last = sdp->dtsd_action_last;
321 dtrace_actdesc_t *ap, *next;
323 assert(last != NULL);
325 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
326 if (ap == sdp->dtsd_action)
329 if (ap->dtad_next == sdp->dtsd_action)
335 if (ap == edp->dted_action)
336 edp->dted_action = last->dtad_next;
338 ap->dtad_next = last->dtad_next;
341 * We have now removed our action list from its ECB; we can
342 * safely destroy the list.
344 last->dtad_next = NULL;
346 for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
347 assert(ap->dtad_uarg == (uintptr_t)sdp);
348 dt_difo_free(dtp, ap->dtad_difo);
349 next = ap->dtad_next;
354 if (sdp->dtsd_fmtdata != NULL)
355 dt_printf_destroy(sdp->dtsd_fmtdata);
356 dt_free(dtp, sdp->dtsd_strdata);
358 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
362 typedef struct dt_header_info {
363 dtrace_hdl_t *dthi_dtp; /* consumer handle */
364 FILE *dthi_out; /* output file */
365 char *dthi_pmname; /* provider macro name */
366 char *dthi_pfname; /* provider function name */
367 int dthi_empty; /* should we generate empty macros */
371 dt_header_fmt_macro(char *buf, const char *str)
375 *buf++ = *str++ + 'A' - 'a';
376 } else if (*str == '-') {
379 } else if (*str == '.') {
382 } else if ((*buf++ = *str++) == '\0') {
389 dt_header_fmt_func(char *buf, const char *str)
396 } else if ((*buf++ = *str++) == '\0') {
404 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
406 dt_header_info_t *infop = data;
407 dtrace_hdl_t *dtp = infop->dthi_dtp;
408 dt_probe_t *prp = idp->di_data;
410 char buf[DT_TYPE_NAMELEN];
416 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
419 fname = alloca(strlen(prp->pr_name) + 1 + i);
420 dt_header_fmt_func(fname, prp->pr_name);
422 if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
423 infop->dthi_pfname, fname) < 0)
424 return (dt_set_errno(dtp, errno));
426 for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
427 if (fprintf(infop->dthi_out, "%s",
428 ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
429 buf, sizeof (buf))) < 0)
430 return (dt_set_errno(dtp, errno));
432 if (i + 1 != prp->pr_nargc &&
433 fprintf(infop->dthi_out, ", ") < 0)
434 return (dt_set_errno(dtp, errno));
437 if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
438 return (dt_set_errno(dtp, errno));
440 if (fprintf(infop->dthi_out, ");\n") < 0)
441 return (dt_set_errno(dtp, errno));
443 if (fprintf(infop->dthi_out,
445 "extern int __dtraceenabled_%s___%s(void);\n"
447 "extern int __dtraceenabled_%s___%s(long);\n"
449 infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
450 return (dt_set_errno(dtp, errno));
457 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
459 dt_header_info_t *infop = data;
460 dtrace_hdl_t *dtp = infop->dthi_dtp;
461 dt_probe_t *prp = idp->di_data;
467 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
470 mname = alloca(strlen(prp->pr_name) + 1);
471 dt_header_fmt_macro(mname, prp->pr_name);
473 fname = alloca(strlen(prp->pr_name) + 1 + i);
474 dt_header_fmt_func(fname, prp->pr_name);
476 if (fprintf(infop->dthi_out, "#define\t%s_%s(",
477 infop->dthi_pmname, mname) < 0)
478 return (dt_set_errno(dtp, errno));
480 for (i = 0; i < prp->pr_nargc; i++) {
481 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
482 return (dt_set_errno(dtp, errno));
484 if (i + 1 != prp->pr_nargc &&
485 fprintf(infop->dthi_out, ", ") < 0)
486 return (dt_set_errno(dtp, errno));
489 if (!infop->dthi_empty) {
490 if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
491 return (dt_set_errno(dtp, errno));
493 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
494 infop->dthi_pfname, fname) < 0)
495 return (dt_set_errno(dtp, errno));
497 for (i = 0; i < prp->pr_nargc; i++) {
498 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
499 return (dt_set_errno(dtp, errno));
501 if (i + 1 != prp->pr_nargc &&
502 fprintf(infop->dthi_out, ", ") < 0)
503 return (dt_set_errno(dtp, errno));
507 if (fprintf(infop->dthi_out, ")\n") < 0)
508 return (dt_set_errno(dtp, errno));
510 if (!infop->dthi_empty) {
511 if (fprintf(infop->dthi_out,
513 "#define\t%s_%s_ENABLED() \\\n"
514 "\t__dtraceenabled_%s___%s()\n"
516 "#define\t%s_%s_ENABLED() \\\n"
517 "\t__dtraceenabled_%s___%s(0)\n"
519 infop->dthi_pmname, mname,
520 infop->dthi_pfname, fname,
521 infop->dthi_pmname, mname,
522 infop->dthi_pfname, fname) < 0)
523 return (dt_set_errno(dtp, errno));
526 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
527 infop->dthi_pmname, mname) < 0)
528 return (dt_set_errno(dtp, errno));
535 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
537 dt_header_info_t info;
541 if (pvp->pv_flags & DT_PROVIDER_IMPL)
545 * Count the instances of the '-' character since we'll need to double
548 p = pvp->pv_desc.dtvd_name;
549 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
556 info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
557 dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
559 info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
560 dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
563 if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
564 return (dt_set_errno(dtp, errno));
566 if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
567 return (dt_set_errno(dtp, errno));
569 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
570 return (-1); /* dt_errno is set for us */
571 if (fprintf(out, "\n\n") < 0)
572 return (dt_set_errno(dtp, errno));
573 if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
574 return (-1); /* dt_errno is set for us */
576 if (fprintf(out, "\n#else\n\n") < 0)
577 return (dt_set_errno(dtp, errno));
581 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
582 return (-1); /* dt_errno is set for us */
584 if (fprintf(out, "\n#endif\n\n") < 0)
585 return (dt_set_errno(dtp, errno));
591 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
597 if ((p = strrchr(fname, '/')) != NULL)
600 mfname = alloca(strlen(fname) + 1);
601 dt_header_fmt_macro(mfname, fname);
602 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
604 return (dt_set_errno(dtp, errno));
607 if (fprintf(out, "#include <unistd.h>\n\n") < 0)
610 if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
613 for (pvp = dt_list_next(&dtp->dt_provlist);
614 pvp != NULL; pvp = dt_list_next(pvp)) {
615 if (dt_header_provider(dtp, pvp, out) != 0)
616 return (-1); /* dt_errno is set for us */
619 if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
620 return (dt_set_errno(dtp, errno));
622 if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
623 return (dt_set_errno(dtp, errno));