diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/ExtPacks/VBoxDTrace/onnv/lib/libdtrace/common/dt_program.c | 622 |
1 files changed, 622 insertions, 0 deletions
diff --git a/src/VBox/ExtPacks/VBoxDTrace/onnv/lib/libdtrace/common/dt_program.c b/src/VBox/ExtPacks/VBoxDTrace/onnv/lib/libdtrace/common/dt_program.c new file mode 100644 index 00000000..33e5a8eb --- /dev/null +++ b/src/VBox/ExtPacks/VBoxDTrace/onnv/lib/libdtrace/common/dt_program.c @@ -0,0 +1,622 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef VBOX +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <ctype.h> +#include <alloca.h> +#else +# include <ctype.h> +#endif + +#include <dt_impl.h> +#include <dt_program.h> +#include <dt_printf.h> +#include <dt_provider.h> + +dtrace_prog_t * +dt_program_create(dtrace_hdl_t *dtp) +{ + dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); + + if (pgp != NULL) { + dt_list_append(&dtp->dt_programs, pgp); + } else { + (void) dt_set_errno(dtp, EDT_NOMEM); + return (NULL); + } + + /* + * By default, programs start with DOF version 1 so that output files + * containing DOF are backward compatible. If a program requires new + * DOF features, the version is increased as needed. + */ + pgp->dp_dofversion = DOF_VERSION_1; + + return (pgp); +} + +void +dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) +{ + dt_stmt_t *stp, *next; + uint_t i; + + for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { + next = dt_list_next(stp); + dtrace_stmt_destroy(dtp, stp->ds_desc); + dt_free(dtp, stp); + } + + for (i = 0; i < pgp->dp_xrefslen; i++) + dt_free(dtp, pgp->dp_xrefs[i]); + + dt_free(dtp, pgp->dp_xrefs); + dt_list_delete(&dtp->dt_programs, pgp); + dt_free(dtp, pgp); +} + +/*ARGSUSED*/ +void +dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, + dtrace_proginfo_t *pip) +{ + dt_stmt_t *stp; + dtrace_actdesc_t *ap; + dtrace_ecbdesc_t *last = NULL; + RT_NOREF1(dtp); + + if (pip == NULL) + return; + + bzero(pip, sizeof (dtrace_proginfo_t)); + + if (dt_list_next(&pgp->dp_stmts) != NULL) { + pip->dpi_descattr = _dtrace_maxattr; + pip->dpi_stmtattr = _dtrace_maxattr; + } else { + pip->dpi_descattr = _dtrace_defattr; + pip->dpi_stmtattr = _dtrace_defattr; + } + + for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { + dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; + + if (edp == last) + continue; + last = edp; + + pip->dpi_descattr = + dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); + + pip->dpi_stmtattr = + dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); + + /* + * If there aren't any actions, account for the fact that + * recording the epid will generate a record. + */ + if (edp->dted_action == NULL) + pip->dpi_recgens++; + + for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { + if (ap->dtad_kind == DTRACEACT_SPECULATE) { + pip->dpi_speculations++; + continue; + } + + if (DTRACEACT_ISAGG(ap->dtad_kind)) { + pip->dpi_recgens -= ap->dtad_arg; + pip->dpi_aggregates++; + continue; + } + + if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) + continue; + + if (ap->dtad_kind == DTRACEACT_DIFEXPR && + ap->dtad_difo->dtdo_rtype.dtdt_kind == + DIF_TYPE_CTF && + ap->dtad_difo->dtdo_rtype.dtdt_size == 0) + continue; + + pip->dpi_recgens++; + } + } +} + +int +dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, + dtrace_proginfo_t *pip) +{ + void *dof; + int n, err; + + dtrace_program_info(dtp, pgp, pip); + + if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) + return (-1); + + n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); + dtrace_dof_destroy(dtp, dof); + + if (n == -1) { + switch (errno) { + case EINVAL: + err = EDT_DIFINVAL; + break; + case EFAULT: + err = EDT_DIFFAULT; + break; + case E2BIG: + err = EDT_DIFSIZE; + break; + case EBUSY: + err = EDT_ENABLING_ERR; + break; + default: + err = errno; + } + + return (dt_set_errno(dtp, err)); + } + + if (pip != NULL) + pip->dpi_matches += n; + + return (0); +} + +static void +dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) +{ + edp->dted_refcnt++; +} + +void +dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) +{ + if (--edp->dted_refcnt > 0) + return; + + dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); + assert(edp->dted_action == NULL); + dt_free(dtp, edp); +} + +dtrace_ecbdesc_t * +dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) +{ + dtrace_ecbdesc_t *edp; + + if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { + (void) dt_set_errno(dtp, EDT_NOMEM); + return (NULL); + } + + edp->dted_probe = *pdp; + dt_ecbdesc_hold(edp); + return (edp); +} + +dtrace_stmtdesc_t * +dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) +{ + dtrace_stmtdesc_t *sdp; + + if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) + return (NULL); + + dt_ecbdesc_hold(edp); + sdp->dtsd_ecbdesc = edp; + sdp->dtsd_descattr = _dtrace_defattr; + sdp->dtsd_stmtattr = _dtrace_defattr; + + return (sdp); +} + +dtrace_actdesc_t * +dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) +{ + dtrace_actdesc_t *new; + dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; + + if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) + return (NULL); + + if (sdp->dtsd_action_last != NULL) { + assert(sdp->dtsd_action != NULL); + assert(sdp->dtsd_action_last->dtad_next == NULL); + sdp->dtsd_action_last->dtad_next = new; + } else { + dtrace_actdesc_t *ap = edp->dted_action; + + assert(sdp->dtsd_action == NULL); + sdp->dtsd_action = new; + + while (ap != NULL && ap->dtad_next != NULL) + ap = ap->dtad_next; + + if (ap == NULL) + edp->dted_action = new; + else + ap->dtad_next = new; + } + + sdp->dtsd_action_last = new; + bzero(new, sizeof (dtrace_actdesc_t)); + new->dtad_uarg = (uintptr_t)sdp; + + return (new); +} + +int +dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) +{ + dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); + + if (stp == NULL) + return (-1); /* errno is set for us */ + + dt_list_append(&pgp->dp_stmts, stp); + stp->ds_desc = sdp; + + return (0); +} + +int +dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, + dtrace_stmt_f *func, void *data) +{ + dt_stmt_t *stp, *next; + int status = 0; + + for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { + next = dt_list_next(stp); + if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) + break; + } + + return (status); +} + +void +dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) +{ + dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; + + /* + * We need to remove any actions that we have on this ECB, and + * remove our hold on the ECB itself. + */ + if (sdp->dtsd_action != NULL) { + dtrace_actdesc_t *last = sdp->dtsd_action_last; + dtrace_actdesc_t *ap, *next; + + assert(last != NULL); + + for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { + if (ap == sdp->dtsd_action) + break; + + if (ap->dtad_next == sdp->dtsd_action) + break; + } + + assert(ap != NULL); + + if (ap == edp->dted_action) + edp->dted_action = last->dtad_next; + else + ap->dtad_next = last->dtad_next; + + /* + * We have now removed our action list from its ECB; we can + * safely destroy the list. + */ + last->dtad_next = NULL; + + for (ap = sdp->dtsd_action; ap != NULL; ap = next) { + assert(ap->dtad_uarg == (uintptr_t)sdp); + dt_difo_free(dtp, ap->dtad_difo); + next = ap->dtad_next; + dt_free(dtp, ap); + } + } + + if (sdp->dtsd_fmtdata != NULL) + dt_printf_destroy(sdp->dtsd_fmtdata); + + dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); + dt_free(dtp, sdp); +} + +typedef struct dt_header_info { + dtrace_hdl_t *dthi_dtp; /* consumer handle */ + FILE *dthi_out; /* output file */ + char *dthi_pmname; /* provider macro name */ + char *dthi_pfname; /* provider function name */ + int dthi_empty; /* should we generate empty macros */ +} dt_header_info_t; + +static void +dt_header_fmt_macro(char *buf, const char *str) +{ + for (;;) { + if (islower(*str)) { + *buf++ = *str++ + 'A' - 'a'; + } else if (*str == '-') { + *buf++ = '_'; + str++; + } else if (*str == '.') { + *buf++ = '_'; + str++; + } else if ((*buf++ = *str++) == '\0') { + break; + } + } +} + +static void +dt_header_fmt_func(char *buf, const char *str) +{ + for (;;) { + if (*str == '-') { + *buf++ = '_'; + *buf++ = '_'; + str++; + } else if ((*buf++ = *str++) == '\0') { + break; + } + } +} + +/*ARGSUSED*/ +static int +dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) +{ + dt_header_info_t *infop = data; + dtrace_hdl_t *dtp = infop->dthi_dtp; + dt_probe_t *prp = idp->di_data; + dt_node_t *dnp; + char buf[DT_TYPE_NAMELEN]; + char *fname; + const char *p; + int i; + RT_NOREF1(dhp); + + p = prp->pr_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + fname = alloca(strlen(prp->pr_name) + 1 + i); + dt_header_fmt_func(fname, prp->pr_name); + + if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { + if (fprintf(infop->dthi_out, "%s", + ctf_type_name(dnp->dn_ctfp, dnp->dn_type, + buf, sizeof (buf))) < 0) + return (dt_set_errno(dtp, errno)); + + if ((uint_t)i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + + if (i == 0 && fprintf(infop->dthi_out, "void") < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, ");\n") < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, + "#ifndef\t__sparc\n" + "extern int __dtraceenabled_%s___%s(void);\n" + "#else\n" + "extern int __dtraceenabled_%s___%s(long);\n" + "#endif\n", + infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} + +/*ARGSUSED*/ +static int +dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) +{ + dt_header_info_t *infop = data; + dtrace_hdl_t *dtp = infop->dthi_dtp; + dt_probe_t *prp = idp->di_data; + char *mname, *fname; + const char *p; + VBDTTYPE(uint_t,int) i; + RT_NOREF1(dhp); + + p = prp->pr_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + mname = alloca(strlen(prp->pr_name) + 1); + dt_header_fmt_macro(mname, prp->pr_name); + + fname = alloca(strlen(prp->pr_name) + 1 + i); + dt_header_fmt_func(fname, prp->pr_name); + + if (fprintf(infop->dthi_out, "#define\t%s_%s(", + infop->dthi_pmname, mname) < 0) + return (dt_set_errno(dtp, errno)); + + for (i = 0; i < prp->pr_nargc; i++) { + if (fprintf(infop->dthi_out, "arg%d", i) < 0) + return (dt_set_errno(dtp, errno)); + + if (i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + + if (!infop->dthi_empty) { + if (fprintf(infop->dthi_out, ") \\\n\t") < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + for (i = 0; i < prp->pr_nargc; i++) { + if (fprintf(infop->dthi_out, "arg%d", i) < 0) + return (dt_set_errno(dtp, errno)); + + if (i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + } + + if (fprintf(infop->dthi_out, ")\n") < 0) + return (dt_set_errno(dtp, errno)); + + if (!infop->dthi_empty) { + if (fprintf(infop->dthi_out, + "#ifndef\t__sparc\n" + "#define\t%s_%s_ENABLED() \\\n" + "\t__dtraceenabled_%s___%s()\n" + "#else\n" + "#define\t%s_%s_ENABLED() \\\n" + "\t__dtraceenabled_%s___%s(0)\n" + "#endif\n", + infop->dthi_pmname, mname, + infop->dthi_pfname, fname, + infop->dthi_pmname, mname, + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + } else { + if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n", + infop->dthi_pmname, mname) < 0) + return (dt_set_errno(dtp, errno)); + } + + return (0); +} + +static int +dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) +{ + dt_header_info_t info; + const char *p; + int i; + + if (pvp->pv_flags & DT_PROVIDER_IMPL) + return (0); + + /* + * Count the instances of the '-' character since we'll need to double + * those up. + */ + p = pvp->pv_desc.dtvd_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + info.dthi_dtp = dtp; + info.dthi_out = out; + info.dthi_empty = 0; + + info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); + dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); + + info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); + dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); + + if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0) + return (dt_set_errno(dtp, errno)); + + if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) + return (-1); /* dt_errno is set for us */ + if (fprintf(out, "\n\n") < 0) + return (dt_set_errno(dtp, errno)); + if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) + return (-1); /* dt_errno is set for us */ + + if (fprintf(out, "\n#else\n\n") < 0) + return (dt_set_errno(dtp, errno)); + + info.dthi_empty = 1; + + if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) + return (-1); /* dt_errno is set for us */ + + if (fprintf(out, "\n#endif\n\n") < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} + +int +dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) +{ + dt_provider_t *pvp; + char *mfname VBDTMSC(NULL), *p; + + if (fname != NULL) { + if ((p = strrchr(fname, '/')) != NULL) + fname = p + 1; + + mfname = alloca(strlen(fname) + 1); + dt_header_fmt_macro(mfname, fname); + if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", + mfname, mfname) < 0) + return (dt_set_errno(dtp, errno)); + } + + if (fprintf(out, "#include <unistd.h>\n\n") < 0) + return (-1); + + if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) + return (-1); + + for (pvp = dt_list_next(&dtp->dt_provlist); + pvp != NULL; pvp = dt_list_next(pvp)) { + if (dt_header_provider(dtp, pvp, out) != 0) + return (-1); /* dt_errno is set for us */ + } + + if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) + return (dt_set_errno(dtp, errno)); + + if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} |